@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
package/src/parser.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Class } from 'type-fest';
|
|
2
2
|
import { type ParserInputCompanion } from './parserInputCompanion.js';
|
|
3
3
|
import { InputReaderImplementation } from './inputReader.js';
|
|
4
4
|
import { type ParserContext, ParserContextImplementation } from './parserContext.js';
|
|
5
5
|
import { type DeriveSequenceElement } from './sequence.js';
|
|
6
|
+
import { ParserError, ParserUnexpectedRemainingInputError } from './parserError.js';
|
|
7
|
+
import { toAsyncIterator } from './toAsyncIterator.js';
|
|
8
|
+
import { inputReaderStateCompanion } from './inputReaderState.js';
|
|
6
9
|
|
|
7
10
|
export type Parser<
|
|
8
11
|
Output,
|
|
9
12
|
Sequence,
|
|
10
13
|
Element = DeriveSequenceElement<Sequence>,
|
|
11
|
-
> = (parserContext: ParserContext<Sequence, Element>) => Promise<Output>;
|
|
14
|
+
> = (parserContext: ParserContext<Sequence, Element>) => Output | Promise<Output>;
|
|
12
15
|
|
|
13
16
|
export function getParserName(parser: Parser<any, any, any>, default_ = 'anonymous'): string {
|
|
14
17
|
return parser.name || default_;
|
|
@@ -26,59 +29,152 @@ export function setParserName<
|
|
|
26
29
|
return parser;
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
const originalParserByClone = new WeakMap<Parser<any, any, any>, Parser<any, any, any>>();
|
|
33
|
+
|
|
34
|
+
export function cloneParser<
|
|
35
|
+
Output,
|
|
36
|
+
Sequence,
|
|
37
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
38
|
+
>(
|
|
39
|
+
parser: Parser<Output, Sequence, Element>,
|
|
40
|
+
): Parser<Output, Sequence, Element> {
|
|
41
|
+
const originalParser = originalParserByClone.get(parser) ?? parser;
|
|
42
|
+
|
|
43
|
+
const clone: Parser<Output, Sequence, Element> = (parserContext) => {
|
|
44
|
+
return originalParser(parserContext);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
setParserName(clone, getParserName(parser));
|
|
48
|
+
|
|
49
|
+
originalParserByClone.set(clone, originalParser);
|
|
50
|
+
|
|
51
|
+
return clone;
|
|
52
|
+
}
|
|
53
|
+
|
|
29
54
|
export type RunParserOptions<
|
|
30
55
|
Output,
|
|
31
56
|
Sequence,
|
|
32
57
|
Element = DeriveSequenceElement<Sequence>,
|
|
33
58
|
> = {
|
|
34
59
|
errorJoinMode?: 'none' | 'deepest' | 'furthest' | 'all';
|
|
60
|
+
parserContextClass?: Class<ParserContext<Sequence, Element>>;
|
|
35
61
|
};
|
|
36
62
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
63
|
+
export type RunParserWithRemainingInputResult<
|
|
64
|
+
Output,
|
|
65
|
+
Sequence,
|
|
66
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
67
|
+
> = {
|
|
68
|
+
output: Output;
|
|
69
|
+
position: number;
|
|
70
|
+
remainingInput: undefined | AsyncIterable<Sequence>;
|
|
71
|
+
};
|
|
40
72
|
|
|
41
|
-
function
|
|
42
|
-
|
|
73
|
+
async function withEnrichedParserError<
|
|
74
|
+
Output,
|
|
75
|
+
Sequence,
|
|
76
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
77
|
+
>(
|
|
78
|
+
parserContext: ParserContext<Sequence, Element>,
|
|
79
|
+
inputReader: InputReaderImplementation<Sequence, Element>,
|
|
80
|
+
f: () => Promise<Output>,
|
|
81
|
+
): Promise<Output> {
|
|
82
|
+
try {
|
|
83
|
+
return await f();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (error instanceof ParserError) {
|
|
86
|
+
if (error.position === undefined) {
|
|
87
|
+
error.position = parserContext.position;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (error.inputReaderSate === undefined) {
|
|
91
|
+
error.inputReaderSate = inputReader.toInputReaderState();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
43
97
|
}
|
|
44
98
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
99
|
+
type RunParserInternalResult<
|
|
100
|
+
Output,
|
|
101
|
+
Sequence,
|
|
102
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
103
|
+
> = {
|
|
104
|
+
outputPromise: Promise<Output>;
|
|
105
|
+
parserContext: ParserContext<Sequence, Element>;
|
|
106
|
+
inputReader: InputReaderImplementation<Sequence, Element>;
|
|
107
|
+
};
|
|
48
108
|
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
109
|
+
function runParserInternal<
|
|
110
|
+
Output,
|
|
111
|
+
Sequence,
|
|
112
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
113
|
+
>(
|
|
114
|
+
parser: Parser<Output, Sequence, Element>,
|
|
115
|
+
input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence,
|
|
116
|
+
parserInputCompanion: ParserInputCompanion<Sequence, Element>,
|
|
117
|
+
options: RunParserOptions<Output, Sequence, Element> = {},
|
|
118
|
+
): RunParserInternalResult<Output, Sequence, Element> {
|
|
119
|
+
const inputAsyncIterator = toAsyncIterator(input);
|
|
54
120
|
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
typeof value === 'string'
|
|
58
|
-
|| value instanceof Uint8Array
|
|
59
|
-
) {
|
|
60
|
-
return (async function * () {
|
|
61
|
-
yield value as any;
|
|
62
|
-
})();
|
|
63
|
-
}
|
|
121
|
+
const inputReader = new InputReaderImplementation<Sequence, Element>(parserInputCompanion, inputAsyncIterator);
|
|
64
122
|
|
|
65
|
-
|
|
66
|
-
return value[Symbol.asyncIterator]();
|
|
67
|
-
}
|
|
123
|
+
const ParserContext = options.parserContextClass ?? ParserContextImplementation;
|
|
68
124
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
125
|
+
const parserContext = new ParserContext<Sequence, Element>(parserInputCompanion, inputReader, undefined, {
|
|
126
|
+
...options,
|
|
127
|
+
debugName: 'root',
|
|
128
|
+
});
|
|
72
129
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
130
|
+
const outputPromise = (async () => {
|
|
131
|
+
try {
|
|
132
|
+
return await parser(parserContext);
|
|
133
|
+
} finally {
|
|
134
|
+
await parserContext.peek(0);
|
|
135
|
+
}
|
|
136
|
+
})();
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
outputPromise,
|
|
140
|
+
parserContext,
|
|
141
|
+
inputReader,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
76
144
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
export async function runParserWithRemainingInput<
|
|
146
|
+
Output,
|
|
147
|
+
Sequence,
|
|
148
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
149
|
+
>(
|
|
150
|
+
parser: Parser<Output, Sequence, Element>,
|
|
151
|
+
input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence,
|
|
152
|
+
parserInputCompanion: ParserInputCompanion<Sequence, Element>,
|
|
153
|
+
options: RunParserOptions<Output, Sequence, Element> = {},
|
|
154
|
+
): Promise<RunParserWithRemainingInputResult<Output, Sequence, Element>> {
|
|
155
|
+
const {
|
|
156
|
+
outputPromise,
|
|
157
|
+
parserContext,
|
|
158
|
+
inputReader,
|
|
159
|
+
} = runParserInternal(parser, input, parserInputCompanion, options);
|
|
160
|
+
|
|
161
|
+
return await withEnrichedParserError(parserContext, inputReader, async () => {
|
|
162
|
+
const output = await outputPromise;
|
|
163
|
+
|
|
164
|
+
const inputReaderState = inputReader.toInputReaderState();
|
|
165
|
+
|
|
166
|
+
const remainingInput = (
|
|
167
|
+
inputReaderStateCompanion.isDone(inputReaderState)
|
|
168
|
+
? undefined
|
|
169
|
+
: inputReaderStateCompanion.toRemainingInputAsyncIterator(inputReaderState)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
output,
|
|
174
|
+
position: parserContext.position,
|
|
175
|
+
remainingInput,
|
|
176
|
+
};
|
|
177
|
+
});
|
|
82
178
|
}
|
|
83
179
|
|
|
84
180
|
export async function runParser<
|
|
@@ -91,13 +187,21 @@ export async function runParser<
|
|
|
91
187
|
parserInputCompanion: ParserInputCompanion<Sequence, Element>,
|
|
92
188
|
options: RunParserOptions<Output, Sequence, Element> = {},
|
|
93
189
|
): Promise<Output> {
|
|
94
|
-
const
|
|
190
|
+
const {
|
|
191
|
+
outputPromise,
|
|
192
|
+
parserContext,
|
|
193
|
+
inputReader,
|
|
194
|
+
} = runParserInternal(parser, input, parserInputCompanion, options);
|
|
95
195
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
196
|
+
return await withEnrichedParserError(parserContext, inputReader, async () => {
|
|
197
|
+
const output = await outputPromise;
|
|
198
|
+
|
|
199
|
+
const inputReaderState = inputReader.toInputReaderState();
|
|
101
200
|
|
|
102
|
-
|
|
201
|
+
if (!inputReaderStateCompanion.isDone(inputReaderState)) {
|
|
202
|
+
throw new ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return output;
|
|
206
|
+
});
|
|
103
207
|
}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
import { type Parser } from './parser.js';
|
|
1
|
+
import { getParserName, setParserName, type Parser } from './parser.js';
|
|
2
2
|
|
|
3
|
-
export const createParserAccessorParser = <Output, Sequence>(parserAccessor: () => Parser<Output, Sequence>): Parser<Output, Sequence> =>
|
|
3
|
+
export const createParserAccessorParser = <Output, Sequence>(parserAccessor: () => Parser<Output, Sequence>): Parser<Output, Sequence> => {
|
|
4
|
+
const parserAccessorParser: Parser<Output, Sequence> = async parserContext => {
|
|
5
|
+
const parser = parserAccessor();
|
|
6
|
+
|
|
7
|
+
setParserName(parserAccessorParser, `parserAccessorParser(${getParserName(parser, 'anonymousParserAccessor')})`);
|
|
8
|
+
|
|
9
|
+
return parser(parserContext);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
return parserAccessorParser;
|
|
13
|
+
}
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { createFixedLengthSequenceParser } from "./fixedLengthSequenceParser.js";
|
|
2
|
-
import { Parser } from "./parser.js";
|
|
2
|
+
import { getParserName, Parser, setParserName } from "./parser.js";
|
|
3
3
|
|
|
4
4
|
export const createParserConsumedSequenceParser = <Output, Sequence>(
|
|
5
5
|
childParser: Parser<Output, Sequence>,
|
|
6
|
-
): Parser<[Output, Sequence], Sequence> =>
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
6
|
+
): Parser<[Output, Sequence], Sequence> => {
|
|
7
|
+
const parserConsumedSequenceParser: Parser<[Output, Sequence], Sequence> = async parserContext => {
|
|
8
|
+
const initialPosition = parserContext.position;
|
|
9
|
+
const childParserContext = parserContext.lookahead();
|
|
10
|
+
|
|
11
|
+
let value: Output;
|
|
12
|
+
let consumedLength: number;
|
|
13
|
+
try {
|
|
14
|
+
value = await childParser(childParserContext);
|
|
15
|
+
consumedLength = childParserContext.position - initialPosition;
|
|
16
|
+
} finally {
|
|
17
|
+
childParserContext.dispose();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const consumedSequenceParser = createFixedLengthSequenceParser<Sequence>(consumedLength);
|
|
21
|
+
const consumedSequence = await consumedSequenceParser(parserContext);
|
|
22
|
+
|
|
23
|
+
return [value, consumedSequence];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
setParserName(parserConsumedSequenceParser, `parserConsumedSequenceParser(${getParserName(childParser, 'anonymousParserConsumedSequenceParserChild')})`);
|
|
27
|
+
|
|
28
|
+
return parserConsumedSequenceParser;
|
|
29
|
+
};
|
|
@@ -30,6 +30,29 @@ test('parserContext.read', async t => {
|
|
|
30
30
|
});
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
+
test('parserContext.readSequence', async t => {
|
|
34
|
+
const parserContext = new ParserContextImplementation(stringParserInputCompanion, new InputReaderImplementation(stringParserInputCompanion, (async function * () {
|
|
35
|
+
yield '';
|
|
36
|
+
yield 'abc';
|
|
37
|
+
yield 'def';
|
|
38
|
+
yield '';
|
|
39
|
+
yield 'gh';
|
|
40
|
+
})()), ...commonParserContextArguments);
|
|
41
|
+
|
|
42
|
+
t.is(await parserContext.readSequence(0, 0), '');
|
|
43
|
+
t.is(await parserContext.readSequence(0, 1), 'a');
|
|
44
|
+
t.is(await parserContext.readSequence(1, 4), 'cde');
|
|
45
|
+
t.is(await parserContext.readSequence(0, 1), 'f');
|
|
46
|
+
t.is(await parserContext.readSequence(0, 0), '');
|
|
47
|
+
t.is(await parserContext.readSequence(0, 1), 'g');
|
|
48
|
+
t.is(await parserContext.readSequence(1, 1), '');
|
|
49
|
+
t.is(await parserContext.readSequence(0, 0), '');
|
|
50
|
+
|
|
51
|
+
await t.throwsAsync(async () => parserContext.readSequence(0, 1), {
|
|
52
|
+
instanceOf: ParserUnexpectedEndOfInputError,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
33
56
|
test('parserContext.lookahead', async t => {
|
|
34
57
|
const parserContext = new ParserContextImplementation(stringParserInputCompanion, new InputReaderImplementation(stringParserInputCompanion, (async function * () {
|
|
35
58
|
yield * 'abcdefgh';
|
|
@@ -42,11 +65,15 @@ test('parserContext.lookahead', async t => {
|
|
|
42
65
|
});
|
|
43
66
|
|
|
44
67
|
t.is(await lookaheadContext3.peek(2), 'c');
|
|
68
|
+
t.is(await lookaheadContext3.peekSequence(2, 3), 'c');
|
|
45
69
|
t.is(await lookaheadContext3.peek(3), undefined);
|
|
70
|
+
t.is(await lookaheadContext3.peekSequence(3, 4), undefined);
|
|
46
71
|
t.is(await lookaheadContext3.read(0), 'a');
|
|
47
72
|
t.is(await lookaheadContext3.read(0), 'b');
|
|
48
73
|
t.is(await lookaheadContext3.read(0), 'c');
|
|
49
74
|
t.is(await lookaheadContext3.peek(0), undefined);
|
|
75
|
+
t.is(await lookaheadContext3.peekSequence(0, 1), undefined);
|
|
76
|
+
t.is(await lookaheadContext3.peekSequence(0, 0), '');
|
|
50
77
|
|
|
51
78
|
t.is(await parserContext.peek(0), 'a');
|
|
52
79
|
t.is(await lookaheadContext1.peek(0), 'a');
|
|
@@ -63,6 +90,10 @@ test('parserContext.lookahead', async t => {
|
|
|
63
90
|
t.is(lookaheadContext1.position, 1);
|
|
64
91
|
t.is(lookaheadContext2.position, 0);
|
|
65
92
|
t.is(lookaheadContext3.position, 3);
|
|
93
|
+
|
|
94
|
+
lookaheadContext3.skip(1);
|
|
95
|
+
t.is(await lookaheadContext3.peekSequence(0, 0), undefined);
|
|
96
|
+
t.is(lookaheadContext3.position, 4);
|
|
66
97
|
});
|
|
67
98
|
|
|
68
99
|
test('parserContext.unlookahead', async t => {
|
package/src/parserContext.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* eslint-disable prefer-arrow-callback */
|
|
2
2
|
|
|
3
|
-
import invariant from 'invariant';
|
|
4
3
|
import { type ParserInputCompanion } from './parserInputCompanion.js';
|
|
5
4
|
import { type InputReader } from './inputReader.js';
|
|
6
5
|
import {
|
|
@@ -8,6 +7,7 @@ import {
|
|
|
8
7
|
} from './parserError.js';
|
|
9
8
|
import { type RunParserOptions } from './parser.js';
|
|
10
9
|
import { type Falsy, customInvariant, type ValueOrAccessor } from './customInvariant.js';
|
|
10
|
+
import { parserImplementationInvariant } from './parserImplementationInvariant.js';
|
|
11
11
|
|
|
12
12
|
type LookaheadOptions = {
|
|
13
13
|
debugName?: string;
|
|
@@ -21,14 +21,21 @@ type ParserContextOptions<Sequence, Element> =
|
|
|
21
21
|
|
|
22
22
|
export type ParserContext<Sequence, Element> = {
|
|
23
23
|
from(elements: Element[]): Sequence;
|
|
24
|
+
concat(sequences: Sequence[]): Sequence;
|
|
24
25
|
length(sequence: Sequence): number;
|
|
25
26
|
at(sequence: Sequence, index: number): Element | undefined;
|
|
27
|
+
subsequence(sequence: Sequence, start: number, end: number): Sequence;
|
|
28
|
+
indexOf(sequence: Sequence, element: Element, fromIndex?: number): number;
|
|
29
|
+
indexOfSubsequence(sequence: Sequence, subsequence: Sequence, fromIndex?: number): number;
|
|
30
|
+
equals(sequenceA: Sequence, sequenceB: Sequence): boolean;
|
|
26
31
|
|
|
27
32
|
get position(): number;
|
|
28
33
|
peek(offset: number): Promise<Element | undefined>;
|
|
34
|
+
peekSequence(start: number, end: number): Promise<Sequence | undefined>;
|
|
29
35
|
skip(offset: number): void;
|
|
30
36
|
|
|
31
37
|
read(offset: number): Promise<Element>;
|
|
38
|
+
readSequence(start: number, end: number): Promise<Sequence>;
|
|
32
39
|
|
|
33
40
|
lookahead(options?: LookaheadOptions): ParserContext<Sequence, Element>;
|
|
34
41
|
unlookahead(): void;
|
|
@@ -72,6 +79,10 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
72
79
|
return this._parserInputCompanion.from(elements);
|
|
73
80
|
}
|
|
74
81
|
|
|
82
|
+
concat(sequences: Sequence[]): Sequence {
|
|
83
|
+
return this._parserInputCompanion.concat(sequences);
|
|
84
|
+
}
|
|
85
|
+
|
|
75
86
|
length(sequence: Sequence): number {
|
|
76
87
|
return this._parserInputCompanion.length(sequence);
|
|
77
88
|
}
|
|
@@ -80,6 +91,22 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
80
91
|
return this._parserInputCompanion.at(sequence, index);
|
|
81
92
|
}
|
|
82
93
|
|
|
94
|
+
subsequence(sequence: Sequence, start: number, end: number): Sequence {
|
|
95
|
+
return this._parserInputCompanion.subsequence(sequence, start, end);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
indexOf(sequence: Sequence, element: Element, fromIndex?: number): number {
|
|
99
|
+
return this._parserInputCompanion.indexOf(sequence, element, fromIndex);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
indexOfSubsequence(sequence: Sequence, subsequence: Sequence, fromIndex?: number): number {
|
|
103
|
+
return this._parserInputCompanion.indexOfSubsequence(sequence, subsequence, fromIndex);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
equals(sequenceA: Sequence, sequenceB: Sequence): boolean {
|
|
107
|
+
return this._parserInputCompanion.equals(sequenceA, sequenceB);
|
|
108
|
+
}
|
|
109
|
+
|
|
83
110
|
get position() {
|
|
84
111
|
return this._inputReader.position;
|
|
85
112
|
}
|
|
@@ -95,6 +122,39 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
95
122
|
return this._inputReader.peek(offset);
|
|
96
123
|
}
|
|
97
124
|
|
|
125
|
+
async peekSequence(start: number, end: number): Promise<Sequence | undefined> {
|
|
126
|
+
if (
|
|
127
|
+
this._options.sliceEnd !== undefined
|
|
128
|
+
&& (this.position + end - 1) >= this._options.sliceEnd
|
|
129
|
+
) {
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
parserImplementationInvariant(
|
|
134
|
+
start >= 0,
|
|
135
|
+
'start (%s) >= 0',
|
|
136
|
+
start,
|
|
137
|
+
);
|
|
138
|
+
parserImplementationInvariant(
|
|
139
|
+
end >= start,
|
|
140
|
+
'end (%s) >= start (%s)',
|
|
141
|
+
start,
|
|
142
|
+
end,
|
|
143
|
+
);
|
|
144
|
+
parserImplementationInvariant(
|
|
145
|
+
Number.isSafeInteger(start),
|
|
146
|
+
'start (%d) is not a safe integer',
|
|
147
|
+
start,
|
|
148
|
+
);
|
|
149
|
+
parserImplementationInvariant(
|
|
150
|
+
Number.isSafeInteger(end),
|
|
151
|
+
'end (%d) is not a safe integer',
|
|
152
|
+
end,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return this._inputReader.peekSequence(start, end);
|
|
156
|
+
}
|
|
157
|
+
|
|
98
158
|
skip(offset: number) {
|
|
99
159
|
this._inputReader.skip(offset);
|
|
100
160
|
}
|
|
@@ -111,21 +171,31 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
111
171
|
return element;
|
|
112
172
|
}
|
|
113
173
|
|
|
114
|
-
|
|
115
|
-
const
|
|
174
|
+
async readSequence(start: number, end: number): Promise<Sequence> {
|
|
175
|
+
const sequence = await this.peekSequence(start, end);
|
|
116
176
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
177
|
+
if (sequence === undefined) {
|
|
178
|
+
throw new ParserUnexpectedEndOfInputError('', this._depth, this.position);
|
|
119
179
|
}
|
|
120
180
|
|
|
121
|
-
|
|
181
|
+
this.skip(end);
|
|
182
|
+
|
|
183
|
+
return sequence;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
lookahead(options: LookaheadOptions = {}): ParserContext<Sequence, Element> {
|
|
187
|
+
const lookaheadInputReader = this._inputReader.lookahead();
|
|
188
|
+
|
|
189
|
+
parserImplementationInvariant(
|
|
122
190
|
this.position === lookaheadInputReader.position,
|
|
123
191
|
'lookahead this.position (%s) === lookaheadInputReader.position (%s)',
|
|
124
192
|
this.position,
|
|
125
193
|
lookaheadInputReader.position,
|
|
126
194
|
);
|
|
127
195
|
|
|
128
|
-
const
|
|
196
|
+
const ParserContext = this._options.parserContextClass ?? ParserContextImplementation;
|
|
197
|
+
|
|
198
|
+
const lookaheadParserContext = new ParserContext<Sequence, Element>(
|
|
129
199
|
this._parserInputCompanion,
|
|
130
200
|
lookaheadInputReader,
|
|
131
201
|
this,
|
|
@@ -143,11 +213,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
143
213
|
},
|
|
144
214
|
);
|
|
145
215
|
|
|
146
|
-
|
|
147
|
-
debugger;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
invariant(
|
|
216
|
+
parserImplementationInvariant(
|
|
151
217
|
this.position === lookaheadParserContext.position,
|
|
152
218
|
'lookahead this.position (%s) === lookaheadParserContext.position (%s)',
|
|
153
219
|
this.position,
|
|
@@ -158,11 +224,14 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
158
224
|
}
|
|
159
225
|
|
|
160
226
|
unlookahead() {
|
|
161
|
-
|
|
162
|
-
|
|
227
|
+
const parentParserContext = parserImplementationInvariant(
|
|
228
|
+
this._parentParserContext,
|
|
229
|
+
'this._parentParserContext !== undefined',
|
|
230
|
+
);
|
|
231
|
+
parserImplementationInvariant(
|
|
163
232
|
(
|
|
164
|
-
|
|
165
|
-
||
|
|
233
|
+
parentParserContext._exclusiveChildParserContext === undefined
|
|
234
|
+
|| parentParserContext._exclusiveChildParserContext === this
|
|
166
235
|
),
|
|
167
236
|
[
|
|
168
237
|
'Parent\'s exclusive child must be undefined or this',
|
|
@@ -171,29 +240,29 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
171
240
|
'parent.exclusiveChild: %s',
|
|
172
241
|
].join('\n'),
|
|
173
242
|
this.toString(),
|
|
174
|
-
|
|
175
|
-
|
|
243
|
+
parentParserContext.toString(),
|
|
244
|
+
parentParserContext._exclusiveChildParserContext?.toString(),
|
|
176
245
|
);
|
|
177
|
-
|
|
178
|
-
|
|
246
|
+
parserImplementationInvariant(
|
|
247
|
+
parentParserContext.position <= this.position,
|
|
179
248
|
'unlookahead this._parentParserContext.position (%s) <= this.position (%s)',
|
|
180
|
-
|
|
249
|
+
parentParserContext.position,
|
|
181
250
|
this.position,
|
|
182
251
|
);
|
|
183
252
|
|
|
184
|
-
const offset = this._inputReader.position -
|
|
253
|
+
const offset = this._inputReader.position - parentParserContext._inputReader.position;
|
|
185
254
|
|
|
186
|
-
|
|
255
|
+
parentParserContext.skip(offset);
|
|
187
256
|
|
|
188
|
-
|
|
189
|
-
|
|
257
|
+
parserImplementationInvariant(
|
|
258
|
+
parentParserContext.position === this.position,
|
|
190
259
|
'unlookahead this._parentParserContext.position (%s) === this.position (%s)',
|
|
191
|
-
|
|
260
|
+
parentParserContext.position,
|
|
192
261
|
this.position,
|
|
193
262
|
);
|
|
194
263
|
|
|
195
|
-
this._inputReader =
|
|
196
|
-
|
|
264
|
+
this._inputReader = parentParserContext._inputReader;
|
|
265
|
+
parentParserContext._exclusiveChildParserContext = this;
|
|
197
266
|
|
|
198
267
|
if (this._exclusiveChildParserContext) {
|
|
199
268
|
this._exclusiveChildParserContext.unlookahead();
|
|
@@ -201,11 +270,14 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
201
270
|
}
|
|
202
271
|
|
|
203
272
|
dispose() {
|
|
204
|
-
|
|
205
|
-
|
|
273
|
+
const parentParserContext = parserImplementationInvariant(
|
|
274
|
+
this._parentParserContext,
|
|
275
|
+
'this._parentParserContext !== undefined',
|
|
276
|
+
);
|
|
277
|
+
parserImplementationInvariant(
|
|
206
278
|
(
|
|
207
|
-
|
|
208
|
-
||
|
|
279
|
+
parentParserContext._exclusiveChildParserContext === undefined
|
|
280
|
+
|| parentParserContext._exclusiveChildParserContext === this
|
|
209
281
|
),
|
|
210
282
|
[
|
|
211
283
|
'Parent\'s exclusive child must be undefined or this',
|
|
@@ -214,11 +286,11 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
214
286
|
'parent.exclusiveChild: %s',
|
|
215
287
|
].join('\n'),
|
|
216
288
|
this.toString(),
|
|
217
|
-
|
|
218
|
-
|
|
289
|
+
parentParserContext.toString(),
|
|
290
|
+
parentParserContext._exclusiveChildParserContext?.toString(),
|
|
219
291
|
);
|
|
220
292
|
|
|
221
|
-
|
|
293
|
+
parentParserContext._exclusiveChildParserContext = undefined;
|
|
222
294
|
this._parentParserContext = undefined;
|
|
223
295
|
}
|
|
224
296
|
|
|
@@ -231,7 +303,7 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
231
303
|
}
|
|
232
304
|
|
|
233
305
|
invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: any[]): Exclude<T, Falsy> {
|
|
234
|
-
|
|
306
|
+
parserImplementationInvariant(childErrors.length > 0, 'childErrors.length > 0');
|
|
235
307
|
|
|
236
308
|
const errorJoinMode = this._options.errorJoinMode ?? 'none';
|
|
237
309
|
const parserContext = this;
|
|
@@ -315,6 +387,6 @@ export class ParserContextImplementation<Sequence, Element> implements ParserCon
|
|
|
315
387
|
}, value, format, ...formatArguments);
|
|
316
388
|
}
|
|
317
389
|
|
|
318
|
-
|
|
390
|
+
return parserImplementationInvariant(false, 'Unsupported errorJoinMode: %s', errorJoinMode);
|
|
319
391
|
}
|
|
320
392
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import mem from 'mem';
|
|
1
2
|
import { type Parser } from './parser.js';
|
|
2
3
|
import { type DeriveSequenceElement } from './sequence.js';
|
|
3
4
|
|
|
@@ -11,13 +12,30 @@ export function parserCreatorCompose<
|
|
|
11
12
|
f1: (...arguments_: Arguments) => Parser<OutputA, Sequence, Element>,
|
|
12
13
|
f2: (outputA: OutputA) => Parser<OutputB, Sequence, Element>,
|
|
13
14
|
): (...arguments_: Arguments) => Parser<OutputB, Sequence, Element> {
|
|
14
|
-
|
|
15
|
+
const parserCreatorComposedOuter: (...arguments_: Arguments) => Parser<OutputB, Sequence, Element> = (...arguments_) => {
|
|
15
16
|
const parserA = f1(...arguments_);
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
const parserCreatorComposedInner: Parser<OutputB, Sequence, Element> = async parserContext => {
|
|
18
19
|
const outputA = await parserA(parserContext);
|
|
19
20
|
const parserB = f2(outputA);
|
|
20
21
|
return parserB(parserContext);
|
|
21
22
|
};
|
|
23
|
+
|
|
24
|
+
return parserCreatorComposedInner;
|
|
22
25
|
};
|
|
26
|
+
|
|
27
|
+
return parserCreatorComposedOuter;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function parserCreatorComposeMem<
|
|
31
|
+
Arguments extends unknown[],
|
|
32
|
+
OutputA,
|
|
33
|
+
OutputB,
|
|
34
|
+
Sequence,
|
|
35
|
+
Element = DeriveSequenceElement<Sequence>,
|
|
36
|
+
>(
|
|
37
|
+
f1: (...arguments_: Arguments) => Parser<OutputA, Sequence, Element>,
|
|
38
|
+
f2: (outputA: OutputA) => Parser<OutputB, Sequence, Element>,
|
|
39
|
+
): (...arguments_: Arguments) => Parser<OutputB, Sequence, Element> {
|
|
40
|
+
return parserCreatorCompose(mem(f1), mem(f2));
|
|
23
41
|
}
|