@futpib/parser 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/allSettledStream.js +32 -14
- package/build/allSettledStream.test.js +32 -0
- package/build/androidPackage.d.ts +39 -0
- package/build/androidPackageParser.d.ts +17 -0
- package/build/androidPackageParser.js +183 -0
- package/build/{apkParser.test.js → androidPackageParser.test.js} +6 -6
- package/build/androidPackageUnparser.d.ts +4 -0
- package/build/{apkUnparser.js → androidPackageUnparser.js} +23 -23
- package/build/androidPackageUnparser.test.js +26 -0
- package/build/arbitrarilySlicedAsyncInterable.d.ts +3 -1
- package/build/arbitrarilySlicedAsyncInterable.js +3 -3
- package/build/arrayParser.test.js +3 -3
- package/build/backsmali.d.ts +1 -0
- package/build/backsmali.js +22 -0
- package/build/bsonParser.js +6 -2
- package/build/customInvariant.d.ts +1 -1
- package/build/dalvikBytecodeParser/formatParsers.d.ts +97 -0
- package/build/dalvikBytecodeParser/formatParsers.js +169 -0
- package/build/dalvikBytecodeParser.d.ts +107 -0
- package/build/dalvikBytecodeParser.js +836 -0
- package/build/dalvikExecutable.d.ts +158 -0
- package/build/dalvikExecutable.js +20 -0
- package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
- package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
- package/build/dalvikExecutableParser/typeParsers.d.ts +10 -0
- package/build/dalvikExecutableParser/typeParsers.js +34 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +90 -0
- package/build/dalvikExecutableParser/typedNumbers.js +19 -0
- package/build/dalvikExecutableParser.d.ts +5 -0
- package/build/dalvikExecutableParser.js +1439 -0
- package/build/dalvikExecutableParser.test.js +70 -0
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +298 -0
- package/build/debugLogInputParser.d.ts +4 -0
- package/build/debugLogInputParser.js +16 -0
- package/build/debugLogParser.js +14 -3
- package/build/disjunctionParser.d.ts +2 -1
- package/build/disjunctionParser.js +4 -2
- package/build/elementTerminatedArrayParser.d.ts +3 -0
- package/build/elementTerminatedArrayParser.js +18 -0
- package/build/elementTerminatedArrayParser.test.js +52 -0
- package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
- package/build/elementTerminatedSequenceArrayParser.js +32 -0
- package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
- package/build/elementTerminatedSequenceParser.d.ts +3 -0
- package/build/elementTerminatedSequenceParser.js +27 -0
- package/build/elementTerminatedSequenceParser.test.js +34 -0
- package/build/exactElementParser.js +10 -5
- package/build/exactSequenceParser.d.ts +2 -1
- package/build/exactSequenceParser.js +12 -2
- package/build/fetchCid.d.ts +1 -0
- package/build/fetchCid.js +107 -0
- package/build/fixedLengthSequenceParser.d.ts +1 -0
- package/build/fixedLengthSequenceParser.js +18 -1
- package/build/fixedLengthSequenceParser.test.js +41 -0
- package/build/hasExecutable.d.ts +1 -0
- package/build/hasExecutable.js +8 -0
- package/build/highResolutionTimer.d.ts +16 -0
- package/build/highResolutionTimer.js +42 -0
- package/build/inputReader.d.ts +11 -0
- package/build/inputReader.js +37 -0
- package/build/inputReader.test.js +165 -0
- package/build/inputReaderState.d.ts +10 -0
- package/build/inputReaderState.js +16 -0
- package/build/inspect.d.ts +1 -0
- package/build/inspect.js +7 -0
- package/build/javaKeyStoreParser.test.js +2 -2
- package/build/jsonParser.d.ts +2 -0
- package/build/jsonParser.js +11 -14
- package/build/leb128Parser.d.ts +7 -0
- package/build/leb128Parser.js +82 -0
- package/build/leb128Parser.test.js +107 -0
- package/build/lookaheadParser.d.ts +2 -0
- package/build/lookaheadParser.js +14 -0
- package/build/negativeLookaheadParser.js +21 -15
- package/build/negativeLookaheadParser.test.js +30 -0
- package/build/nonEmptyArrayParser.d.ts +2 -0
- package/build/nonEmptyArrayParser.js +32 -0
- package/build/nonEmptyArrayParser.test.js +16 -0
- package/build/parser.d.ts +10 -1
- package/build/parser.js +66 -31
- package/build/parser.test.js +79 -12
- package/build/parserAccessorParser.js +9 -1
- package/build/parserConsumedSequenceParser.js +20 -15
- package/build/parserContext.d.ts +14 -0
- package/build/parserContext.js +56 -27
- package/build/parserContext.test.js +27 -0
- package/build/parserCreatorCompose.d.ts +1 -0
- package/build/parserCreatorCompose.js +8 -2
- package/build/parserError.d.ts +6 -0
- package/build/parserError.js +6 -6
- package/build/parserInputCompanion.d.ts +15 -0
- package/build/parserInputCompanion.js +38 -0
- package/build/promiseCompose.d.ts +1 -1
- package/build/promiseCompose.js +12 -1
- package/build/promiseSettled.d.ts +1 -0
- package/build/promiseSettled.js +4 -0
- package/build/separatedArrayParser.d.ts +2 -0
- package/build/separatedArrayParser.js +39 -0
- package/build/separatedArrayParser.test.d.ts +1 -0
- package/build/separatedArrayParser.test.js +21 -0
- package/build/sequenceBuffer.d.ts +10 -0
- package/build/sequenceBuffer.js +54 -2
- package/build/sequenceBuffer.test.js +57 -0
- package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
- package/build/sequenceTerminatedSequenceParser.js +32 -0
- package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
- package/build/sequenceTerminatedSequenceParser.test.js +37 -0
- package/build/skipParser.d.ts +1 -1
- package/build/skipParser.js +4 -2
- package/build/skipToParser.d.ts +2 -0
- package/build/skipToParser.js +11 -0
- package/build/sliceBoundedParser.d.ts +1 -1
- package/build/sliceBoundedParser.js +7 -2
- package/build/sliceBoundedParser.test.js +35 -1
- package/build/smali.d.ts +1 -0
- package/build/smali.js +17 -0
- package/build/smaliParser.d.ts +12 -0
- package/build/smaliParser.js +656 -0
- package/build/smaliParser.test.d.ts +1 -0
- package/build/smaliParser.test.js +115 -0
- package/build/terminatedArrayParser.d.ts +3 -1
- package/build/terminatedArrayParser.js +79 -2
- package/build/terminatedArrayParser.test.d.ts +1 -0
- package/build/terminatedArrayParser.test.js +131 -0
- package/build/toAsyncIterable.d.ts +1 -0
- package/build/toAsyncIterable.js +7 -0
- package/build/toAsyncIterator.d.ts +1 -0
- package/build/toAsyncIterator.js +33 -0
- package/build/tupleParser.d.ts +4 -0
- package/build/tupleParser.js +1 -5
- package/build/unionParser.d.ts +2 -1
- package/build/unionParser.js +27 -12
- package/build/unionParser.test.d.ts +1 -0
- package/build/unionParser.test.js +60 -0
- package/build/zipParser.d.ts +7 -2
- package/build/zipParser.js +36 -12
- package/build/zipUnparser.d.ts +4 -1
- package/build/zipUnparser.js +55 -26
- package/build/zipUnparser.test.js +14 -14
- package/package.json +23 -7
- package/src/allSettledStream.test.ts +40 -0
- package/src/allSettledStream.ts +47 -15
- package/src/androidPackage.ts +48 -0
- package/src/{apkParser.test.ts → androidPackageParser.test.ts} +6 -7
- package/src/{apkParser.test.ts.md → androidPackageParser.test.ts.md} +4 -4
- package/src/androidPackageParser.test.ts.snap +0 -0
- package/src/androidPackageParser.ts +440 -0
- package/src/androidPackageUnparser.test.ts +36 -0
- package/src/androidPackageUnparser.ts +120 -0
- package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
- package/src/arrayParser.test.ts +3 -3
- package/src/backsmali.ts +30 -0
- package/src/bsonParser.ts +13 -2
- package/src/customInvariant.ts +1 -1
- package/src/dalvikBytecodeParser/formatParsers.ts +421 -0
- package/src/dalvikBytecodeParser.ts +2074 -0
- package/src/dalvikExecutable.ts +220 -0
- package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
- package/src/dalvikExecutableParser/typeParsers.ts +65 -0
- package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
- package/src/dalvikExecutableParser.test.ts +89 -0
- package/src/dalvikExecutableParser.test.ts.md +634 -0
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +2768 -0
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +346 -0
- package/src/debugLogInputParser.ts +28 -0
- package/src/debugLogParser.ts +19 -3
- package/src/disjunctionParser.ts +10 -5
- package/src/elementTerminatedArrayParser.test.ts +99 -0
- package/src/elementTerminatedArrayParser.ts +31 -0
- package/src/elementTerminatedSequenceArrayParser.test.ts +54 -0
- package/src/elementTerminatedSequenceArrayParser.ts +52 -0
- package/src/elementTerminatedSequenceParser.test.ts +54 -0
- package/src/elementTerminatedSequenceParser.ts +43 -0
- package/src/exactElementParser.ts +17 -11
- package/src/exactSequenceParser.ts +23 -2
- package/src/fetchCid.ts +125 -0
- package/src/fixedLengthSequenceParser.test.ts +77 -0
- package/src/fixedLengthSequenceParser.ts +28 -1
- package/src/hasExecutable.ts +11 -0
- package/src/highResolutionTimer.ts +49 -0
- package/src/inputReader.test.ts +209 -0
- package/src/inputReader.ts +75 -0
- package/src/inputReaderState.ts +33 -0
- package/src/inspect.ts +9 -0
- package/src/javaKeyStoreParser.test.ts +2 -3
- package/src/jsonParser.ts +13 -25
- package/src/leb128Parser.test.ts +171 -0
- package/src/leb128Parser.ts +125 -0
- package/src/lookaheadParser.ts +19 -0
- package/src/negativeLookaheadParser.test.ts +53 -0
- package/src/negativeLookaheadParser.ts +26 -14
- package/src/nonEmptyArrayParser.test.ts +20 -0
- package/src/nonEmptyArrayParser.ts +44 -0
- package/src/optionalParser.ts +1 -0
- package/src/parser.test.ts +131 -12
- package/src/parser.test.ts.md +21 -21
- package/src/parser.test.ts.snap +0 -0
- package/src/parser.ts +149 -45
- package/src/parserAccessorParser.ts +12 -2
- package/src/parserConsumedSequenceParser.ts +25 -16
- package/src/parserContext.test.ts +31 -0
- package/src/parserContext.ts +109 -37
- package/src/parserCreatorCompose.ts +20 -2
- package/src/parserError.ts +9 -6
- package/src/parserInputCompanion.ts +55 -0
- package/src/promiseCompose.ts +17 -3
- package/src/promiseSettled.ts +6 -0
- package/src/separatedArrayParser.test.ts +34 -0
- package/src/separatedArrayParser.ts +55 -0
- package/src/sequenceBuffer.test.ts +70 -0
- package/src/sequenceBuffer.ts +88 -2
- package/src/sequenceTerminatedSequenceParser.test.ts +60 -0
- package/src/sequenceTerminatedSequenceParser.ts +62 -0
- package/src/skipParser.ts +7 -5
- package/src/skipToParser.ts +16 -0
- package/src/sliceBoundedParser.test.ts +43 -1
- package/src/sliceBoundedParser.ts +19 -1
- package/src/smali.ts +24 -0
- package/src/smaliParser.test.ts +132 -0
- package/src/smaliParser.test.ts.md +2320 -0
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +1166 -0
- package/src/terminatedArrayParser.test.ts +258 -0
- package/src/terminatedArrayParser.ts +108 -3
- package/src/toAsyncIterable.ts +7 -0
- package/src/toAsyncIterator.ts +48 -0
- package/src/tupleParser.ts +8 -5
- package/src/unionParser.test.ts +79 -0
- package/src/unionParser.ts +44 -16
- package/src/zipParser.ts +77 -18
- package/src/zipUnparser.test.ts +18 -18
- package/src/zipUnparser.ts +88 -27
- package/build/apk.d.ts +0 -39
- package/build/apkParser.d.ts +0 -16
- package/build/apkParser.js +0 -164
- package/build/apkUnparser.d.ts +0 -4
- package/build/apkUnparser.test.js +0 -26
- package/build/arbitraryDosDate.d.ts +0 -2
- package/build/arbitraryDosDate.js +0 -8
- package/build/arbitraryZipEntry.d.ts +0 -3
- package/build/arbitraryZipEntry.js +0 -26
- package/build/createDisjunctionParser.d.ts +0 -2
- package/build/createDisjunctionParser.js +0 -47
- package/build/createExactParser.d.ts +0 -2
- package/build/createExactParser.js +0 -12
- package/build/createSequentialUnionParser.d.ts +0 -2
- package/build/createSequentialUnionParser.js +0 -69
- package/build/fixedLengthChunkParser.d.ts +0 -2
- package/build/fixedLengthChunkParser.js +0 -12
- package/build/fixedLengthParser.d.ts +0 -2
- package/build/fixedLengthParser.js +0 -12
- package/build/inputChunkBuffer.d.ts +0 -15
- package/build/inputChunkBuffer.js +0 -40
- package/build/inputChunkBuffer.test.js +0 -34
- package/build/inputCompanion.d.ts +0 -18
- package/build/inputCompanion.js +0 -28
- package/build/invariantDefined.d.ts +0 -1
- package/build/invariantDefined.js +0 -5
- package/build/invariantIdentity.d.ts +0 -3
- package/build/invariantIdentity.js +0 -5
- package/build/javaKeystoreParser.d.ts +0 -2
- package/build/javaKeystoreParser.js +0 -7
- package/build/jsonParser2.d.ts +0 -3
- package/build/jsonParser2.js +0 -52
- package/build/jsonParser2.test.js +0 -22
- package/build/negativeLookahead.d.ts +0 -2
- package/build/negativeLookahead.js +0 -18
- package/build/parserCompose.d.ts +0 -3
- package/build/parserCompose.js +0 -7
- package/build/parserImplementationInvariantInvariant.d.ts +0 -3
- package/build/parserImplementationInvariantInvariant.js +0 -15
- package/build/parserInvariant.d.ts +0 -4
- package/build/parserInvariant.js +0 -11
- package/build/promiseFish.d.ts +0 -1
- package/build/promiseFish.js +0 -3
- package/build/sequenceParser.d.ts +0 -3
- package/build/sequenceParser.js +0 -10
- package/build/terminatedSequenceParser.d.ts +0 -2
- package/build/terminatedSequenceParser.js +0 -24
- package/build/unparserInputCompanion.d.ts +0 -15
- package/build/unparserInputCompanion.js +0 -13
- package/build/zipEntry.d.ts +0 -28
- package/build/zipFile.d.ts +0 -32
- package/build/zipFileEntry.d.ts +0 -6
- package/src/apk.ts +0 -48
- package/src/apkParser.test.ts.snap +0 -0
- package/src/apkParser.ts +0 -392
- package/src/apkUnparser.test.ts +0 -37
- package/src/apkUnparser.ts +0 -120
- package/src/invariantDefined.ts +0 -6
- package/src/invariantIdentity.ts +0 -8
- /package/build/{apk.js → androidPackage.js} +0 -0
- /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
- /package/build/{apkUnparser.test.d.ts → androidPackageUnparser.test.d.ts} +0 -0
- /package/build/{arbitraryDosPermissions.d.ts → dalvikExecutableParser.test.d.ts} +0 -0
- /package/build/{arbitraryDosPermissions.js → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
- /package/build/{inputChunkBuffer.test.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
- /package/build/{jsonParser2.test.d.ts → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
- /package/build/{parserParsingInvariant.d.ts → elementTerminatedSequenceParser.test.d.ts} +0 -0
- /package/build/{parserParsingInvariant.js → fixedLengthSequenceParser.test.d.ts} +0 -0
- /package/build/{zipEntry.js → leb128Parser.test.d.ts} +0 -0
- /package/build/{zipFile.js → negativeLookaheadParser.test.d.ts} +0 -0
- /package/build/{zipFileEntry.js → nonEmptyArrayParser.test.d.ts} +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getParserName, setParserName } from './parser.js';
|
|
2
|
+
import { ParserParsingFailedError } from './parserError.js';
|
|
3
|
+
import { promiseCompose } from './promiseCompose.js';
|
|
4
|
+
import { createTupleParser } from './tupleParser.js';
|
|
5
|
+
export const createSeparatedArrayParser = (elementParser, separatorParser) => {
|
|
6
|
+
const separatorThenElementParser = promiseCompose(createTupleParser([
|
|
7
|
+
separatorParser,
|
|
8
|
+
elementParser,
|
|
9
|
+
]), ([, element]) => element);
|
|
10
|
+
const separatedArrayParser = async (parserContext) => {
|
|
11
|
+
let parser = elementParser;
|
|
12
|
+
const elements = [];
|
|
13
|
+
while (true) {
|
|
14
|
+
const elementParserContext = parserContext.lookahead();
|
|
15
|
+
const initialPosition = elementParserContext.position;
|
|
16
|
+
try {
|
|
17
|
+
const element = await parser(elementParserContext);
|
|
18
|
+
if (elementParserContext.position === initialPosition) {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
elements.push(element);
|
|
22
|
+
elementParserContext.unlookahead();
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error instanceof ParserParsingFailedError) {
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
elementParserContext.dispose();
|
|
32
|
+
}
|
|
33
|
+
parser = separatorThenElementParser;
|
|
34
|
+
}
|
|
35
|
+
return elements;
|
|
36
|
+
};
|
|
37
|
+
setParserName(separatedArrayParser, getParserName(elementParser, 'anonymousSeparatedArrayChild') + '*');
|
|
38
|
+
return separatedArrayParser;
|
|
39
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { testProp, fc } from '@fast-check/ava';
|
|
3
|
+
import { createSeparatedArrayParser } from './separatedArrayParser.js';
|
|
4
|
+
import { runParser, runParserWithRemainingInput } from './parser.js';
|
|
5
|
+
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
6
|
+
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
7
|
+
test('does not loop forever with a child parser that does not consume anything', async (t) => {
|
|
8
|
+
const parser = createSeparatedArrayParser(async () => undefined, () => undefined);
|
|
9
|
+
const { output } = await runParserWithRemainingInput(parser, 'foo', stringParserInputCompanion);
|
|
10
|
+
t.deepEqual(output, []);
|
|
11
|
+
});
|
|
12
|
+
testProp('separatedArray', [
|
|
13
|
+
fc.array(fc.constant('element')),
|
|
14
|
+
], async (t, elements) => {
|
|
15
|
+
const separatedArrayParser = createSeparatedArrayParser(createExactSequenceParser('element'), createExactSequenceParser('separator'));
|
|
16
|
+
const actual = await runParser(separatedArrayParser, elements.join('separator'), stringParserInputCompanion);
|
|
17
|
+
const expected = elements;
|
|
18
|
+
t.deepEqual(actual, expected);
|
|
19
|
+
}, {
|
|
20
|
+
verbose: true,
|
|
21
|
+
});
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { type ParserInputCompanion } from './parserInputCompanion.js';
|
|
2
|
+
export type SequenceBufferState<Sequence> = {
|
|
3
|
+
consumedBufferedSequences: Sequence[];
|
|
4
|
+
unconsumedBufferedSequences: Sequence[];
|
|
5
|
+
};
|
|
2
6
|
export type SequenceBuffer<Sequence, Element> = {
|
|
3
7
|
push(sequence: Sequence): void;
|
|
4
8
|
peek(offset: number): Element | undefined;
|
|
9
|
+
peekSequence(start: number, end: number): Sequence | undefined;
|
|
5
10
|
skip(offset: number): void;
|
|
11
|
+
toSequenceBufferState(): SequenceBufferState<Sequence>;
|
|
6
12
|
};
|
|
7
13
|
export declare class SequenceBufferImplementation<Sequence, Element> implements SequenceBuffer<Sequence, Element> {
|
|
8
14
|
private readonly _parserInputCompanion;
|
|
9
15
|
private readonly _sequences;
|
|
10
16
|
private _indexInFirstSequence;
|
|
11
17
|
constructor(_parserInputCompanion: ParserInputCompanion<Sequence, Element>);
|
|
18
|
+
get length(): number;
|
|
19
|
+
private _shift;
|
|
12
20
|
push(sequence: Sequence): void;
|
|
13
21
|
peek(offset: number): Element | undefined;
|
|
22
|
+
peekSequence(start: number, end: number): Sequence | undefined;
|
|
14
23
|
skip(offset: number): void;
|
|
24
|
+
toSequenceBufferState(): SequenceBufferState<Sequence>;
|
|
15
25
|
}
|
package/build/sequenceBuffer.js
CHANGED
|
@@ -6,8 +6,10 @@ export class SequenceBufferImplementation {
|
|
|
6
6
|
constructor(_parserInputCompanion) {
|
|
7
7
|
this._parserInputCompanion = _parserInputCompanion;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
this._sequences.
|
|
9
|
+
get length() {
|
|
10
|
+
return this._sequences.reduce((sequenceLength, sequence) => sequenceLength + this._parserInputCompanion.length(sequence), 0 - this._indexInFirstSequence);
|
|
11
|
+
}
|
|
12
|
+
_shift() {
|
|
11
13
|
while (this._sequences.length > 0) {
|
|
12
14
|
const firstSequence = this._sequences[0];
|
|
13
15
|
const firstSequenceLength = this._parserInputCompanion.length(firstSequence);
|
|
@@ -22,6 +24,10 @@ export class SequenceBufferImplementation {
|
|
|
22
24
|
this._indexInFirstSequence -= firstSequenceLength;
|
|
23
25
|
}
|
|
24
26
|
}
|
|
27
|
+
push(sequence) {
|
|
28
|
+
this._sequences.push(sequence);
|
|
29
|
+
this._shift();
|
|
30
|
+
}
|
|
25
31
|
peek(offset) {
|
|
26
32
|
invariant(offset >= 0, 'Offset must be non-negative.');
|
|
27
33
|
let index = this._indexInFirstSequence + offset;
|
|
@@ -34,7 +40,53 @@ export class SequenceBufferImplementation {
|
|
|
34
40
|
}
|
|
35
41
|
return undefined;
|
|
36
42
|
}
|
|
43
|
+
peekSequence(start, end) {
|
|
44
|
+
invariant(start >= 0, 'Start must be non-negative.');
|
|
45
|
+
invariant(end >= start, 'End must be greater than or equal to start.');
|
|
46
|
+
let startIndex = this._indexInFirstSequence + start;
|
|
47
|
+
let endIndex = this._indexInFirstSequence + end;
|
|
48
|
+
const sequences = [];
|
|
49
|
+
for (const sequence of this._sequences) {
|
|
50
|
+
const sequenceLength = this._parserInputCompanion.length(sequence);
|
|
51
|
+
if (startIndex < sequenceLength) {
|
|
52
|
+
const subsequence = this._parserInputCompanion.subsequence(sequence, Math.max(0, startIndex), Math.min(sequenceLength, endIndex));
|
|
53
|
+
sequences.push(subsequence);
|
|
54
|
+
}
|
|
55
|
+
startIndex -= sequenceLength;
|
|
56
|
+
endIndex -= sequenceLength;
|
|
57
|
+
if (endIndex <= 0) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return endIndex > 0 ? undefined : this._parserInputCompanion.concat(sequences);
|
|
62
|
+
}
|
|
37
63
|
skip(offset) {
|
|
38
64
|
this._indexInFirstSequence += offset;
|
|
65
|
+
this._shift();
|
|
66
|
+
}
|
|
67
|
+
toSequenceBufferState() {
|
|
68
|
+
if (this._sequences.length === 0) {
|
|
69
|
+
return {
|
|
70
|
+
consumedBufferedSequences: [],
|
|
71
|
+
unconsumedBufferedSequences: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if (this._indexInFirstSequence === 0) {
|
|
75
|
+
return {
|
|
76
|
+
consumedBufferedSequences: [],
|
|
77
|
+
unconsumedBufferedSequences: this._sequences.slice(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const firstSequence = this._sequences[0];
|
|
81
|
+
const firstSequenceLength = this._parserInputCompanion.length(firstSequence);
|
|
82
|
+
const consumedFirstSequence = this._parserInputCompanion.subsequence(firstSequence, 0, this._indexInFirstSequence);
|
|
83
|
+
const unconsumedFirstSequence = this._parserInputCompanion.subsequence(firstSequence, this._indexInFirstSequence, firstSequenceLength);
|
|
84
|
+
const unconsumedFirstSequenceLength = this._parserInputCompanion.length(unconsumedFirstSequence);
|
|
85
|
+
return {
|
|
86
|
+
consumedBufferedSequences: [consumedFirstSequence],
|
|
87
|
+
unconsumedBufferedSequences: (unconsumedFirstSequenceLength === 0
|
|
88
|
+
? this._sequences.slice(1)
|
|
89
|
+
: [unconsumedFirstSequence, ...this._sequences.slice(1)]),
|
|
90
|
+
};
|
|
39
91
|
}
|
|
40
92
|
}
|
|
@@ -3,32 +3,89 @@ import { SequenceBufferImplementation } from './sequenceBuffer.js';
|
|
|
3
3
|
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
4
4
|
test('sequenceBuffer', t => {
|
|
5
5
|
const sequenceBuffer = new SequenceBufferImplementation(stringParserInputCompanion);
|
|
6
|
+
t.is(sequenceBuffer.length, 0);
|
|
6
7
|
t.is(sequenceBuffer.peek(0), undefined);
|
|
8
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
9
|
+
consumedBufferedSequences: [],
|
|
10
|
+
unconsumedBufferedSequences: [],
|
|
11
|
+
});
|
|
7
12
|
sequenceBuffer.push('');
|
|
13
|
+
t.is(sequenceBuffer.length, 0);
|
|
8
14
|
t.is(sequenceBuffer.peek(0), undefined);
|
|
15
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
16
|
+
consumedBufferedSequences: [],
|
|
17
|
+
unconsumedBufferedSequences: [],
|
|
18
|
+
});
|
|
9
19
|
sequenceBuffer.push('abc');
|
|
20
|
+
t.is(sequenceBuffer.length, 3);
|
|
10
21
|
t.is(sequenceBuffer.peek(0), 'a');
|
|
11
22
|
t.is(sequenceBuffer.peek(1), 'b');
|
|
12
23
|
t.is(sequenceBuffer.peek(2), 'c');
|
|
13
24
|
t.is(sequenceBuffer.peek(3), undefined);
|
|
25
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
26
|
+
consumedBufferedSequences: [],
|
|
27
|
+
unconsumedBufferedSequences: ['abc'],
|
|
28
|
+
});
|
|
14
29
|
sequenceBuffer.push('def');
|
|
30
|
+
t.is(sequenceBuffer.length, 6);
|
|
15
31
|
t.is(sequenceBuffer.peek(0), 'a');
|
|
16
32
|
t.is(sequenceBuffer.peek(3), 'd');
|
|
17
33
|
t.is(sequenceBuffer.peek(6), undefined);
|
|
34
|
+
t.is(sequenceBuffer.peekSequence(1, 4), 'abcdef'.slice(1, 4), 'bcd');
|
|
35
|
+
t.is(sequenceBuffer.peekSequence(1, 5), 'abcdef'.slice(1, 5), 'bcde');
|
|
36
|
+
t.is(sequenceBuffer.peekSequence(1, 6), 'abcdef'.slice(1, 6), 'bcdef');
|
|
37
|
+
t.is(sequenceBuffer.peekSequence(1, 7), undefined, 'bcdef?');
|
|
38
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
39
|
+
consumedBufferedSequences: [],
|
|
40
|
+
unconsumedBufferedSequences: ['abc', 'def'],
|
|
41
|
+
});
|
|
18
42
|
sequenceBuffer.push('');
|
|
43
|
+
t.is(sequenceBuffer.length, 6);
|
|
19
44
|
t.is(sequenceBuffer.peek(0), 'a');
|
|
20
45
|
t.is(sequenceBuffer.peek(3), 'd');
|
|
21
46
|
t.is(sequenceBuffer.peek(6), undefined);
|
|
47
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
48
|
+
consumedBufferedSequences: [],
|
|
49
|
+
unconsumedBufferedSequences: ['abc', 'def', ''],
|
|
50
|
+
});
|
|
22
51
|
sequenceBuffer.skip(1);
|
|
52
|
+
t.is(sequenceBuffer.length, 5);
|
|
23
53
|
t.is(sequenceBuffer.peek(0), 'b');
|
|
24
54
|
t.is(sequenceBuffer.peek(3), 'e');
|
|
25
55
|
t.is(sequenceBuffer.peek(5), undefined);
|
|
56
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
57
|
+
consumedBufferedSequences: ['a'],
|
|
58
|
+
unconsumedBufferedSequences: ['bc', 'def', ''],
|
|
59
|
+
});
|
|
26
60
|
sequenceBuffer.skip(3);
|
|
61
|
+
t.is(sequenceBuffer.length, 2);
|
|
27
62
|
t.is(sequenceBuffer.peek(0), 'e');
|
|
28
63
|
t.is(sequenceBuffer.peek(2), undefined);
|
|
64
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
65
|
+
consumedBufferedSequences: ['d'],
|
|
66
|
+
unconsumedBufferedSequences: ['ef', ''],
|
|
67
|
+
});
|
|
29
68
|
sequenceBuffer.push('gh');
|
|
69
|
+
t.is(sequenceBuffer.length, 4);
|
|
30
70
|
t.is(sequenceBuffer.peek(0), 'e');
|
|
31
71
|
t.is(sequenceBuffer.peek(2), 'g');
|
|
32
72
|
t.is(sequenceBuffer.peek(3), 'h');
|
|
33
73
|
t.is(sequenceBuffer.peek(4), undefined);
|
|
74
|
+
t.is(sequenceBuffer.peekSequence(1, 3), 'efgh'.slice(1, 3), 'fg');
|
|
75
|
+
t.is(sequenceBuffer.peekSequence(1, 4), 'efgh'.slice(1, 4), 'fgh');
|
|
76
|
+
t.is(sequenceBuffer.peekSequence(1, 5), undefined, 'fgh?');
|
|
77
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
78
|
+
consumedBufferedSequences: ['d'],
|
|
79
|
+
unconsumedBufferedSequences: ['ef', '', 'gh'],
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
test('skip more then first sequence length', t => {
|
|
83
|
+
const sequenceBuffer = new SequenceBufferImplementation(stringParserInputCompanion);
|
|
84
|
+
sequenceBuffer.push('a');
|
|
85
|
+
sequenceBuffer.push('b');
|
|
86
|
+
sequenceBuffer.skip(2);
|
|
87
|
+
t.deepEqual(sequenceBuffer.toSequenceBufferState(), {
|
|
88
|
+
consumedBufferedSequences: [],
|
|
89
|
+
unconsumedBufferedSequences: [],
|
|
90
|
+
});
|
|
34
91
|
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Parser } from "./parser.js";
|
|
2
|
+
import { DeriveSequenceElement } from "./sequence.js";
|
|
3
|
+
export declare const createSequenceTerminatedSequenceParser: <Sequence, Element = DeriveSequenceElement<Sequence>>(terminatorSequence: Sequence, { consumeTerminator, }?: {
|
|
4
|
+
consumeTerminator?: boolean;
|
|
5
|
+
}) => Parser<Sequence, Sequence, Element>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { inspect } from "./inspect.js";
|
|
2
|
+
import { setParserName } from "./parser.js";
|
|
3
|
+
function clamp(x, min, max) {
|
|
4
|
+
return Math.max(min, Math.min(x, max));
|
|
5
|
+
}
|
|
6
|
+
export const createSequenceTerminatedSequenceParser = (terminatorSequence, { consumeTerminator = true, } = {}) => {
|
|
7
|
+
const elementTerminatedSequenceParser = async (parserContext) => {
|
|
8
|
+
let window = 1;
|
|
9
|
+
let nonEndOfInputWindow = 0;
|
|
10
|
+
while (true) {
|
|
11
|
+
const sequence = await parserContext.peekSequence(0, window);
|
|
12
|
+
if (sequence === undefined) {
|
|
13
|
+
window = clamp(Math.floor(window * 0.75), nonEndOfInputWindow + 1, window - 1);
|
|
14
|
+
parserContext.invariant(window !== nonEndOfInputWindow, 'Unexpected end of input without terminated sequence');
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
nonEndOfInputWindow = Math.max(window, nonEndOfInputWindow);
|
|
18
|
+
const terminatorIndex = parserContext.indexOfSubsequence(sequence, terminatorSequence);
|
|
19
|
+
if (terminatorIndex === -1) {
|
|
20
|
+
window = window * 2;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const sequence_ = await parserContext.readSequence(0, terminatorIndex);
|
|
24
|
+
if (consumeTerminator) {
|
|
25
|
+
parserContext.skip(parserContext.length(terminatorSequence));
|
|
26
|
+
}
|
|
27
|
+
return sequence_;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
setParserName(elementTerminatedSequenceParser, `.*?${inspect(terminatorSequence)}`);
|
|
31
|
+
return elementTerminatedSequenceParser;
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as fc from 'fast-check';
|
|
2
|
+
import { testProp } from '@fast-check/ava';
|
|
3
|
+
import { runParser } from './parser.js';
|
|
4
|
+
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
5
|
+
import { createSequenceTerminatedSequenceParser } from './sequenceTerminatedSequenceParser.js';
|
|
6
|
+
testProp.serial('sequenceTerminatedSequenceParser', [
|
|
7
|
+
fc.tuple(fc
|
|
8
|
+
.string({
|
|
9
|
+
minLength: 1,
|
|
10
|
+
}), fc
|
|
11
|
+
.integer({
|
|
12
|
+
min: 1,
|
|
13
|
+
}))
|
|
14
|
+
.map(([string, terminatorLength]) => ({
|
|
15
|
+
string,
|
|
16
|
+
terminator: string.slice(-terminatorLength),
|
|
17
|
+
}))
|
|
18
|
+
.filter(({ string, terminator }) => string.split(terminator).length === 2)
|
|
19
|
+
], async (t, { string, terminator }) => {
|
|
20
|
+
const sequenceTerminatedSequenceParser = createSequenceTerminatedSequenceParser(terminator);
|
|
21
|
+
const createTestWrapperParser = (innerParser) => async (parserContext) => {
|
|
22
|
+
const string = await innerParser(parserContext);
|
|
23
|
+
return {
|
|
24
|
+
string,
|
|
25
|
+
nextPeek: await parserContext.peek(0),
|
|
26
|
+
position: parserContext.position,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
const actual = await runParser(createTestWrapperParser(sequenceTerminatedSequenceParser), string, stringParserInputCompanion);
|
|
30
|
+
t.deepEqual(actual, {
|
|
31
|
+
string: string.split(terminator)[0],
|
|
32
|
+
nextPeek: undefined,
|
|
33
|
+
position: string.length,
|
|
34
|
+
});
|
|
35
|
+
}, {
|
|
36
|
+
verbose: true,
|
|
37
|
+
});
|
package/build/skipParser.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type Parser } from './parser.js';
|
|
2
|
-
export declare const createSkipParser: <Sequence>(length: number) => Parser<
|
|
2
|
+
export declare const createSkipParser: <Sequence>(length: number) => Parser<void, Sequence, unknown>;
|
package/build/skipParser.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { setParserName } from './parser.js';
|
|
1
2
|
import { parserImplementationInvariant } from './parserImplementationInvariant.js';
|
|
2
3
|
export const createSkipParser = (length) => {
|
|
3
4
|
parserImplementationInvariant(length > 0, 'Length must be positive.');
|
|
4
|
-
|
|
5
|
+
const skipParser = parserContext => {
|
|
5
6
|
parserContext.skip(length);
|
|
6
|
-
return undefined;
|
|
7
7
|
};
|
|
8
|
+
setParserName(skipParser, `createSkipParser(${length})`);
|
|
9
|
+
return skipParser;
|
|
8
10
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { setParserName } from "./parser.js";
|
|
2
|
+
import { parserImplementationInvariant } from './parserImplementationInvariant.js';
|
|
3
|
+
export const createSkipToParser = (offset) => {
|
|
4
|
+
const skipToParser = (parserContext) => {
|
|
5
|
+
const length = offset - parserContext.position;
|
|
6
|
+
parserImplementationInvariant(length >= 0, 'Skip length must be positive, got %s (position: %s)', length, parserContext.position);
|
|
7
|
+
parserContext.skip(length);
|
|
8
|
+
};
|
|
9
|
+
setParserName(skipToParser, `createSkipToParser(${offset})`);
|
|
10
|
+
return skipToParser;
|
|
11
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { type Parser } from './parser.js';
|
|
2
|
-
export declare const createSliceBoundedParser: <Output, Sequence>(childParser: Parser<Output, Sequence>, sliceEnd: number) => Parser<Output, Sequence>;
|
|
2
|
+
export declare const createSliceBoundedParser: <Output, Sequence>(childParser: Parser<Output, Sequence>, sliceEnd: number, mustConsumeAll?: boolean) => Parser<Output, Sequence>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { getParserName, setParserName } from './parser.js';
|
|
2
|
-
export const createSliceBoundedParser = (childParser, sliceEnd) => {
|
|
2
|
+
export const createSliceBoundedParser = (childParser, sliceEnd, mustConsumeAll = true) => {
|
|
3
3
|
const sliceBoundedParser = async (parserContext) => {
|
|
4
|
+
const absoluteSliceEnd = parserContext.position + sliceEnd;
|
|
4
5
|
const childParserContext = parserContext.lookahead({
|
|
5
|
-
sliceEnd:
|
|
6
|
+
sliceEnd: absoluteSliceEnd,
|
|
6
7
|
});
|
|
7
8
|
try {
|
|
8
9
|
const value = await childParser(childParserContext);
|
|
10
|
+
childParserContext.invariant((!mustConsumeAll
|
|
11
|
+
|| childParserContext.position === absoluteSliceEnd), 'child parser must consume all input in the slice (%s in total, up to position %s), instead consumed %s up to position %s', sliceEnd, absoluteSliceEnd, childParserContext.position - parserContext.position, childParserContext.position);
|
|
9
12
|
childParserContext.unlookahead();
|
|
10
13
|
return value;
|
|
11
14
|
}
|
|
@@ -18,6 +21,8 @@ export const createSliceBoundedParser = (childParser, sliceEnd) => {
|
|
|
18
21
|
getParserName(childParser, 'anonymousSliceBoundedChild'),
|
|
19
22
|
',',
|
|
20
23
|
sliceEnd,
|
|
24
|
+
',',
|
|
25
|
+
mustConsumeAll,
|
|
21
26
|
')',
|
|
22
27
|
].join(''));
|
|
23
28
|
return sliceBoundedParser;
|
|
@@ -3,8 +3,16 @@ import { createArrayParser } from './arrayParser.js';
|
|
|
3
3
|
import { createElementParser } from './elementParser.js';
|
|
4
4
|
import { createTupleParser } from './tupleParser.js';
|
|
5
5
|
import { createSliceBoundedParser } from './sliceBoundedParser.js';
|
|
6
|
-
import { runParser } from './parser.js';
|
|
6
|
+
import { runParser, runParserWithRemainingInput } from './parser.js';
|
|
7
7
|
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
8
|
+
import { createExactElementParser } from './exactElementParser.js';
|
|
9
|
+
async function stringFromAsyncIterable(asyncIterable) {
|
|
10
|
+
let string = '';
|
|
11
|
+
for await (const chunk of asyncIterable) {
|
|
12
|
+
string += chunk;
|
|
13
|
+
}
|
|
14
|
+
return string;
|
|
15
|
+
}
|
|
8
16
|
const anythingParser = createArrayParser(createElementParser());
|
|
9
17
|
test('sliceBoundedParser', async (t) => {
|
|
10
18
|
const parser = createTupleParser([
|
|
@@ -22,3 +30,29 @@ test('sliceBoundedParser', async (t) => {
|
|
|
22
30
|
'a',
|
|
23
31
|
]);
|
|
24
32
|
});
|
|
33
|
+
test('sliceBoundedParser mustConsumeAll: true fail to cosume all', async (t) => {
|
|
34
|
+
const parser = createTupleParser([
|
|
35
|
+
createElementParser(),
|
|
36
|
+
createSliceBoundedParser(createArrayParser(createExactElementParser('b')), 2),
|
|
37
|
+
createElementParser(),
|
|
38
|
+
]);
|
|
39
|
+
await t.throwsAsync(() => runParser(parser, 'abcd', stringParserInputCompanion), {
|
|
40
|
+
message: /child parser must consume all input in the slice/,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
test('sliceBoundedParser mustConsumeAll: false', async (t) => {
|
|
44
|
+
const parser = createTupleParser([
|
|
45
|
+
createElementParser(),
|
|
46
|
+
createSliceBoundedParser(createArrayParser(createExactElementParser('b')), 2, false),
|
|
47
|
+
createElementParser(),
|
|
48
|
+
]);
|
|
49
|
+
const { output, remainingInput } = await runParserWithRemainingInput(parser, 'abcd', stringParserInputCompanion);
|
|
50
|
+
t.deepEqual(output, [
|
|
51
|
+
'a',
|
|
52
|
+
[
|
|
53
|
+
'b',
|
|
54
|
+
],
|
|
55
|
+
'c',
|
|
56
|
+
]);
|
|
57
|
+
t.deepEqual(await stringFromAsyncIterable(remainingInput), 'd');
|
|
58
|
+
});
|
package/build/smali.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function smaliClass(smaliStream: AsyncIterable<string>): Promise<Buffer<ArrayBufferLike>>;
|
package/build/smali.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { temporaryFile } from 'tempy';
|
|
4
|
+
export async function smaliClass(smaliStream) {
|
|
5
|
+
const inputFilePath = temporaryFile();
|
|
6
|
+
const outputFilePath = temporaryFile();
|
|
7
|
+
await fs.writeFile(inputFilePath, smaliStream);
|
|
8
|
+
await execa('smali', [
|
|
9
|
+
'assemble',
|
|
10
|
+
'--output', outputFilePath,
|
|
11
|
+
inputFilePath,
|
|
12
|
+
]);
|
|
13
|
+
await fs.unlink(inputFilePath);
|
|
14
|
+
const dex = await fs.readFile(outputFilePath);
|
|
15
|
+
await fs.unlink(outputFilePath);
|
|
16
|
+
return dex;
|
|
17
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DalvikBytecode } from "./dalvikBytecodeParser.js";
|
|
2
|
+
import { DalvikExecutableClassDefinition, DalvikExecutableFieldWithAccess } from "./dalvikExecutable.js";
|
|
3
|
+
import { Parser } from "./parser.js";
|
|
4
|
+
export declare const smaliFieldParser: Parser<DalvikExecutableFieldWithAccess, string>;
|
|
5
|
+
export declare const smaliAnnotationParser: Parser<unknown, string>;
|
|
6
|
+
type SmaliRegister = {
|
|
7
|
+
prefix: 'v' | 'p';
|
|
8
|
+
index: number;
|
|
9
|
+
};
|
|
10
|
+
export declare const smaliCodeParameterParser: Parser<SmaliRegister, string>;
|
|
11
|
+
export declare const smaliParser: Parser<DalvikExecutableClassDefinition<DalvikBytecode>, string>;
|
|
12
|
+
export {};
|