@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.
Files changed (262) hide show
  1. package/.claude/settings.local.json +24 -0
  2. package/.github/workflows/main.yml +1 -0
  3. package/build/androidPackageParser.js +30 -32
  4. package/build/arbitraryDalvikBytecode.d.ts +3 -3
  5. package/build/arbitraryDalvikBytecode.js +33 -27
  6. package/build/arbitraryDalvikExecutable.js +55 -17
  7. package/build/arbitraryJava.d.ts +31 -0
  8. package/build/arbitraryJava.js +532 -0
  9. package/build/arbitraryJavaScript.d.ts +3 -0
  10. package/build/arbitraryJavaScript.js +263 -0
  11. package/build/arbitraryJavascript.d.ts +3 -0
  12. package/build/arbitraryJavascript.js +263 -0
  13. package/build/arbitraryZig.d.ts +3 -0
  14. package/build/arbitraryZig.js +240 -0
  15. package/build/arbitraryZipStream.d.ts +1 -1
  16. package/build/arrayParser.js +72 -13
  17. package/build/backsmali.d.ts +4 -3
  18. package/build/backsmali.js +26 -6
  19. package/build/bash.d.ts +89 -0
  20. package/build/bash.js +1 -0
  21. package/build/bashParser.d.ts +6 -0
  22. package/build/bashParser.js +335 -0
  23. package/build/bashParser.test.d.ts +1 -0
  24. package/build/bashParser.test.js +343 -0
  25. package/build/bashParserEdgeCases.test.d.ts +1 -0
  26. package/build/bashParserEdgeCases.test.js +117 -0
  27. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  28. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  29. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  30. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  31. package/build/dalvikBytecodeParser.d.ts +60 -31
  32. package/build/dalvikBytecodeParser.js +92 -35
  33. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  34. package/build/dalvikBytecodeParser.test-d.js +268 -0
  35. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  36. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  37. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  38. package/build/dalvikBytecodeUnparser.js +23 -23
  39. package/build/dalvikBytecodeUnparser.test.js +7 -7
  40. package/build/dalvikExecutable.d.ts +3 -3
  41. package/build/dalvikExecutable.test-d.d.ts +1 -0
  42. package/build/dalvikExecutable.test-d.js +59 -0
  43. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  44. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  45. package/build/dalvikExecutableParser.d.ts +2 -1
  46. package/build/dalvikExecutableParser.js +96 -77
  47. package/build/dalvikExecutableParser.test.js +24 -3
  48. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  49. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  51. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  52. package/build/dalvikExecutableUnparser.d.ts +2 -2
  53. package/build/dalvikExecutableUnparser.test.js +2 -1
  54. package/build/disjunctionParser.d.ts +5 -3
  55. package/build/disjunctionParser.js +79 -17
  56. package/build/disjunctionParser.test-d.d.ts +1 -0
  57. package/build/disjunctionParser.test-d.js +72 -0
  58. package/build/elementSwitchParser.d.ts +4 -0
  59. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  60. package/build/elementSwitchParser.test-d.d.ts +1 -0
  61. package/build/elementSwitchParser.test-d.js +44 -0
  62. package/build/exactSequenceParser.d.ts +4 -2
  63. package/build/exactSequenceParser.test-d.d.ts +1 -0
  64. package/build/exactSequenceParser.test-d.js +36 -0
  65. package/build/fetchCid.js +2 -66
  66. package/build/index.d.ts +25 -2
  67. package/build/index.js +23 -1
  68. package/build/index.test.js +16 -1
  69. package/build/inputReader.d.ts +10 -0
  70. package/build/inputReader.js +36 -0
  71. package/build/java.d.ts +502 -0
  72. package/build/java.js +2 -0
  73. package/build/javaKeyStoreParser.js +14 -17
  74. package/build/javaParser.d.ts +51 -0
  75. package/build/javaParser.js +1538 -0
  76. package/build/javaParser.test.d.ts +1 -0
  77. package/build/javaParser.test.js +1287 -0
  78. package/build/javaScript.d.ts +35 -0
  79. package/build/javaScript.js +1 -0
  80. package/build/javaScriptParser.d.ts +9 -0
  81. package/build/javaScriptParser.js +34 -0
  82. package/build/javaScriptUnparser.d.ts +3 -0
  83. package/build/javaScriptUnparser.js +4 -0
  84. package/build/javaScriptUnparser.test.d.ts +1 -0
  85. package/build/javaScriptUnparser.test.js +24 -0
  86. package/build/javaUnparser.d.ts +2 -0
  87. package/build/javaUnparser.js +519 -0
  88. package/build/javaUnparser.test.d.ts +1 -0
  89. package/build/javaUnparser.test.js +24 -0
  90. package/build/javascript.d.ts +35 -0
  91. package/build/javascript.js +1 -0
  92. package/build/javascriptParser.d.ts +9 -0
  93. package/build/javascriptParser.js +34 -0
  94. package/build/javascriptUnparser.d.ts +3 -0
  95. package/build/javascriptUnparser.js +4 -0
  96. package/build/javascriptUnparser.test.d.ts +1 -0
  97. package/build/javascriptUnparser.test.js +24 -0
  98. package/build/jsonParser.js +2 -12
  99. package/build/lazyMessageError.d.ts +3 -0
  100. package/build/lookaheadParser.js +60 -3
  101. package/build/negativeLookaheadParser.js +70 -11
  102. package/build/nonEmptyArrayParser.js +72 -13
  103. package/build/objectParser.d.ts +12 -0
  104. package/build/objectParser.js +31 -0
  105. package/build/objectParser.test-d.d.ts +1 -0
  106. package/build/objectParser.test-d.js +112 -0
  107. package/build/objectParser.test.d.ts +1 -0
  108. package/build/objectParser.test.js +55 -0
  109. package/build/optionalParser.js +69 -10
  110. package/build/parser.d.ts +4 -0
  111. package/build/parser.js +3 -1
  112. package/build/parser.test.js +114 -1
  113. package/build/parserConsumedSequenceParser.js +66 -7
  114. package/build/parserContext.d.ts +6 -0
  115. package/build/parserContext.js +20 -11
  116. package/build/parserError.d.ts +119 -27
  117. package/build/parserError.js +16 -8
  118. package/build/regexpParser.d.ts +2 -0
  119. package/build/regexpParser.js +101 -0
  120. package/build/regexpParser.test.d.ts +1 -0
  121. package/build/regexpParser.test.js +114 -0
  122. package/build/regularExpression.d.ts +63 -0
  123. package/build/regularExpression.js +1 -0
  124. package/build/regularExpressionParser.d.ts +3 -0
  125. package/build/regularExpressionParser.js +600 -0
  126. package/build/regularExpressionParser.test.d.ts +1 -0
  127. package/build/regularExpressionParser.test.js +89 -0
  128. package/build/separatedArrayParser.js +73 -14
  129. package/build/separatedNonEmptyArrayParser.js +73 -14
  130. package/build/sliceBoundedParser.js +62 -5
  131. package/build/smaliParser.d.ts +7 -7
  132. package/build/smaliParser.js +185 -268
  133. package/build/smaliParser.test.js +58 -0
  134. package/build/stringEscapes.d.ts +5 -0
  135. package/build/stringEscapes.js +244 -0
  136. package/build/symbolicExpression.d.ts +29 -0
  137. package/build/symbolicExpression.js +1 -0
  138. package/build/symbolicExpressionParser.d.ts +4 -0
  139. package/build/symbolicExpressionParser.js +123 -0
  140. package/build/symbolicExpressionParser.test.d.ts +1 -0
  141. package/build/symbolicExpressionParser.test.js +289 -0
  142. package/build/terminatedArrayParser.js +113 -38
  143. package/build/terminatedArrayParser.test.js +4 -2
  144. package/build/tupleParser.d.ts +7 -15
  145. package/build/tupleParser.js +1 -0
  146. package/build/unionParser.d.ts +5 -3
  147. package/build/unionParser.js +7 -2
  148. package/build/unionParser.test-d.d.ts +1 -0
  149. package/build/unionParser.test-d.js +72 -0
  150. package/build/unionParser.test.js +10 -11
  151. package/build/zig.d.ts +280 -0
  152. package/build/zig.js +2 -0
  153. package/build/zigParser.d.ts +3 -0
  154. package/build/zigParser.js +1119 -0
  155. package/build/zigParser.test.d.ts +1 -0
  156. package/build/zigParser.test.js +1590 -0
  157. package/build/zigUnparser.d.ts +2 -0
  158. package/build/zigUnparser.js +460 -0
  159. package/build/zigUnparser.test.d.ts +1 -0
  160. package/build/zigUnparser.test.js +24 -0
  161. package/build/zipParser.js +19 -32
  162. package/build/zipUnparser.js +19 -7
  163. package/build/zipUnparser.test.js +1 -1
  164. package/node_modules-@types/s-expression/index.d.ts +5 -0
  165. package/package.json +25 -6
  166. package/src/androidPackageParser.ts +33 -60
  167. package/src/arbitraryDalvikBytecode.ts +39 -31
  168. package/src/arbitraryDalvikExecutable.ts +65 -20
  169. package/src/arbitraryJava.ts +804 -0
  170. package/src/arbitraryJavaScript.ts +410 -0
  171. package/src/arbitraryZig.ts +380 -0
  172. package/src/arrayParser.ts +1 -3
  173. package/src/backsmali.ts +35 -4
  174. package/src/bash.ts +127 -0
  175. package/src/bashParser.test.ts +590 -0
  176. package/src/bashParser.ts +498 -0
  177. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  178. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  179. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  180. package/src/dalvikBytecodeParser.ts +194 -69
  181. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  182. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  183. package/src/dalvikBytecodeUnparser.ts +31 -30
  184. package/src/dalvikExecutable.test-d.ts +132 -0
  185. package/src/dalvikExecutable.ts +3 -3
  186. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  187. package/src/dalvikExecutableParser.test.ts +37 -3
  188. package/src/dalvikExecutableParser.test.ts.md +163 -2
  189. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  190. package/src/dalvikExecutableParser.ts +121 -139
  191. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  192. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  193. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  194. package/src/dalvikExecutableUnparser.test.ts +3 -2
  195. package/src/dalvikExecutableUnparser.ts +4 -4
  196. package/src/disjunctionParser.test-d.ts +105 -0
  197. package/src/disjunctionParser.ts +18 -15
  198. package/src/elementSwitchParser.test-d.ts +74 -0
  199. package/src/elementSwitchParser.ts +51 -0
  200. package/src/exactSequenceParser.test-d.ts +43 -0
  201. package/src/exactSequenceParser.ts +13 -8
  202. package/src/fetchCid.ts +2 -76
  203. package/src/index.test.ts +22 -1
  204. package/src/index.ts +119 -2
  205. package/src/inputReader.ts +53 -0
  206. package/src/java.ts +708 -0
  207. package/src/javaKeyStoreParser.ts +18 -32
  208. package/src/javaParser.test.ts +1592 -0
  209. package/src/javaParser.ts +2640 -0
  210. package/src/javaScript.ts +36 -0
  211. package/src/javaScriptParser.ts +57 -0
  212. package/src/javaScriptUnparser.test.ts +37 -0
  213. package/src/javaScriptUnparser.ts +7 -0
  214. package/src/javaUnparser.test.ts +37 -0
  215. package/src/javaUnparser.ts +640 -0
  216. package/src/jsonParser.ts +6 -27
  217. package/src/lookaheadParser.ts +2 -6
  218. package/src/negativeLookaheadParser.ts +1 -3
  219. package/src/nonEmptyArrayParser.ts +1 -3
  220. package/src/objectParser.test-d.ts +152 -0
  221. package/src/objectParser.test.ts +71 -0
  222. package/src/objectParser.ts +69 -0
  223. package/src/optionalParser.ts +1 -3
  224. package/src/parser.test.ts +151 -4
  225. package/src/parser.ts +11 -1
  226. package/src/parserConsumedSequenceParser.ts +2 -4
  227. package/src/parserContext.ts +26 -11
  228. package/src/parserError.ts +17 -3
  229. package/src/regexpParser.test.ts +264 -0
  230. package/src/regexpParser.ts +126 -0
  231. package/src/regularExpression.ts +24 -0
  232. package/src/regularExpressionParser.test.ts +102 -0
  233. package/src/regularExpressionParser.ts +920 -0
  234. package/src/separatedArrayParser.ts +1 -3
  235. package/src/separatedNonEmptyArrayParser.ts +1 -3
  236. package/src/sliceBoundedParser.test.ts +2 -2
  237. package/src/sliceBoundedParser.ts +15 -19
  238. package/src/smaliParser.test.ts +64 -0
  239. package/src/smaliParser.test.ts.md +12 -12
  240. package/src/smaliParser.test.ts.snap +0 -0
  241. package/src/smaliParser.ts +246 -534
  242. package/src/stringEscapes.ts +253 -0
  243. package/src/symbolicExpression.ts +17 -0
  244. package/src/symbolicExpressionParser.test.ts +466 -0
  245. package/src/symbolicExpressionParser.ts +190 -0
  246. package/src/terminatedArrayParser.test.ts +9 -6
  247. package/src/terminatedArrayParser.ts +25 -29
  248. package/src/tupleParser.ts +21 -18
  249. package/src/unionParser.test-d.ts +105 -0
  250. package/src/unionParser.test.ts +18 -17
  251. package/src/unionParser.ts +28 -16
  252. package/src/zig.ts +411 -0
  253. package/src/zigParser.test.ts +1693 -0
  254. package/src/zigParser.ts +1745 -0
  255. package/src/zigUnparser.test.ts +37 -0
  256. package/src/zigUnparser.ts +615 -0
  257. package/src/zipParser.ts +20 -56
  258. package/src/zipUnparser.test.ts +1 -1
  259. package/src/zipUnparser.ts +22 -7
  260. package/tsconfig.json +2 -2
  261. package/build/exactElementSwitchParser.d.ts +0 -3
  262. package/src/exactElementSwitchParser.ts +0 -41
@@ -0,0 +1,55 @@
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
+ // Type tests are in objectParser.test-d.ts (using tsd)
8
+ test('parses object with parsers only', async (t) => {
9
+ const parser = createObjectParser({
10
+ first: createFixedLengthSequenceParser(3),
11
+ second: createFixedLengthSequenceParser(3),
12
+ });
13
+ const output = await runParser(parser, 'foobar', stringParserInputCompanion);
14
+ t.deepEqual(output, { first: 'foo', second: 'bar' });
15
+ });
16
+ test('parses object with literals', async (t) => {
17
+ const parser = createObjectParser({
18
+ type: 'block',
19
+ value: createFixedLengthSequenceParser(3),
20
+ });
21
+ const output = await runParser(parser, 'foo', stringParserInputCompanion);
22
+ t.deepEqual(output, { type: 'block', value: 'foo' });
23
+ });
24
+ test('excludes underscore-prefixed keys from result but runs parsers', async (t) => {
25
+ const parser = createObjectParser({
26
+ first: createFixedLengthSequenceParser(3),
27
+ _separator: createExactSequenceParser(':'),
28
+ second: createFixedLengthSequenceParser(3),
29
+ });
30
+ const output = await runParser(parser, 'foo:bar', stringParserInputCompanion);
31
+ t.deepEqual(output, { first: 'foo', second: 'bar' });
32
+ t.false('_separator' in output);
33
+ });
34
+ test('preserves property order', async (t) => {
35
+ const parser = createObjectParser({
36
+ c: createFixedLengthSequenceParser(1),
37
+ a: createFixedLengthSequenceParser(1),
38
+ b: createFixedLengthSequenceParser(1),
39
+ });
40
+ const output = await runParser(parser, 'xyz', stringParserInputCompanion);
41
+ t.deepEqual(Object.keys(output), ['c', 'a', 'b']);
42
+ t.deepEqual(output, { c: 'x', a: 'y', b: 'z' });
43
+ });
44
+ test('mixed parsers and literals with underscore keys', async (t) => {
45
+ const parser = createObjectParser({
46
+ type: 'assignment',
47
+ _open: createExactSequenceParser('('),
48
+ name: createFixedLengthSequenceParser(1),
49
+ _eq: createExactSequenceParser('='),
50
+ value: createFixedLengthSequenceParser(1),
51
+ _close: createExactSequenceParser(')'),
52
+ });
53
+ const output = await runParser(parser, '(x=5)', stringParserInputCompanion);
54
+ t.deepEqual(output, { type: 'assignment', name: 'x', value: '5' });
55
+ });
@@ -1,21 +1,80 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { getParserName, setParserName } from './parser.js';
2
54
  import { isParserParsingFailedError } from './parserError.js';
3
55
  export const createOptionalParser = (childParser) => {
4
56
  const optionalParser = async (parserContext) => {
5
- const childParserContext = parserContext.lookahead();
57
+ const env_1 = { stack: [], error: void 0, hasError: false };
6
58
  try {
7
- const value = await childParser(childParserContext);
8
- childParserContext.unlookahead();
9
- return value;
10
- }
11
- catch (error) {
12
- if (isParserParsingFailedError(error)) {
13
- return undefined;
59
+ const childParserContext = __addDisposableResource(env_1, parserContext.lookahead(), false);
60
+ try {
61
+ const value = await childParser(childParserContext);
62
+ childParserContext.unlookahead();
63
+ return value;
14
64
  }
15
- throw error;
65
+ catch (error) {
66
+ if (isParserParsingFailedError(error)) {
67
+ return undefined;
68
+ }
69
+ throw error;
70
+ }
71
+ }
72
+ catch (e_1) {
73
+ env_1.error = e_1;
74
+ env_1.hasError = true;
16
75
  }
17
76
  finally {
18
- childParserContext.dispose();
77
+ __disposeResources(env_1);
19
78
  }
20
79
  };
21
80
  setParserName(optionalParser, getParserName(childParser, 'anonymousOptionalChild') + '?');
package/build/parser.d.ts CHANGED
@@ -3,6 +3,8 @@ import { type ParserInputCompanion } from './parserInputCompanion.js';
3
3
  import { type ParserContext } from './parserContext.js';
4
4
  import { type DeriveSequenceElement } from './sequence.js';
5
5
  export type Parser<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = (parserContext: ParserContext<Sequence, Element>) => Output | Promise<Output>;
6
+ export type ParserOutput<P> = P extends Parser<infer O, any, any> ? O : never;
7
+ export type ParserSequence<P> = P extends Parser<any, infer S, any> ? S : never;
6
8
  export declare function getParserName(parser: Parser<any, any, any>, default_?: string): string;
7
9
  export declare function setParserName<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>, name: string): Parser<Output, Sequence, Element>;
8
10
  export declare function cloneParser<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>): Parser<Output, Sequence, Element>;
@@ -14,6 +16,8 @@ export type RunParserOptions<Output, Sequence, Element = DeriveSequenceElement<S
14
16
  export type RunParserWithRemainingInputResult<Output, Sequence, Element = DeriveSequenceElement<Sequence>> = {
15
17
  output: Output;
16
18
  position: number;
19
+ furthestReadPosition: number;
20
+ furthestPeekedPosition: number;
17
21
  remainingInput: undefined | AsyncIterable<Sequence>;
18
22
  };
19
23
  export declare function runParserWithRemainingInput<Output, Sequence, Element = DeriveSequenceElement<Sequence>>(parser: Parser<Output, Sequence, Element>, input: AsyncIterator<Sequence> | AsyncIterable<Sequence> | Iterable<Sequence> | Sequence, parserInputCompanion: ParserInputCompanion<Sequence, Element>, options?: RunParserOptions<Output, Sequence, Element>): Promise<RunParserWithRemainingInputResult<Output, Sequence, Element>>;
package/build/parser.js CHANGED
@@ -86,6 +86,8 @@ export async function runParserWithRemainingInput(parser, input, parserInputComp
86
86
  return {
87
87
  output,
88
88
  position: parserContext.position,
89
+ furthestReadPosition: inputReader.furthestReadPosition,
90
+ furthestPeekedPosition: inputReader.furthestPeekedPosition,
89
91
  remainingInput,
90
92
  };
91
93
  });
@@ -96,7 +98,7 @@ export async function runParser(parser, input, parserInputCompanion, options = {
96
98
  const output = await outputPromise;
97
99
  const inputReaderState = inputReader.toInputReaderState();
98
100
  if (!inputReaderStateCompanion.isDone(inputReaderState)) {
99
- throw new normalParserErrorModule.ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position);
101
+ throw new normalParserErrorModule.ParserUnexpectedRemainingInputError('Unexpected remaining input', 0, parserContext.position, inputReader.furthestReadPosition, inputReader.furthestPeekedPosition);
100
102
  }
101
103
  return output;
102
104
  });
@@ -12,6 +12,8 @@ import { createArrayParser } from './arrayParser.js';
12
12
  import { createElementParser } from './elementParser.js';
13
13
  import { toAsyncIterable } from './toAsyncIterable.js';
14
14
  import { stringFromAsyncIterable } from './stringFromAsyncIterable.js';
15
+ import { createLookaheadParser } from './lookaheadParser.js';
16
+ import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
15
17
  const aUnionParser = createUnionParser([
16
18
  createExactSequenceNaiveParser('1'),
17
19
  createExactSequenceNaiveParser('aa'),
@@ -228,11 +230,13 @@ test('runParser does not throw without remaining input', async (t) => {
228
230
  });
229
231
  test('runParserWithRemainingInput with remaining input', async (t) => {
230
232
  const parser = createExactSequenceNaiveParser('foo');
231
- const { output, remainingInput, position, ...resultRest } = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
233
+ const { output, remainingInput, position, furthestReadPosition, furthestPeekedPosition, ...resultRest } = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
232
234
  t.deepEqual(resultRest, {});
233
235
  t.is(output, 'foo');
234
236
  t.is(await stringFromAsyncIterable(remainingInput), 'bar');
235
237
  t.is(position, 3);
238
+ t.is(furthestReadPosition, 3);
239
+ t.is(furthestPeekedPosition, 3);
236
240
  });
237
241
  test('runParserWithRemainingInput without remaining input', async (t) => {
238
242
  const parser = createExactSequenceNaiveParser('foo');
@@ -240,3 +244,112 @@ test('runParserWithRemainingInput without remaining input', async (t) => {
240
244
  t.is(output, 'foo');
241
245
  t.is(remainingInput, undefined);
242
246
  });
247
+ test('furthestReadPosition equals position when no backtracking', async (t) => {
248
+ const parser = createExactSequenceNaiveParser('foo');
249
+ const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
250
+ t.is(result.position, 3);
251
+ t.is(result.furthestReadPosition, 3);
252
+ t.is(result.furthestPeekedPosition, 3);
253
+ });
254
+ test('furthestReadPosition tracks lookahead that succeeded', async (t) => {
255
+ // Parser: lookahead('foo') followed by 'foobar'
256
+ // The lookahead parses 'foo' (position 3) but doesn't consume it
257
+ // Then 'foobar' is parsed (position 6)
258
+ const parser = createTupleParser([
259
+ createLookaheadParser(createExactSequenceNaiveParser('foo')),
260
+ createExactSequenceNaiveParser('foobar'),
261
+ ]);
262
+ const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
263
+ t.is(result.position, 6);
264
+ t.is(result.furthestReadPosition, 6);
265
+ t.is(result.furthestPeekedPosition, 6);
266
+ });
267
+ test('furthestReadPosition tracks failed lookahead with backtracking', async (t) => {
268
+ // Parser: try 'foobar' OR 'foo'
269
+ // First tries 'foobar', reads 'f','o','o','q' (position 4) then fails because 'q' != 'b'
270
+ // Backtracks and tries 'foo', succeeds at position 3
271
+ // furthestReadPosition should be 4 (from the failed 'foobar' attempt that read up to 'q')
272
+ const parser = createDisjunctionParser([
273
+ createExactSequenceNaiveParser('foobar'),
274
+ createExactSequenceNaiveParser('foo'),
275
+ ]);
276
+ const result = await runParserWithRemainingInput(parser, 'fooqux', stringParserInputCompanion);
277
+ t.is(result.output, 'foo');
278
+ t.is(result.position, 3);
279
+ t.is(result.furthestReadPosition, 4);
280
+ t.is(result.furthestPeekedPosition, 3);
281
+ });
282
+ test('furthestReadPosition exceeds position after backtracking from longer match', async (t) => {
283
+ // Parser: try 'foobarqux' OR 'foo'
284
+ // First tries 'foobarqux', reads up to position 6 ('foobar'), then fails
285
+ // Backtracks and tries 'foo', succeeds at position 3
286
+ // furthestReadPosition should be 6 (from the failed 'foobarqux' attempt)
287
+ const parser = createDisjunctionParser([
288
+ createExactSequenceNaiveParser('foobarqux'),
289
+ createExactSequenceNaiveParser('foo'),
290
+ ]);
291
+ const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
292
+ t.is(result.output, 'foo');
293
+ t.is(result.position, 3);
294
+ t.is(result.furthestReadPosition, 6);
295
+ t.is(result.furthestPeekedPosition, 6);
296
+ });
297
+ test('furthestPeekedPosition differs from furthestReadPosition with lookahead', async (t) => {
298
+ // Parser: lookahead('foobar') then 'foo'
299
+ // The lookahead parses 'foobar':
300
+ // - Each read() calls peek(0) at positions 0,1,2,3,4,5 then skip(1) advancing to 1,2,3,4,5,6
301
+ // - This updates furthestReadPosition to 6 and furthestPeekedPosition to 5
302
+ // Then 'foo' is parsed from position 0, position becomes 3
303
+ // furthestReadPosition=6 (from lookahead's skip calls)
304
+ // furthestPeekedPosition=5 (from lookahead's peek calls at positions 0-5)
305
+ const parser = createTupleParser([
306
+ createLookaheadParser(createExactSequenceNaiveParser('foobar')),
307
+ createExactSequenceNaiveParser('foo'),
308
+ ]);
309
+ const result = await runParserWithRemainingInput(parser, 'foobar', stringParserInputCompanion);
310
+ t.is(result.output[1], 'foo');
311
+ t.is(result.position, 3);
312
+ t.is(result.furthestReadPosition, 6);
313
+ t.is(result.furthestPeekedPosition, 5);
314
+ });
315
+ test('error has furthestReadPosition after backtracking', async (t) => {
316
+ // Parser: try 'foobarqux' OR 'foobaz'
317
+ // Input: 'foobar'
318
+ // First tries 'foobarqux', reads up to position 6 ('foobar'), then fails (no 'qux')
319
+ // Then tries 'foobaz', reads up to position 4 ('foob'), then fails ('b' != 'z')
320
+ // Both fail, error at position 0, but furthestReadPosition should be 6
321
+ const parser = createDisjunctionParser([
322
+ createExactSequenceNaiveParser('foobarqux'),
323
+ createExactSequenceNaiveParser('foobaz'),
324
+ ]);
325
+ const error = await t.throwsAsync(runParser(parser, 'foobar', stringParserInputCompanion, { errorStack: true }));
326
+ t.is(error.position, 0);
327
+ t.is(error.furthestReadPosition, 6);
328
+ t.is(error.furthestPeekedPosition, 6);
329
+ });
330
+ test('error from negative lookahead has furthestReadPosition from lookahead content', async (t) => {
331
+ // Parser: negativeLookahead('foobar') then 'foo'
332
+ // Input: 'foobar'
333
+ // Negative lookahead tries 'foobar', succeeds (reads to position 6)
334
+ // Since lookahead succeeded, negative lookahead fails
335
+ // Error position is 0 (where negative lookahead started), but furthestReadPosition is 6
336
+ const parser = createTupleParser([
337
+ createNegativeLookaheadParser(createExactSequenceNaiveParser('foobar')),
338
+ createExactSequenceNaiveParser('foo'),
339
+ ]);
340
+ const error = await t.throwsAsync(runParser(parser, 'foobar', stringParserInputCompanion, { errorStack: true }), {
341
+ name: 'ParserParsingInvariantError',
342
+ });
343
+ t.is(error.position, 0);
344
+ t.is(error.furthestReadPosition, 6);
345
+ t.is(error.furthestPeekedPosition, 5);
346
+ });
347
+ test('furthestReadPosition on ParserUnexpectedRemainingInputError', async (t) => {
348
+ const parser = createExactSequenceNaiveParser('foo');
349
+ const error = await t.throwsAsync(runParser(parser, 'foobar', stringParserInputCompanion), {
350
+ name: 'ParserUnexpectedRemainingInputError',
351
+ });
352
+ t.is(error.position, 3);
353
+ t.is(error.furthestReadPosition, 3);
354
+ t.is(error.furthestPeekedPosition, 3);
355
+ });
@@ -1,17 +1,76 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
1
53
  import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
2
54
  import { getParserName, setParserName } from './parser.js';
3
55
  export const createParserConsumedSequenceParser = (childParser) => {
4
56
  const parserConsumedSequenceParser = async (parserContext) => {
5
57
  const initialPosition = parserContext.position;
6
- const childParserContext = parserContext.lookahead();
7
58
  let value;
8
59
  let consumedLength;
9
- try {
10
- value = await childParser(childParserContext);
11
- consumedLength = childParserContext.position - initialPosition;
12
- }
13
- finally {
14
- childParserContext.dispose();
60
+ {
61
+ const env_1 = { stack: [], error: void 0, hasError: false };
62
+ try {
63
+ const childParserContext = __addDisposableResource(env_1, parserContext.lookahead(), false);
64
+ value = await childParser(childParserContext);
65
+ consumedLength = childParserContext.position - initialPosition;
66
+ }
67
+ catch (e_1) {
68
+ env_1.error = e_1;
69
+ env_1.hasError = true;
70
+ }
71
+ finally {
72
+ __disposeResources(env_1);
73
+ }
15
74
  }
16
75
  const consumedSequenceParser = createFixedLengthSequenceParser(consumedLength);
17
76
  const consumedSequence = await consumedSequenceParser(parserContext);
@@ -20,6 +20,8 @@ export type ParserContext<Sequence, Element> = {
20
20
  indexOfSubsequence(sequence: Sequence, subsequence: Sequence, fromIndex?: number): number;
21
21
  equals(sequenceA: Sequence, sequenceB: Sequence): boolean;
22
22
  get position(): number;
23
+ get furthestReadPosition(): number;
24
+ get furthestPeekedPosition(): number;
23
25
  peek(offset: number): Promise<Element | undefined>;
24
26
  peekSequence(start: number, end: number): Promise<Sequence | undefined>;
25
27
  skip(offset: number): void;
@@ -28,6 +30,7 @@ export type ParserContext<Sequence, Element> = {
28
30
  lookahead(options?: LookaheadOptions): ParserContext<Sequence, Element>;
29
31
  unlookahead(): void;
30
32
  dispose(): void;
33
+ [Symbol.dispose](): void;
31
34
  invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
32
35
  invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
33
36
  };
@@ -50,6 +53,8 @@ export declare class ParserContextImplementation<Sequence, Element> implements P
50
53
  indexOfSubsequence(sequence: Sequence, subsequence: Sequence, fromIndex?: number): number;
51
54
  equals(sequenceA: Sequence, sequenceB: Sequence): boolean;
52
55
  get position(): number;
56
+ get furthestReadPosition(): number;
57
+ get furthestPeekedPosition(): number;
53
58
  peek(offset: number): Promise<Element | undefined>;
54
59
  peekSequence(start: number, end: number): Promise<Sequence | undefined>;
55
60
  skip(offset: number): void;
@@ -58,6 +63,7 @@ export declare class ParserContextImplementation<Sequence, Element> implements P
58
63
  lookahead(options?: LookaheadOptions): ParserContext<Sequence, Element>;
59
64
  unlookahead(): void;
60
65
  dispose(): void;
66
+ [Symbol.dispose](): void;
61
67
  invariant<T>(value: T, format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
62
68
  invariantJoin<T>(value: T, childErrors: ParserParsingFailedError[], format: ValueOrAccessor<string | string[]>, ...formatArguments: unknown[]): Exclude<T, Falsy>;
63
69
  }
@@ -57,6 +57,12 @@ export class ParserContextImplementation {
57
57
  get position() {
58
58
  return this._inputReader.position;
59
59
  }
60
+ get furthestReadPosition() {
61
+ return this._inputReader.furthestReadPosition;
62
+ }
63
+ get furthestPeekedPosition() {
64
+ return this._inputReader.furthestPeekedPosition;
65
+ }
60
66
  async peek(offset) {
61
67
  if (this._options.sliceEnd !== undefined
62
68
  && (this.position + offset) >= this._options.sliceEnd) {
@@ -81,7 +87,7 @@ export class ParserContextImplementation {
81
87
  async read(offset) {
82
88
  const element = await this.peek(offset);
83
89
  if (element === undefined) {
84
- throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position);
90
+ throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position, this._inputReader.furthestReadPosition, this._inputReader.furthestPeekedPosition);
85
91
  }
86
92
  this.skip(offset + 1);
87
93
  return element;
@@ -89,7 +95,7 @@ export class ParserContextImplementation {
89
95
  async readSequence(start, end) {
90
96
  const sequence = await this.peekSequence(start, end);
91
97
  if (sequence === undefined) {
92
- throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position);
98
+ throw new this._options.errorsModule.ParserUnexpectedEndOfInputError('', this._depth, this.position, this._inputReader.furthestReadPosition, this._inputReader.furthestPeekedPosition);
93
99
  }
94
100
  this.skip(end);
95
101
  return sequence;
@@ -144,10 +150,13 @@ export class ParserContextImplementation {
144
150
  parentParserContext._exclusiveChildParserContext = undefined;
145
151
  this._parentParserContext = undefined;
146
152
  }
153
+ [Symbol.dispose]() {
154
+ this.dispose();
155
+ }
147
156
  invariant(value, format, ...formatArguments) {
148
157
  const parserContext = this;
149
158
  return customInvariant(function (lazyMessage) {
150
- return new parserContext._options.errorsModule.ParserParsingInvariantError(lazyMessage, parserContext._depth, parserContext.position);
159
+ return new parserContext._options.errorsModule.ParserParsingInvariantError(lazyMessage, parserContext._depth, parserContext.position, parserContext._inputReader.furthestReadPosition, parserContext._inputReader.furthestPeekedPosition);
151
160
  }, value, format, ...formatArguments);
152
161
  }
153
162
  invariantJoin(value, childErrors, format, ...formatArguments) {
@@ -156,19 +165,19 @@ export class ParserContextImplementation {
156
165
  const parserContext = this;
157
166
  if (errorJoinMode === 'none') {
158
167
  return customInvariant(function (lazyMessage) {
159
- return new parserContext._options.errorsModule.ParserParsingJoinNoneError(lazyMessage, parserContext._depth, parserContext.position);
168
+ return new parserContext._options.errorsModule.ParserParsingJoinNoneError(lazyMessage, parserContext._depth, parserContext.position, parserContext._inputReader.furthestReadPosition, parserContext._inputReader.furthestPeekedPosition);
160
169
  }, value, format, ...formatArguments);
161
170
  }
162
171
  if (errorJoinMode === 'furthest') {
163
172
  return customInvariant(function (userLazyMessage) {
164
- let furthestPosition = 0;
173
+ let furthestChildErrorPosition = 0;
165
174
  let furthestChildErrors = [];
166
175
  for (const childError of childErrors) {
167
- if (childError.position < furthestPosition) {
176
+ if (childError.position < furthestChildErrorPosition) {
168
177
  continue;
169
178
  }
170
- if (childError.position > furthestPosition) {
171
- furthestPosition = childError.position;
179
+ if (childError.position > furthestChildErrorPosition) {
180
+ furthestChildErrorPosition = childError.position;
172
181
  furthestChildErrors = [childError];
173
182
  continue;
174
183
  }
@@ -188,7 +197,7 @@ export class ParserContextImplementation {
188
197
  }
189
198
  return furthestChildError.stack?.split('\n').map(line => ' ' + line);
190
199
  }).join('\n'),
191
- ], parserContext._depth, furthestPosition, furthestChildErrors);
200
+ ], parserContext._depth, furthestChildErrorPosition, parserContext._inputReader.furthestReadPosition, parserContext._inputReader.furthestPeekedPosition, furthestChildErrors);
192
201
  }, value, format, ...formatArguments);
193
202
  }
194
203
  if (errorJoinMode === 'deepest') {
@@ -223,7 +232,7 @@ export class ParserContextImplementation {
223
232
  }
224
233
  return deepestChildError.stack?.split('\n').map(line => ' ' + line);
225
234
  }).join('\n'),
226
- ], deepestDepth, parserContext.position, deepestChildErrors);
235
+ ], deepestDepth, parserContext.position, parserContext._inputReader.furthestReadPosition, parserContext._inputReader.furthestPeekedPosition, deepestChildErrors);
227
236
  }, value, format, ...formatArguments);
228
237
  }
229
238
  if (errorJoinMode === 'all') {
@@ -242,7 +251,7 @@ export class ParserContextImplementation {
242
251
  }
243
252
  return childError.stack?.split('\n').map(line => ' ' + line);
244
253
  }).join('\n'),
245
- ], parserContext._depth, parserContext.position, childErrors);
254
+ ], parserContext._depth, parserContext.position, parserContext._inputReader.furthestReadPosition, parserContext._inputReader.furthestPeekedPosition, childErrors);
246
255
  }, value, format, ...formatArguments);
247
256
  }
248
257
  return parserImplementationInvariant(false, 'Unsupported errorJoinMode: %s', errorJoinMode);