@futpib/parser 1.0.3 → 1.0.6
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/.claude/settings.local.json +24 -0
- package/.github/workflows/main.yml +1 -0
- package/build/androidPackageParser.js +30 -32
- package/build/arbitraryDalvikBytecode.d.ts +3 -3
- package/build/arbitraryDalvikBytecode.js +33 -27
- package/build/arbitraryDalvikExecutable.js +55 -17
- package/build/arbitraryJava.d.ts +31 -0
- package/build/arbitraryJava.js +532 -0
- package/build/arbitraryJavaScript.d.ts +3 -0
- package/build/arbitraryJavaScript.js +263 -0
- package/build/arbitraryJavascript.d.ts +3 -0
- package/build/arbitraryJavascript.js +263 -0
- package/build/arbitraryZig.d.ts +3 -0
- package/build/arbitraryZig.js +240 -0
- package/build/arbitraryZipStream.d.ts +1 -1
- package/build/arrayParser.js +72 -13
- package/build/backsmali.d.ts +4 -3
- package/build/backsmali.js +26 -6
- package/build/bash.d.ts +89 -0
- package/build/bash.js +1 -0
- package/build/bashParser.d.ts +6 -0
- package/build/bashParser.js +335 -0
- package/build/bashParser.test.d.ts +1 -0
- package/build/bashParser.test.js +343 -0
- package/build/bashParserEdgeCases.test.d.ts +1 -0
- package/build/bashParserEdgeCases.test.js +117 -0
- package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
- package/build/dalvikBytecodeParser/addressConversion.js +334 -0
- package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
- package/build/dalvikBytecodeParser/formatParsers.js +13 -14
- package/build/dalvikBytecodeParser.d.ts +60 -31
- package/build/dalvikBytecodeParser.js +92 -35
- package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
- package/build/dalvikBytecodeParser.test-d.js +268 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
- package/build/dalvikBytecodeUnparser.d.ts +2 -2
- package/build/dalvikBytecodeUnparser.js +23 -23
- package/build/dalvikBytecodeUnparser.test.js +7 -7
- package/build/dalvikExecutable.d.ts +3 -3
- package/build/dalvikExecutable.test-d.d.ts +1 -0
- package/build/dalvikExecutable.test-d.js +59 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
- package/build/dalvikExecutableParser/typedNumbers.js +3 -0
- package/build/dalvikExecutableParser.d.ts +2 -1
- package/build/dalvikExecutableParser.js +96 -77
- package/build/dalvikExecutableParser.test.js +24 -3
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
- package/build/dalvikExecutableUnparser.d.ts +2 -2
- package/build/dalvikExecutableUnparser.test.js +2 -1
- package/build/disjunctionParser.d.ts +5 -3
- package/build/disjunctionParser.js +79 -17
- package/build/disjunctionParser.test-d.d.ts +1 -0
- package/build/disjunctionParser.test-d.js +72 -0
- package/build/elementSwitchParser.d.ts +4 -0
- package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
- package/build/elementSwitchParser.test-d.d.ts +1 -0
- package/build/elementSwitchParser.test-d.js +44 -0
- package/build/exactSequenceParser.d.ts +4 -2
- package/build/exactSequenceParser.test-d.d.ts +1 -0
- package/build/exactSequenceParser.test-d.js +36 -0
- package/build/fetchCid.js +2 -66
- package/build/index.d.ts +25 -2
- package/build/index.js +23 -1
- package/build/index.test.js +16 -1
- package/build/inputReader.d.ts +10 -0
- package/build/inputReader.js +36 -0
- package/build/java.d.ts +502 -0
- package/build/java.js +2 -0
- package/build/javaKeyStoreParser.js +14 -17
- package/build/javaParser.d.ts +51 -0
- package/build/javaParser.js +1538 -0
- package/build/javaParser.test.d.ts +1 -0
- package/build/javaParser.test.js +1287 -0
- package/build/javaScript.d.ts +35 -0
- package/build/javaScript.js +1 -0
- package/build/javaScriptParser.d.ts +9 -0
- package/build/javaScriptParser.js +34 -0
- package/build/javaScriptUnparser.d.ts +3 -0
- package/build/javaScriptUnparser.js +4 -0
- package/build/javaScriptUnparser.test.d.ts +1 -0
- package/build/javaScriptUnparser.test.js +24 -0
- package/build/javaUnparser.d.ts +2 -0
- package/build/javaUnparser.js +519 -0
- package/build/javaUnparser.test.d.ts +1 -0
- package/build/javaUnparser.test.js +24 -0
- package/build/javascript.d.ts +35 -0
- package/build/javascript.js +1 -0
- package/build/javascriptParser.d.ts +9 -0
- package/build/javascriptParser.js +34 -0
- package/build/javascriptUnparser.d.ts +3 -0
- package/build/javascriptUnparser.js +4 -0
- package/build/javascriptUnparser.test.d.ts +1 -0
- package/build/javascriptUnparser.test.js +24 -0
- package/build/jsonParser.js +2 -12
- package/build/lazyMessageError.d.ts +3 -0
- package/build/lookaheadParser.js +60 -3
- package/build/negativeLookaheadParser.js +70 -11
- package/build/nonEmptyArrayParser.js +72 -13
- package/build/objectParser.d.ts +12 -0
- package/build/objectParser.js +31 -0
- package/build/objectParser.test-d.d.ts +1 -0
- package/build/objectParser.test-d.js +112 -0
- package/build/objectParser.test.d.ts +1 -0
- package/build/objectParser.test.js +55 -0
- package/build/optionalParser.js +69 -10
- package/build/parser.d.ts +4 -0
- package/build/parser.js +3 -1
- package/build/parser.test.js +114 -1
- package/build/parserConsumedSequenceParser.js +66 -7
- package/build/parserContext.d.ts +6 -0
- package/build/parserContext.js +20 -11
- package/build/parserError.d.ts +119 -27
- package/build/parserError.js +16 -8
- package/build/regexpParser.d.ts +2 -0
- package/build/regexpParser.js +101 -0
- package/build/regexpParser.test.d.ts +1 -0
- package/build/regexpParser.test.js +114 -0
- package/build/regularExpression.d.ts +63 -0
- package/build/regularExpression.js +1 -0
- package/build/regularExpressionParser.d.ts +3 -0
- package/build/regularExpressionParser.js +600 -0
- package/build/regularExpressionParser.test.d.ts +1 -0
- package/build/regularExpressionParser.test.js +89 -0
- package/build/separatedArrayParser.js +73 -14
- package/build/separatedNonEmptyArrayParser.js +73 -14
- package/build/sliceBoundedParser.js +62 -5
- package/build/smaliParser.d.ts +7 -7
- package/build/smaliParser.js +185 -268
- package/build/smaliParser.test.js +58 -0
- package/build/stringEscapes.d.ts +5 -0
- package/build/stringEscapes.js +244 -0
- package/build/symbolicExpression.d.ts +29 -0
- package/build/symbolicExpression.js +1 -0
- package/build/symbolicExpressionParser.d.ts +4 -0
- package/build/symbolicExpressionParser.js +123 -0
- package/build/symbolicExpressionParser.test.d.ts +1 -0
- package/build/symbolicExpressionParser.test.js +289 -0
- package/build/terminatedArrayParser.js +113 -38
- package/build/terminatedArrayParser.test.js +4 -2
- package/build/tupleParser.d.ts +7 -15
- package/build/tupleParser.js +1 -0
- package/build/unionParser.d.ts +5 -3
- package/build/unionParser.js +7 -2
- package/build/unionParser.test-d.d.ts +1 -0
- package/build/unionParser.test-d.js +72 -0
- package/build/unionParser.test.js +10 -11
- package/build/zig.d.ts +280 -0
- package/build/zig.js +2 -0
- package/build/zigParser.d.ts +3 -0
- package/build/zigParser.js +1119 -0
- package/build/zigParser.test.d.ts +1 -0
- package/build/zigParser.test.js +1590 -0
- package/build/zigUnparser.d.ts +2 -0
- package/build/zigUnparser.js +460 -0
- package/build/zigUnparser.test.d.ts +1 -0
- package/build/zigUnparser.test.js +24 -0
- package/build/zipParser.js +19 -32
- package/build/zipUnparser.js +19 -7
- package/build/zipUnparser.test.js +1 -1
- package/node_modules-@types/s-expression/index.d.ts +5 -0
- package/package.json +25 -6
- package/src/androidPackageParser.ts +33 -60
- package/src/arbitraryDalvikBytecode.ts +39 -31
- package/src/arbitraryDalvikExecutable.ts +65 -20
- package/src/arbitraryJava.ts +804 -0
- package/src/arbitraryJavaScript.ts +410 -0
- package/src/arbitraryZig.ts +380 -0
- package/src/arrayParser.ts +1 -3
- package/src/backsmali.ts +35 -4
- package/src/bash.ts +127 -0
- package/src/bashParser.test.ts +590 -0
- package/src/bashParser.ts +498 -0
- package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
- package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
- package/src/dalvikBytecodeParser.test-d.ts +310 -0
- package/src/dalvikBytecodeParser.ts +194 -69
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
- package/src/dalvikBytecodeUnparser.test.ts +7 -7
- package/src/dalvikBytecodeUnparser.ts +31 -30
- package/src/dalvikExecutable.test-d.ts +132 -0
- package/src/dalvikExecutable.ts +3 -3
- package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
- package/src/dalvikExecutableParser.test.ts +37 -3
- package/src/dalvikExecutableParser.test.ts.md +163 -2
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +121 -139
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
- package/src/dalvikExecutableUnparser.test.ts +3 -2
- package/src/dalvikExecutableUnparser.ts +4 -4
- package/src/disjunctionParser.test-d.ts +105 -0
- package/src/disjunctionParser.ts +18 -15
- package/src/elementSwitchParser.test-d.ts +74 -0
- package/src/elementSwitchParser.ts +51 -0
- package/src/exactSequenceParser.test-d.ts +43 -0
- package/src/exactSequenceParser.ts +13 -8
- package/src/fetchCid.ts +2 -76
- package/src/index.test.ts +22 -1
- package/src/index.ts +119 -2
- package/src/inputReader.ts +53 -0
- package/src/java.ts +708 -0
- package/src/javaKeyStoreParser.ts +18 -32
- package/src/javaParser.test.ts +1592 -0
- package/src/javaParser.ts +2640 -0
- package/src/javaScript.ts +36 -0
- package/src/javaScriptParser.ts +57 -0
- package/src/javaScriptUnparser.test.ts +37 -0
- package/src/javaScriptUnparser.ts +7 -0
- package/src/javaUnparser.test.ts +37 -0
- package/src/javaUnparser.ts +640 -0
- package/src/jsonParser.ts +6 -27
- package/src/lookaheadParser.ts +2 -6
- package/src/negativeLookaheadParser.ts +1 -3
- package/src/nonEmptyArrayParser.ts +1 -3
- package/src/objectParser.test-d.ts +152 -0
- package/src/objectParser.test.ts +71 -0
- package/src/objectParser.ts +69 -0
- package/src/optionalParser.ts +1 -3
- package/src/parser.test.ts +151 -4
- package/src/parser.ts +11 -1
- package/src/parserConsumedSequenceParser.ts +2 -4
- package/src/parserContext.ts +26 -11
- package/src/parserError.ts +17 -3
- package/src/regexpParser.test.ts +264 -0
- package/src/regexpParser.ts +126 -0
- package/src/regularExpression.ts +24 -0
- package/src/regularExpressionParser.test.ts +102 -0
- package/src/regularExpressionParser.ts +920 -0
- package/src/separatedArrayParser.ts +1 -3
- package/src/separatedNonEmptyArrayParser.ts +1 -3
- package/src/sliceBoundedParser.test.ts +2 -2
- package/src/sliceBoundedParser.ts +15 -19
- package/src/smaliParser.test.ts +64 -0
- package/src/smaliParser.test.ts.md +12 -12
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +246 -534
- package/src/stringEscapes.ts +253 -0
- package/src/symbolicExpression.ts +17 -0
- package/src/symbolicExpressionParser.test.ts +466 -0
- package/src/symbolicExpressionParser.ts +190 -0
- package/src/terminatedArrayParser.test.ts +9 -6
- package/src/terminatedArrayParser.ts +25 -29
- package/src/tupleParser.ts +21 -18
- package/src/unionParser.test-d.ts +105 -0
- package/src/unionParser.test.ts +18 -17
- package/src/unionParser.ts +28 -16
- package/src/zig.ts +411 -0
- package/src/zigParser.test.ts +1693 -0
- package/src/zigParser.ts +1745 -0
- package/src/zigUnparser.test.ts +37 -0
- package/src/zigUnparser.ts +615 -0
- package/src/zipParser.ts +20 -56
- package/src/zipUnparser.test.ts +1 -1
- package/src/zipUnparser.ts +22 -7
- package/tsconfig.json +2 -2
- package/build/exactElementSwitchParser.d.ts +0 -3
- package/src/exactElementSwitchParser.ts +0 -41
|
@@ -5,7 +5,7 @@ export const createNegativeLookaheadParser = <Sequence>(
|
|
|
5
5
|
childParser: Parser<unknown, Sequence>,
|
|
6
6
|
): Parser<void, Sequence> => {
|
|
7
7
|
const negativeLookaheadParser: Parser<void, Sequence> = async parserContext => {
|
|
8
|
-
|
|
8
|
+
using childParserContext = parserContext.lookahead();
|
|
9
9
|
|
|
10
10
|
let childParserSuccess: boolean;
|
|
11
11
|
|
|
@@ -19,8 +19,6 @@ export const createNegativeLookaheadParser = <Sequence>(
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
childParserSuccess = false;
|
|
22
|
-
} finally {
|
|
23
|
-
childParserContext.dispose();
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
parserContext.invariant(
|
|
@@ -8,7 +8,7 @@ export const createNonEmptyArrayParser = <ElementOutput, Sequence>(
|
|
|
8
8
|
const elements: ElementOutput[] = [];
|
|
9
9
|
|
|
10
10
|
while (true) {
|
|
11
|
-
|
|
11
|
+
using elementParserContext = parserContext.lookahead();
|
|
12
12
|
const initialPosition = elementParserContext.position;
|
|
13
13
|
try {
|
|
14
14
|
const element = await elementParser(elementParserContext);
|
|
@@ -24,8 +24,6 @@ export const createNonEmptyArrayParser = <ElementOutput, Sequence>(
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
throw error;
|
|
27
|
-
} finally {
|
|
28
|
-
elementParserContext.dispose();
|
|
29
27
|
}
|
|
30
28
|
}
|
|
31
29
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { expectAssignable, expectNotAssignable, expectType } from 'tsd';
|
|
2
|
+
import { createObjectParser } from './objectParser.js';
|
|
3
|
+
import { type Parser, type ParserOutput } from './parser.js';
|
|
4
|
+
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
5
|
+
import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
|
|
6
|
+
|
|
7
|
+
// Test: parsers only - extracts output types
|
|
8
|
+
{
|
|
9
|
+
const parser = createObjectParser({
|
|
10
|
+
first: createFixedLengthSequenceParser<string>(3),
|
|
11
|
+
second: createFixedLengthSequenceParser<string>(3),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type Output = ParserOutput<typeof parser>;
|
|
15
|
+
|
|
16
|
+
// Output should be assignable to and from expected type
|
|
17
|
+
expectAssignable<{ first: string; second: string }>(null! as Output);
|
|
18
|
+
expectAssignable<Output>(null! as { first: string; second: string });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Test: literal types are preserved
|
|
22
|
+
{
|
|
23
|
+
const parser = createObjectParser({
|
|
24
|
+
type: 'block' as const,
|
|
25
|
+
name: createFixedLengthSequenceParser<string>(3),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
type Output = ParserOutput<typeof parser>;
|
|
29
|
+
|
|
30
|
+
// 'block' literal should be preserved
|
|
31
|
+
expectAssignable<{ type: 'block'; name: string }>(null! as Output);
|
|
32
|
+
expectType<'block'>(null! as Output['type']);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Test: underscore keys excluded from result type
|
|
36
|
+
{
|
|
37
|
+
const parser = createObjectParser({
|
|
38
|
+
first: createFixedLengthSequenceParser<string>(3),
|
|
39
|
+
_sep: createExactSequenceParser(':'),
|
|
40
|
+
second: createFixedLengthSequenceParser<string>(3),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
type Output = ParserOutput<typeof parser>;
|
|
44
|
+
|
|
45
|
+
// Should have first and second but not _sep
|
|
46
|
+
expectAssignable<{ first: string; second: string }>(null! as Output);
|
|
47
|
+
|
|
48
|
+
// _sep should NOT be a key in Output
|
|
49
|
+
expectNotAssignable<{ _sep: string }>(null! as Output);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Test: mixed literals and parsers with underscore keys
|
|
53
|
+
{
|
|
54
|
+
const parser = createObjectParser({
|
|
55
|
+
type: 'assignment' as const,
|
|
56
|
+
_open: createExactSequenceParser('('),
|
|
57
|
+
name: createFixedLengthSequenceParser<string>(1),
|
|
58
|
+
_eq: createExactSequenceParser('='),
|
|
59
|
+
value: createFixedLengthSequenceParser<string>(1),
|
|
60
|
+
_close: createExactSequenceParser(')'),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
type Output = ParserOutput<typeof parser>;
|
|
64
|
+
|
|
65
|
+
expectAssignable<{ type: 'assignment'; name: string; value: string }>(null! as Output);
|
|
66
|
+
expectType<'assignment'>(null! as Output['type']);
|
|
67
|
+
|
|
68
|
+
// Underscore keys should not exist
|
|
69
|
+
expectNotAssignable<{ _open: string }>(null! as Output);
|
|
70
|
+
expectNotAssignable<{ _eq: string }>(null! as Output);
|
|
71
|
+
expectNotAssignable<{ _close: string }>(null! as Output);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Test: number literal
|
|
75
|
+
{
|
|
76
|
+
const parser = createObjectParser({
|
|
77
|
+
code: 42 as const,
|
|
78
|
+
data: createFixedLengthSequenceParser<string>(2),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
type Output = ParserOutput<typeof parser>;
|
|
82
|
+
|
|
83
|
+
expectAssignable<{ code: 42; data: string }>(null! as Output);
|
|
84
|
+
expectType<42>(null! as Output['code']);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Test: all underscore keys results in empty object
|
|
88
|
+
{
|
|
89
|
+
const parser = createObjectParser({
|
|
90
|
+
_a: createExactSequenceParser('a'),
|
|
91
|
+
_b: createExactSequenceParser('b'),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
type Output = ParserOutput<typeof parser>;
|
|
95
|
+
|
|
96
|
+
// Should be assignable to empty object
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
98
|
+
expectAssignable<{}>(null! as Output);
|
|
99
|
+
|
|
100
|
+
// Should NOT have _a or _b
|
|
101
|
+
expectNotAssignable<{ _a: string }>(null! as Output);
|
|
102
|
+
expectNotAssignable<{ _b: string }>(null! as Output);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Test: boolean literal
|
|
106
|
+
{
|
|
107
|
+
const parser = createObjectParser({
|
|
108
|
+
enabled: true as const,
|
|
109
|
+
name: createFixedLengthSequenceParser<string>(3),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
type Output = ParserOutput<typeof parser>;
|
|
113
|
+
|
|
114
|
+
expectAssignable<{ enabled: true; name: string }>(null! as Output);
|
|
115
|
+
expectType<true>(null! as Output['enabled']);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Test: null literal
|
|
119
|
+
{
|
|
120
|
+
const parser = createObjectParser({
|
|
121
|
+
value: null,
|
|
122
|
+
name: createFixedLengthSequenceParser<string>(3),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
type Output = ParserOutput<typeof parser>;
|
|
126
|
+
|
|
127
|
+
expectAssignable<{ value: null; name: string }>(null! as Output);
|
|
128
|
+
expectType<null>(null! as Output['value']);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Test: underscore-prefixed parsers still contribute to sequence type inference
|
|
132
|
+
{
|
|
133
|
+
const parser = createObjectParser({
|
|
134
|
+
_prefix: createExactSequenceParser<Uint8Array>(Buffer.from([0x00])),
|
|
135
|
+
operation: 'nop' as const,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Parser should be assignable to Parser<{ operation: 'nop' }, Uint8Array>
|
|
139
|
+
expectAssignable<Parser<{ operation: 'nop' }, Uint8Array>>(parser);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Test: sequence type inferred from underscore parser when no other parsers present
|
|
143
|
+
{
|
|
144
|
+
const parser = createObjectParser({
|
|
145
|
+
_marker: createExactSequenceParser<string>('test'),
|
|
146
|
+
type: 'marker' as const,
|
|
147
|
+
value: 42 as const,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Should infer string sequence from _marker parser
|
|
151
|
+
expectAssignable<Parser<{ type: 'marker'; value: 42 }, string>>(parser);
|
|
152
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { createObjectParser } from './objectParser.js';
|
|
3
|
+
import { runParser } from './parser.js';
|
|
4
|
+
import { stringParserInputCompanion } from './parserInputCompanion.js';
|
|
5
|
+
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
6
|
+
import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
|
|
7
|
+
|
|
8
|
+
// Type tests are in objectParser.test-d.ts (using tsd)
|
|
9
|
+
|
|
10
|
+
test('parses object with parsers only', async t => {
|
|
11
|
+
const parser = createObjectParser({
|
|
12
|
+
first: createFixedLengthSequenceParser<string>(3),
|
|
13
|
+
second: createFixedLengthSequenceParser<string>(3),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const output = await runParser(parser, 'foobar', stringParserInputCompanion);
|
|
17
|
+
|
|
18
|
+
t.deepEqual(output, { first: 'foo', second: 'bar' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('parses object with literals', async t => {
|
|
22
|
+
const parser = createObjectParser({
|
|
23
|
+
type: 'block' as const,
|
|
24
|
+
value: createFixedLengthSequenceParser<string>(3),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const output = await runParser(parser, 'foo', stringParserInputCompanion);
|
|
28
|
+
|
|
29
|
+
t.deepEqual(output, { type: 'block', value: 'foo' });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('excludes underscore-prefixed keys from result but runs parsers', async t => {
|
|
33
|
+
const parser = createObjectParser({
|
|
34
|
+
first: createFixedLengthSequenceParser<string>(3),
|
|
35
|
+
_separator: createExactSequenceParser(':'),
|
|
36
|
+
second: createFixedLengthSequenceParser<string>(3),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const output = await runParser(parser, 'foo:bar', stringParserInputCompanion);
|
|
40
|
+
|
|
41
|
+
t.deepEqual(output, { first: 'foo', second: 'bar' });
|
|
42
|
+
t.false('_separator' in output);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('preserves property order', async t => {
|
|
46
|
+
const parser = createObjectParser({
|
|
47
|
+
c: createFixedLengthSequenceParser<string>(1),
|
|
48
|
+
a: createFixedLengthSequenceParser<string>(1),
|
|
49
|
+
b: createFixedLengthSequenceParser<string>(1),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const output = await runParser(parser, 'xyz', stringParserInputCompanion);
|
|
53
|
+
|
|
54
|
+
t.deepEqual(Object.keys(output), ['c', 'a', 'b']);
|
|
55
|
+
t.deepEqual(output, { c: 'x', a: 'y', b: 'z' });
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('mixed parsers and literals with underscore keys', async t => {
|
|
59
|
+
const parser = createObjectParser({
|
|
60
|
+
type: 'assignment' as const,
|
|
61
|
+
_open: createExactSequenceParser('('),
|
|
62
|
+
name: createFixedLengthSequenceParser<string>(1),
|
|
63
|
+
_eq: createExactSequenceParser('='),
|
|
64
|
+
value: createFixedLengthSequenceParser<string>(1),
|
|
65
|
+
_close: createExactSequenceParser(')'),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const output = await runParser(parser, '(x=5)', stringParserInputCompanion);
|
|
69
|
+
|
|
70
|
+
t.deepEqual(output, { type: 'assignment', name: 'x', value: '5' });
|
|
71
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getParserName, setParserName, type Parser, type ParserOutput, type ParserSequence } from './parser.js';
|
|
2
|
+
|
|
3
|
+
// Extract only parser values from an object (filter out literals)
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
type ExtractParsers<T> = T[keyof T] & Parser<any, any, any>;
|
|
6
|
+
|
|
7
|
+
// Extract Sequence from an object of parsers (finds parser's sequence type, ignoring literals)
|
|
8
|
+
type InferSequenceFromParsers<T> = ParserSequence<ExtractParsers<T>>;
|
|
9
|
+
|
|
10
|
+
// Extract output type: Parser<O, S> → O, literal L → L
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
type ExtractOutputOrLiteral<P> = P extends Parser<any, any, any> ? ParserOutput<P> : P;
|
|
13
|
+
|
|
14
|
+
// Filter out underscore-prefixed keys
|
|
15
|
+
type OmitUnderscoreKeys<T> = {
|
|
16
|
+
[K in keyof T as K extends `_${string}` ? never : K]: T[K]
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Result type for object parser
|
|
20
|
+
type ObjectParserOutput<Parsers extends Record<string, unknown>> = OmitUnderscoreKeys<{
|
|
21
|
+
[K in keyof Parsers]: ExtractOutputOrLiteral<Parsers[K]>
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
export function createObjectParser<
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
const Parsers extends Record<string, Parser<any, any, any> | unknown>,
|
|
27
|
+
>(
|
|
28
|
+
parsers: Parsers,
|
|
29
|
+
): Parser<ObjectParserOutput<Parsers>, InferSequenceFromParsers<Parsers>> {
|
|
30
|
+
type Sequence = InferSequenceFromParsers<Parsers>;
|
|
31
|
+
|
|
32
|
+
const objectParser: Parser<ObjectParserOutput<Parsers>, Sequence> = async parserContext => {
|
|
33
|
+
const result: Record<string, unknown> = {};
|
|
34
|
+
|
|
35
|
+
for (const [key, parserOrLiteral] of Object.entries(parsers)) {
|
|
36
|
+
let value: unknown;
|
|
37
|
+
|
|
38
|
+
if (typeof parserOrLiteral === 'function') {
|
|
39
|
+
// It's a parser - execute it
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
value = await (parserOrLiteral as Parser<unknown, any>)(parserContext);
|
|
42
|
+
} else {
|
|
43
|
+
// It's a literal - use directly
|
|
44
|
+
value = parserOrLiteral;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!key.startsWith('_')) {
|
|
48
|
+
result[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return result as ObjectParserOutput<Parsers>;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
setParserName(
|
|
56
|
+
objectParser,
|
|
57
|
+
'{' + Object.keys(parsers).map(k => {
|
|
58
|
+
const v = parsers[k];
|
|
59
|
+
if (typeof v === 'function') {
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
61
|
+
return k.startsWith('_') ? k : getParserName(v as Parser<unknown, any>, k);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `${k}: ${JSON.stringify(v)}`;
|
|
65
|
+
}).join(', ') + '}',
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return objectParser;
|
|
69
|
+
}
|
package/src/optionalParser.ts
CHANGED
|
@@ -5,7 +5,7 @@ export const createOptionalParser = <Output, Sequence>(
|
|
|
5
5
|
childParser: Parser<Output, Sequence>,
|
|
6
6
|
): Parser<undefined | Output, Sequence> => {
|
|
7
7
|
const optionalParser: Parser<undefined | Output, Sequence> = async parserContext => {
|
|
8
|
-
|
|
8
|
+
using childParserContext = parserContext.lookahead();
|
|
9
9
|
|
|
10
10
|
try {
|
|
11
11
|
const value = await childParser(childParserContext);
|
|
@@ -17,8 +17,6 @@ export const createOptionalParser = <Output, Sequence>(
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
throw error;
|
|
20
|
-
} finally {
|
|
21
|
-
childParserContext.dispose();
|
|
22
20
|
}
|
|
23
21
|
};
|
|
24
22
|
|
package/src/parser.test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
isParserParsingJoinError,
|
|
8
8
|
normalParserErrorModule,
|
|
9
9
|
ParserError,
|
|
10
|
+
ParserParsingFailedError,
|
|
10
11
|
ParserParsingJoinError,
|
|
11
12
|
} from './parserError.js';
|
|
12
13
|
import { createTupleParser } from './tupleParser.js';
|
|
@@ -17,21 +18,23 @@ import { createArrayParser } from './arrayParser.js';
|
|
|
17
18
|
import { createElementParser } from './elementParser.js';
|
|
18
19
|
import { toAsyncIterable } from './toAsyncIterable.js';
|
|
19
20
|
import { stringFromAsyncIterable } from './stringFromAsyncIterable.js';
|
|
21
|
+
import { createLookaheadParser } from './lookaheadParser.js';
|
|
22
|
+
import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
|
|
20
23
|
|
|
21
|
-
const aUnionParser = createUnionParser
|
|
24
|
+
const aUnionParser = createUnionParser([
|
|
22
25
|
createExactSequenceNaiveParser('1'),
|
|
23
26
|
createExactSequenceNaiveParser('aa'),
|
|
24
27
|
createExactSequenceNaiveParser('AAA'),
|
|
25
28
|
]);
|
|
26
29
|
|
|
27
|
-
const abDisjunctionParser = createDisjunctionParser
|
|
30
|
+
const abDisjunctionParser = createDisjunctionParser([
|
|
28
31
|
aUnionParser,
|
|
29
32
|
createExactSequenceNaiveParser('2'),
|
|
30
33
|
createExactSequenceNaiveParser('bb'),
|
|
31
34
|
createExactSequenceNaiveParser('BBB'),
|
|
32
35
|
]);
|
|
33
36
|
|
|
34
|
-
const abcUnionParser = createUnionParser
|
|
37
|
+
const abcUnionParser = createUnionParser([
|
|
35
38
|
abDisjunctionParser,
|
|
36
39
|
createExactSequenceNaiveParser('final_3'),
|
|
37
40
|
createExactSequenceNaiveParser('final_cc'),
|
|
@@ -39,7 +42,7 @@ const abcUnionParser = createUnionParser<string, string>([
|
|
|
39
42
|
]);
|
|
40
43
|
|
|
41
44
|
const sampleParser = promiseCompose(
|
|
42
|
-
createTupleParser
|
|
45
|
+
createTupleParser([
|
|
43
46
|
aUnionParser,
|
|
44
47
|
abDisjunctionParser,
|
|
45
48
|
abcUnionParser,
|
|
@@ -332,6 +335,8 @@ test('runParserWithRemainingInput with remaining input', async t => {
|
|
|
332
335
|
output,
|
|
333
336
|
remainingInput,
|
|
334
337
|
position,
|
|
338
|
+
furthestReadPosition,
|
|
339
|
+
furthestPeekedPosition,
|
|
335
340
|
...resultRest
|
|
336
341
|
} = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
|
|
337
342
|
|
|
@@ -339,6 +344,8 @@ test('runParserWithRemainingInput with remaining input', async t => {
|
|
|
339
344
|
t.is(output, 'foo');
|
|
340
345
|
t.is(await stringFromAsyncIterable(remainingInput!), 'bar');
|
|
341
346
|
t.is(position, 3);
|
|
347
|
+
t.is(furthestReadPosition, 3);
|
|
348
|
+
t.is(furthestPeekedPosition, 3);
|
|
342
349
|
});
|
|
343
350
|
|
|
344
351
|
test('runParserWithRemainingInput without remaining input', async t => {
|
|
@@ -348,3 +355,143 @@ test('runParserWithRemainingInput without remaining input', async t => {
|
|
|
348
355
|
t.is(output, 'foo');
|
|
349
356
|
t.is(remainingInput, undefined);
|
|
350
357
|
});
|
|
358
|
+
|
|
359
|
+
test('furthestReadPosition equals position when no backtracking', async t => {
|
|
360
|
+
const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
|
|
361
|
+
const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
|
|
362
|
+
|
|
363
|
+
t.is(result.position, 3);
|
|
364
|
+
t.is(result.furthestReadPosition, 3);
|
|
365
|
+
t.is(result.furthestPeekedPosition, 3);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
test('furthestReadPosition tracks lookahead that succeeded', async t => {
|
|
369
|
+
// Parser: lookahead('foo') followed by 'foobar'
|
|
370
|
+
// The lookahead parses 'foo' (position 3) but doesn't consume it
|
|
371
|
+
// Then 'foobar' is parsed (position 6)
|
|
372
|
+
const parser = createTupleParser([
|
|
373
|
+
createLookaheadParser(createExactSequenceNaiveParser('foo')),
|
|
374
|
+
createExactSequenceNaiveParser('foobar'),
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
|
|
378
|
+
|
|
379
|
+
t.is(result.position, 6);
|
|
380
|
+
t.is(result.furthestReadPosition, 6);
|
|
381
|
+
t.is(result.furthestPeekedPosition, 6);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('furthestReadPosition tracks failed lookahead with backtracking', async t => {
|
|
385
|
+
// Parser: try 'foobar' OR 'foo'
|
|
386
|
+
// First tries 'foobar', reads 'f','o','o','q' (position 4) then fails because 'q' != 'b'
|
|
387
|
+
// Backtracks and tries 'foo', succeeds at position 3
|
|
388
|
+
// furthestReadPosition should be 4 (from the failed 'foobar' attempt that read up to 'q')
|
|
389
|
+
const parser = createDisjunctionParser([
|
|
390
|
+
createExactSequenceNaiveParser('foobar'),
|
|
391
|
+
createExactSequenceNaiveParser('foo'),
|
|
392
|
+
]);
|
|
393
|
+
|
|
394
|
+
const result = await runParserWithRemainingInput(parser, 'fooqux', stringParserInputCompanion);
|
|
395
|
+
|
|
396
|
+
t.is(result.output, 'foo');
|
|
397
|
+
t.is(result.position, 3);
|
|
398
|
+
t.is(result.furthestReadPosition, 4);
|
|
399
|
+
t.is(result.furthestPeekedPosition, 3);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test('furthestReadPosition exceeds position after backtracking from longer match', async t => {
|
|
403
|
+
// Parser: try 'foobarqux' OR 'foo'
|
|
404
|
+
// First tries 'foobarqux', reads up to position 6 ('foobar'), then fails
|
|
405
|
+
// Backtracks and tries 'foo', succeeds at position 3
|
|
406
|
+
// furthestReadPosition should be 6 (from the failed 'foobarqux' attempt)
|
|
407
|
+
const parser = createDisjunctionParser([
|
|
408
|
+
createExactSequenceNaiveParser('foobarqux'),
|
|
409
|
+
createExactSequenceNaiveParser('foo'),
|
|
410
|
+
]);
|
|
411
|
+
|
|
412
|
+
const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
|
|
413
|
+
|
|
414
|
+
t.is(result.output, 'foo');
|
|
415
|
+
t.is(result.position, 3);
|
|
416
|
+
t.is(result.furthestReadPosition, 6);
|
|
417
|
+
t.is(result.furthestPeekedPosition, 6);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
test('furthestPeekedPosition differs from furthestReadPosition with lookahead', async t => {
|
|
421
|
+
// Parser: lookahead('foobar') then 'foo'
|
|
422
|
+
// The lookahead parses 'foobar':
|
|
423
|
+
// - Each read() calls peek(0) at positions 0,1,2,3,4,5 then skip(1) advancing to 1,2,3,4,5,6
|
|
424
|
+
// - This updates furthestReadPosition to 6 and furthestPeekedPosition to 5
|
|
425
|
+
// Then 'foo' is parsed from position 0, position becomes 3
|
|
426
|
+
// furthestReadPosition=6 (from lookahead's skip calls)
|
|
427
|
+
// furthestPeekedPosition=5 (from lookahead's peek calls at positions 0-5)
|
|
428
|
+
const parser = createTupleParser([
|
|
429
|
+
createLookaheadParser(createExactSequenceNaiveParser('foobar')),
|
|
430
|
+
createExactSequenceNaiveParser('foo'),
|
|
431
|
+
]);
|
|
432
|
+
|
|
433
|
+
const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
|
|
434
|
+
|
|
435
|
+
t.is(result.output[1], 'foo');
|
|
436
|
+
t.is(result.position, 3);
|
|
437
|
+
t.is(result.furthestReadPosition, 6);
|
|
438
|
+
t.is(result.furthestPeekedPosition, 5);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
test('error has furthestReadPosition after backtracking', async t => {
|
|
442
|
+
// Parser: try 'foobarqux' OR 'foobaz'
|
|
443
|
+
// Input: 'foobar'
|
|
444
|
+
// First tries 'foobarqux', reads up to position 6 ('foobar'), then fails (no 'qux')
|
|
445
|
+
// Then tries 'foobaz', reads up to position 4 ('foob'), then fails ('b' != 'z')
|
|
446
|
+
// Both fail, error at position 0, but furthestReadPosition should be 6
|
|
447
|
+
const parser = createDisjunctionParser([
|
|
448
|
+
createExactSequenceNaiveParser('foobarqux'),
|
|
449
|
+
createExactSequenceNaiveParser('foobaz'),
|
|
450
|
+
]);
|
|
451
|
+
|
|
452
|
+
const error = await t.throwsAsync(
|
|
453
|
+
runParser(parser, 'foobar', stringParserInputCompanion, { errorStack: true }),
|
|
454
|
+
) as ParserParsingFailedError;
|
|
455
|
+
|
|
456
|
+
t.is(error.position, 0);
|
|
457
|
+
t.is(error.furthestReadPosition, 6);
|
|
458
|
+
t.is(error.furthestPeekedPosition, 6);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('error from negative lookahead has furthestReadPosition from lookahead content', async t => {
|
|
462
|
+
// Parser: negativeLookahead('foobar') then 'foo'
|
|
463
|
+
// Input: 'foobar'
|
|
464
|
+
// Negative lookahead tries 'foobar', succeeds (reads to position 6)
|
|
465
|
+
// Since lookahead succeeded, negative lookahead fails
|
|
466
|
+
// Error position is 0 (where negative lookahead started), but furthestReadPosition is 6
|
|
467
|
+
const parser = createTupleParser([
|
|
468
|
+
createNegativeLookaheadParser(createExactSequenceNaiveParser('foobar')),
|
|
469
|
+
createExactSequenceNaiveParser('foo'),
|
|
470
|
+
]);
|
|
471
|
+
|
|
472
|
+
const error = await t.throwsAsync(
|
|
473
|
+
runParser(parser, 'foobar', stringParserInputCompanion, { errorStack: true }),
|
|
474
|
+
{
|
|
475
|
+
name: 'ParserParsingInvariantError',
|
|
476
|
+
},
|
|
477
|
+
) as ParserParsingFailedError;
|
|
478
|
+
|
|
479
|
+
t.is(error.position, 0);
|
|
480
|
+
t.is(error.furthestReadPosition, 6);
|
|
481
|
+
t.is(error.furthestPeekedPosition, 5);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test('furthestReadPosition on ParserUnexpectedRemainingInputError', async t => {
|
|
485
|
+
const parser: Parser<string, string> = createExactSequenceNaiveParser('foo');
|
|
486
|
+
|
|
487
|
+
const error = await t.throwsAsync(
|
|
488
|
+
runParser(parser, 'foobar', stringParserInputCompanion),
|
|
489
|
+
{
|
|
490
|
+
name: 'ParserUnexpectedRemainingInputError',
|
|
491
|
+
},
|
|
492
|
+
) as ParserParsingFailedError;
|
|
493
|
+
|
|
494
|
+
t.is(error.position, 3);
|
|
495
|
+
t.is(error.furthestReadPosition, 3);
|
|
496
|
+
t.is(error.furthestPeekedPosition, 3);
|
|
497
|
+
});
|
package/src/parser.ts
CHANGED
|
@@ -16,6 +16,12 @@ export type Parser<
|
|
|
16
16
|
Element = DeriveSequenceElement<Sequence>,
|
|
17
17
|
> = (parserContext: ParserContext<Sequence, Element>) => Output | Promise<Output>;
|
|
18
18
|
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
export type ParserOutput<P> = P extends Parser<infer O, any, any> ? O : never;
|
|
21
|
+
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
export type ParserSequence<P> = P extends Parser<any, infer S, any> ? S : never;
|
|
24
|
+
|
|
19
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
26
|
export function getParserName(parser: Parser<any, any, any>, default_ = 'anonymous'): string {
|
|
21
27
|
return parser.name || default_;
|
|
@@ -69,6 +75,8 @@ export type RunParserWithRemainingInputResult<
|
|
|
69
75
|
> = {
|
|
70
76
|
output: Output;
|
|
71
77
|
position: number;
|
|
78
|
+
furthestReadPosition: number;
|
|
79
|
+
furthestPeekedPosition: number;
|
|
72
80
|
remainingInput: undefined | AsyncIterable<Sequence>;
|
|
73
81
|
};
|
|
74
82
|
|
|
@@ -195,6 +203,8 @@ export async function runParserWithRemainingInput<
|
|
|
195
203
|
return {
|
|
196
204
|
output,
|
|
197
205
|
position: parserContext.position,
|
|
206
|
+
furthestReadPosition: inputReader.furthestReadPosition,
|
|
207
|
+
furthestPeekedPosition: inputReader.furthestPeekedPosition,
|
|
198
208
|
remainingInput,
|
|
199
209
|
};
|
|
200
210
|
});
|
|
@@ -222,7 +232,7 @@ export async function runParser<
|
|
|
222
232
|
const inputReaderState = inputReader.toInputReaderState();
|
|
223
233
|
|
|
224
234
|
if (!inputReaderStateCompanion.isDone(inputReaderState)) {
|
|
225
|
-
throw new normalParserErrorModule.ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position);
|
|
235
|
+
throw new normalParserErrorModule.ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position, inputReader.furthestReadPosition, inputReader.furthestPeekedPosition);
|
|
226
236
|
}
|
|
227
237
|
|
|
228
238
|
return output;
|
|
@@ -6,15 +6,13 @@ export const createParserConsumedSequenceParser = <Output, Sequence>(
|
|
|
6
6
|
): Parser<[Output, Sequence], Sequence> => {
|
|
7
7
|
const parserConsumedSequenceParser: Parser<[Output, Sequence], Sequence> = async parserContext => {
|
|
8
8
|
const initialPosition = parserContext.position;
|
|
9
|
-
const childParserContext = parserContext.lookahead();
|
|
10
9
|
|
|
11
10
|
let value: Output;
|
|
12
11
|
let consumedLength: number;
|
|
13
|
-
|
|
12
|
+
{
|
|
13
|
+
using childParserContext = parserContext.lookahead();
|
|
14
14
|
value = await childParser(childParserContext);
|
|
15
15
|
consumedLength = childParserContext.position - initialPosition;
|
|
16
|
-
} finally {
|
|
17
|
-
childParserContext.dispose();
|
|
18
16
|
}
|
|
19
17
|
|
|
20
18
|
const consumedSequenceParser = createFixedLengthSequenceParser<Sequence>(consumedLength);
|