@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.
Files changed (304) hide show
  1. package/build/allSettledStream.js +32 -14
  2. package/build/allSettledStream.test.js +32 -0
  3. package/build/androidPackage.d.ts +39 -0
  4. package/build/androidPackageParser.d.ts +17 -0
  5. package/build/androidPackageParser.js +183 -0
  6. package/build/{apkParser.test.js → androidPackageParser.test.js} +6 -6
  7. package/build/androidPackageUnparser.d.ts +4 -0
  8. package/build/{apkUnparser.js → androidPackageUnparser.js} +23 -23
  9. package/build/androidPackageUnparser.test.js +26 -0
  10. package/build/arbitrarilySlicedAsyncInterable.d.ts +3 -1
  11. package/build/arbitrarilySlicedAsyncInterable.js +3 -3
  12. package/build/arrayParser.test.js +3 -3
  13. package/build/backsmali.d.ts +1 -0
  14. package/build/backsmali.js +22 -0
  15. package/build/bsonParser.js +6 -2
  16. package/build/customInvariant.d.ts +1 -1
  17. package/build/dalvikBytecodeParser/formatParsers.d.ts +97 -0
  18. package/build/dalvikBytecodeParser/formatParsers.js +169 -0
  19. package/build/dalvikBytecodeParser.d.ts +107 -0
  20. package/build/dalvikBytecodeParser.js +836 -0
  21. package/build/dalvikExecutable.d.ts +158 -0
  22. package/build/dalvikExecutable.js +20 -0
  23. package/build/dalvikExecutableParser/stringSyntaxParser.d.ts +4 -0
  24. package/build/dalvikExecutableParser/stringSyntaxParser.js +76 -0
  25. package/build/dalvikExecutableParser/typeParsers.d.ts +10 -0
  26. package/build/dalvikExecutableParser/typeParsers.js +34 -0
  27. package/build/dalvikExecutableParser/typedNumbers.d.ts +90 -0
  28. package/build/dalvikExecutableParser/typedNumbers.js +19 -0
  29. package/build/dalvikExecutableParser.d.ts +5 -0
  30. package/build/dalvikExecutableParser.js +1439 -0
  31. package/build/dalvikExecutableParser.test.js +70 -0
  32. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +298 -0
  33. package/build/debugLogInputParser.d.ts +4 -0
  34. package/build/debugLogInputParser.js +16 -0
  35. package/build/debugLogParser.js +14 -3
  36. package/build/disjunctionParser.d.ts +2 -1
  37. package/build/disjunctionParser.js +4 -2
  38. package/build/elementTerminatedArrayParser.d.ts +3 -0
  39. package/build/elementTerminatedArrayParser.js +18 -0
  40. package/build/elementTerminatedArrayParser.test.js +52 -0
  41. package/build/elementTerminatedSequenceArrayParser.d.ts +3 -0
  42. package/build/elementTerminatedSequenceArrayParser.js +32 -0
  43. package/build/elementTerminatedSequenceArrayParser.test.js +34 -0
  44. package/build/elementTerminatedSequenceParser.d.ts +3 -0
  45. package/build/elementTerminatedSequenceParser.js +27 -0
  46. package/build/elementTerminatedSequenceParser.test.js +34 -0
  47. package/build/exactElementParser.js +10 -5
  48. package/build/exactSequenceParser.d.ts +2 -1
  49. package/build/exactSequenceParser.js +12 -2
  50. package/build/fetchCid.d.ts +1 -0
  51. package/build/fetchCid.js +107 -0
  52. package/build/fixedLengthSequenceParser.d.ts +1 -0
  53. package/build/fixedLengthSequenceParser.js +18 -1
  54. package/build/fixedLengthSequenceParser.test.js +41 -0
  55. package/build/hasExecutable.d.ts +1 -0
  56. package/build/hasExecutable.js +8 -0
  57. package/build/highResolutionTimer.d.ts +16 -0
  58. package/build/highResolutionTimer.js +42 -0
  59. package/build/inputReader.d.ts +11 -0
  60. package/build/inputReader.js +37 -0
  61. package/build/inputReader.test.js +165 -0
  62. package/build/inputReaderState.d.ts +10 -0
  63. package/build/inputReaderState.js +16 -0
  64. package/build/inspect.d.ts +1 -0
  65. package/build/inspect.js +7 -0
  66. package/build/javaKeyStoreParser.test.js +2 -2
  67. package/build/jsonParser.d.ts +2 -0
  68. package/build/jsonParser.js +11 -14
  69. package/build/leb128Parser.d.ts +7 -0
  70. package/build/leb128Parser.js +82 -0
  71. package/build/leb128Parser.test.js +107 -0
  72. package/build/lookaheadParser.d.ts +2 -0
  73. package/build/lookaheadParser.js +14 -0
  74. package/build/negativeLookaheadParser.js +21 -15
  75. package/build/negativeLookaheadParser.test.js +30 -0
  76. package/build/nonEmptyArrayParser.d.ts +2 -0
  77. package/build/nonEmptyArrayParser.js +32 -0
  78. package/build/nonEmptyArrayParser.test.js +16 -0
  79. package/build/parser.d.ts +10 -1
  80. package/build/parser.js +66 -31
  81. package/build/parser.test.js +79 -12
  82. package/build/parserAccessorParser.js +9 -1
  83. package/build/parserConsumedSequenceParser.js +20 -15
  84. package/build/parserContext.d.ts +14 -0
  85. package/build/parserContext.js +56 -27
  86. package/build/parserContext.test.js +27 -0
  87. package/build/parserCreatorCompose.d.ts +1 -0
  88. package/build/parserCreatorCompose.js +8 -2
  89. package/build/parserError.d.ts +6 -0
  90. package/build/parserError.js +6 -6
  91. package/build/parserInputCompanion.d.ts +15 -0
  92. package/build/parserInputCompanion.js +38 -0
  93. package/build/promiseCompose.d.ts +1 -1
  94. package/build/promiseCompose.js +12 -1
  95. package/build/promiseSettled.d.ts +1 -0
  96. package/build/promiseSettled.js +4 -0
  97. package/build/separatedArrayParser.d.ts +2 -0
  98. package/build/separatedArrayParser.js +39 -0
  99. package/build/separatedArrayParser.test.d.ts +1 -0
  100. package/build/separatedArrayParser.test.js +21 -0
  101. package/build/sequenceBuffer.d.ts +10 -0
  102. package/build/sequenceBuffer.js +54 -2
  103. package/build/sequenceBuffer.test.js +57 -0
  104. package/build/sequenceTerminatedSequenceParser.d.ts +5 -0
  105. package/build/sequenceTerminatedSequenceParser.js +32 -0
  106. package/build/sequenceTerminatedSequenceParser.test.d.ts +1 -0
  107. package/build/sequenceTerminatedSequenceParser.test.js +37 -0
  108. package/build/skipParser.d.ts +1 -1
  109. package/build/skipParser.js +4 -2
  110. package/build/skipToParser.d.ts +2 -0
  111. package/build/skipToParser.js +11 -0
  112. package/build/sliceBoundedParser.d.ts +1 -1
  113. package/build/sliceBoundedParser.js +7 -2
  114. package/build/sliceBoundedParser.test.js +35 -1
  115. package/build/smali.d.ts +1 -0
  116. package/build/smali.js +17 -0
  117. package/build/smaliParser.d.ts +12 -0
  118. package/build/smaliParser.js +656 -0
  119. package/build/smaliParser.test.d.ts +1 -0
  120. package/build/smaliParser.test.js +115 -0
  121. package/build/terminatedArrayParser.d.ts +3 -1
  122. package/build/terminatedArrayParser.js +79 -2
  123. package/build/terminatedArrayParser.test.d.ts +1 -0
  124. package/build/terminatedArrayParser.test.js +131 -0
  125. package/build/toAsyncIterable.d.ts +1 -0
  126. package/build/toAsyncIterable.js +7 -0
  127. package/build/toAsyncIterator.d.ts +1 -0
  128. package/build/toAsyncIterator.js +33 -0
  129. package/build/tupleParser.d.ts +4 -0
  130. package/build/tupleParser.js +1 -5
  131. package/build/unionParser.d.ts +2 -1
  132. package/build/unionParser.js +27 -12
  133. package/build/unionParser.test.d.ts +1 -0
  134. package/build/unionParser.test.js +60 -0
  135. package/build/zipParser.d.ts +7 -2
  136. package/build/zipParser.js +36 -12
  137. package/build/zipUnparser.d.ts +4 -1
  138. package/build/zipUnparser.js +55 -26
  139. package/build/zipUnparser.test.js +14 -14
  140. package/package.json +23 -7
  141. package/src/allSettledStream.test.ts +40 -0
  142. package/src/allSettledStream.ts +47 -15
  143. package/src/androidPackage.ts +48 -0
  144. package/src/{apkParser.test.ts → androidPackageParser.test.ts} +6 -7
  145. package/src/{apkParser.test.ts.md → androidPackageParser.test.ts.md} +4 -4
  146. package/src/androidPackageParser.test.ts.snap +0 -0
  147. package/src/androidPackageParser.ts +440 -0
  148. package/src/androidPackageUnparser.test.ts +36 -0
  149. package/src/androidPackageUnparser.ts +120 -0
  150. package/src/arbitrarilySlicedAsyncInterable.ts +7 -2
  151. package/src/arrayParser.test.ts +3 -3
  152. package/src/backsmali.ts +30 -0
  153. package/src/bsonParser.ts +13 -2
  154. package/src/customInvariant.ts +1 -1
  155. package/src/dalvikBytecodeParser/formatParsers.ts +421 -0
  156. package/src/dalvikBytecodeParser.ts +2074 -0
  157. package/src/dalvikExecutable.ts +220 -0
  158. package/src/dalvikExecutableParser/stringSyntaxParser.ts +145 -0
  159. package/src/dalvikExecutableParser/typeParsers.ts +65 -0
  160. package/src/dalvikExecutableParser/typedNumbers.ts +57 -0
  161. package/src/dalvikExecutableParser.test.ts +89 -0
  162. package/src/dalvikExecutableParser.test.ts.md +634 -0
  163. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  164. package/src/dalvikExecutableParser.ts +2768 -0
  165. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +346 -0
  166. package/src/debugLogInputParser.ts +28 -0
  167. package/src/debugLogParser.ts +19 -3
  168. package/src/disjunctionParser.ts +10 -5
  169. package/src/elementTerminatedArrayParser.test.ts +99 -0
  170. package/src/elementTerminatedArrayParser.ts +31 -0
  171. package/src/elementTerminatedSequenceArrayParser.test.ts +54 -0
  172. package/src/elementTerminatedSequenceArrayParser.ts +52 -0
  173. package/src/elementTerminatedSequenceParser.test.ts +54 -0
  174. package/src/elementTerminatedSequenceParser.ts +43 -0
  175. package/src/exactElementParser.ts +17 -11
  176. package/src/exactSequenceParser.ts +23 -2
  177. package/src/fetchCid.ts +125 -0
  178. package/src/fixedLengthSequenceParser.test.ts +77 -0
  179. package/src/fixedLengthSequenceParser.ts +28 -1
  180. package/src/hasExecutable.ts +11 -0
  181. package/src/highResolutionTimer.ts +49 -0
  182. package/src/inputReader.test.ts +209 -0
  183. package/src/inputReader.ts +75 -0
  184. package/src/inputReaderState.ts +33 -0
  185. package/src/inspect.ts +9 -0
  186. package/src/javaKeyStoreParser.test.ts +2 -3
  187. package/src/jsonParser.ts +13 -25
  188. package/src/leb128Parser.test.ts +171 -0
  189. package/src/leb128Parser.ts +125 -0
  190. package/src/lookaheadParser.ts +19 -0
  191. package/src/negativeLookaheadParser.test.ts +53 -0
  192. package/src/negativeLookaheadParser.ts +26 -14
  193. package/src/nonEmptyArrayParser.test.ts +20 -0
  194. package/src/nonEmptyArrayParser.ts +44 -0
  195. package/src/optionalParser.ts +1 -0
  196. package/src/parser.test.ts +131 -12
  197. package/src/parser.test.ts.md +21 -21
  198. package/src/parser.test.ts.snap +0 -0
  199. package/src/parser.ts +149 -45
  200. package/src/parserAccessorParser.ts +12 -2
  201. package/src/parserConsumedSequenceParser.ts +25 -16
  202. package/src/parserContext.test.ts +31 -0
  203. package/src/parserContext.ts +109 -37
  204. package/src/parserCreatorCompose.ts +20 -2
  205. package/src/parserError.ts +9 -6
  206. package/src/parserInputCompanion.ts +55 -0
  207. package/src/promiseCompose.ts +17 -3
  208. package/src/promiseSettled.ts +6 -0
  209. package/src/separatedArrayParser.test.ts +34 -0
  210. package/src/separatedArrayParser.ts +55 -0
  211. package/src/sequenceBuffer.test.ts +70 -0
  212. package/src/sequenceBuffer.ts +88 -2
  213. package/src/sequenceTerminatedSequenceParser.test.ts +60 -0
  214. package/src/sequenceTerminatedSequenceParser.ts +62 -0
  215. package/src/skipParser.ts +7 -5
  216. package/src/skipToParser.ts +16 -0
  217. package/src/sliceBoundedParser.test.ts +43 -1
  218. package/src/sliceBoundedParser.ts +19 -1
  219. package/src/smali.ts +24 -0
  220. package/src/smaliParser.test.ts +132 -0
  221. package/src/smaliParser.test.ts.md +2320 -0
  222. package/src/smaliParser.test.ts.snap +0 -0
  223. package/src/smaliParser.ts +1166 -0
  224. package/src/terminatedArrayParser.test.ts +258 -0
  225. package/src/terminatedArrayParser.ts +108 -3
  226. package/src/toAsyncIterable.ts +7 -0
  227. package/src/toAsyncIterator.ts +48 -0
  228. package/src/tupleParser.ts +8 -5
  229. package/src/unionParser.test.ts +79 -0
  230. package/src/unionParser.ts +44 -16
  231. package/src/zipParser.ts +77 -18
  232. package/src/zipUnparser.test.ts +18 -18
  233. package/src/zipUnparser.ts +88 -27
  234. package/build/apk.d.ts +0 -39
  235. package/build/apkParser.d.ts +0 -16
  236. package/build/apkParser.js +0 -164
  237. package/build/apkUnparser.d.ts +0 -4
  238. package/build/apkUnparser.test.js +0 -26
  239. package/build/arbitraryDosDate.d.ts +0 -2
  240. package/build/arbitraryDosDate.js +0 -8
  241. package/build/arbitraryZipEntry.d.ts +0 -3
  242. package/build/arbitraryZipEntry.js +0 -26
  243. package/build/createDisjunctionParser.d.ts +0 -2
  244. package/build/createDisjunctionParser.js +0 -47
  245. package/build/createExactParser.d.ts +0 -2
  246. package/build/createExactParser.js +0 -12
  247. package/build/createSequentialUnionParser.d.ts +0 -2
  248. package/build/createSequentialUnionParser.js +0 -69
  249. package/build/fixedLengthChunkParser.d.ts +0 -2
  250. package/build/fixedLengthChunkParser.js +0 -12
  251. package/build/fixedLengthParser.d.ts +0 -2
  252. package/build/fixedLengthParser.js +0 -12
  253. package/build/inputChunkBuffer.d.ts +0 -15
  254. package/build/inputChunkBuffer.js +0 -40
  255. package/build/inputChunkBuffer.test.js +0 -34
  256. package/build/inputCompanion.d.ts +0 -18
  257. package/build/inputCompanion.js +0 -28
  258. package/build/invariantDefined.d.ts +0 -1
  259. package/build/invariantDefined.js +0 -5
  260. package/build/invariantIdentity.d.ts +0 -3
  261. package/build/invariantIdentity.js +0 -5
  262. package/build/javaKeystoreParser.d.ts +0 -2
  263. package/build/javaKeystoreParser.js +0 -7
  264. package/build/jsonParser2.d.ts +0 -3
  265. package/build/jsonParser2.js +0 -52
  266. package/build/jsonParser2.test.js +0 -22
  267. package/build/negativeLookahead.d.ts +0 -2
  268. package/build/negativeLookahead.js +0 -18
  269. package/build/parserCompose.d.ts +0 -3
  270. package/build/parserCompose.js +0 -7
  271. package/build/parserImplementationInvariantInvariant.d.ts +0 -3
  272. package/build/parserImplementationInvariantInvariant.js +0 -15
  273. package/build/parserInvariant.d.ts +0 -4
  274. package/build/parserInvariant.js +0 -11
  275. package/build/promiseFish.d.ts +0 -1
  276. package/build/promiseFish.js +0 -3
  277. package/build/sequenceParser.d.ts +0 -3
  278. package/build/sequenceParser.js +0 -10
  279. package/build/terminatedSequenceParser.d.ts +0 -2
  280. package/build/terminatedSequenceParser.js +0 -24
  281. package/build/unparserInputCompanion.d.ts +0 -15
  282. package/build/unparserInputCompanion.js +0 -13
  283. package/build/zipEntry.d.ts +0 -28
  284. package/build/zipFile.d.ts +0 -32
  285. package/build/zipFileEntry.d.ts +0 -6
  286. package/src/apk.ts +0 -48
  287. package/src/apkParser.test.ts.snap +0 -0
  288. package/src/apkParser.ts +0 -392
  289. package/src/apkUnparser.test.ts +0 -37
  290. package/src/apkUnparser.ts +0 -120
  291. package/src/invariantDefined.ts +0 -6
  292. package/src/invariantIdentity.ts +0 -8
  293. /package/build/{apk.js → androidPackage.js} +0 -0
  294. /package/build/{apkParser.test.d.ts → androidPackageParser.test.d.ts} +0 -0
  295. /package/build/{apkUnparser.test.d.ts → androidPackageUnparser.test.d.ts} +0 -0
  296. /package/build/{arbitraryDosPermissions.d.ts → dalvikExecutableParser.test.d.ts} +0 -0
  297. /package/build/{arbitraryDosPermissions.js → dalvikExecutableParserAgainstSmaliParser.test.d.ts} +0 -0
  298. /package/build/{inputChunkBuffer.test.d.ts → elementTerminatedArrayParser.test.d.ts} +0 -0
  299. /package/build/{jsonParser2.test.d.ts → elementTerminatedSequenceArrayParser.test.d.ts} +0 -0
  300. /package/build/{parserParsingInvariant.d.ts → elementTerminatedSequenceParser.test.d.ts} +0 -0
  301. /package/build/{parserParsingInvariant.js → fixedLengthSequenceParser.test.d.ts} +0 -0
  302. /package/build/{zipEntry.js → leb128Parser.test.d.ts} +0 -0
  303. /package/build/{zipFile.js → negativeLookaheadParser.test.d.ts} +0 -0
  304. /package/build/{zipFileEntry.js → nonEmptyArrayParser.test.d.ts} +0 -0
package/src/parser.ts CHANGED
@@ -1,14 +1,17 @@
1
- import invariant from 'invariant';
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
- function isAsyncIterable<T>(value: any): value is AsyncIterable<T> {
38
- return value && typeof value[Symbol.asyncIterator] === 'function';
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 isIterable<T>(value: any): value is Iterable<T> {
42
- return value && typeof value[Symbol.iterator] === 'function';
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
- function isIterator<T>(value: any): value is Iterator<T> {
46
- return value && typeof value.next === 'function';
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 iteratorToAsyncIterator<T>(iterator: Iterator<T>): AsyncIterator<T> {
50
- return {
51
- next: async () => iterator.next(),
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
- function toAsyncIterator<T>(value: AsyncIterator<T> | AsyncIterable<T> | Iterable<T> | T): AsyncIterator<T> {
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
- if (isAsyncIterable(value)) {
66
- return value[Symbol.asyncIterator]();
67
- }
123
+ const ParserContext = options.parserContextClass ?? ParserContextImplementation;
68
124
 
69
- if (isIterable(value)) {
70
- return iteratorToAsyncIterator(value[Symbol.iterator]());
71
- }
125
+ const parserContext = new ParserContext<Sequence, Element>(parserInputCompanion, inputReader, undefined, {
126
+ ...options,
127
+ debugName: 'root',
128
+ });
72
129
 
73
- if (isIterator<T>(value)) {
74
- return iteratorToAsyncIterator(value);
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
- invariant(
78
- false,
79
- 'Value must be an async iterator, async iterable, iterable or iterator got %s.',
80
- value,
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 inputAsyncIterator = toAsyncIterator(input);
190
+ const {
191
+ outputPromise,
192
+ parserContext,
193
+ inputReader,
194
+ } = runParserInternal(parser, input, parserInputCompanion, options);
95
195
 
96
- const inputReader = new InputReaderImplementation<Sequence, Element>(parserInputCompanion, inputAsyncIterator);
97
- const parserContext = new ParserContextImplementation<Sequence, Element>(parserInputCompanion, inputReader, undefined, {
98
- ...options,
99
- debugName: 'root',
100
- });
196
+ return await withEnrichedParserError(parserContext, inputReader, async () => {
197
+ const output = await outputPromise;
198
+
199
+ const inputReaderState = inputReader.toInputReaderState();
101
200
 
102
- return parser(parserContext);
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> => async parserContext => parserAccessor()(parserContext);
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> => async parserContext => {
7
- const initialPosition = parserContext.position;
8
- const childParserContext = parserContext.lookahead();
9
- let value: Output;
10
- let consumedLength: number;
11
- try {
12
- value = await childParser(childParserContext);
13
- consumedLength = childParserContext.position - initialPosition;
14
- } finally {
15
- childParserContext.dispose();
16
- }
17
- const consumedSequenceParser = createFixedLengthSequenceParser<Sequence>(consumedLength);
18
- const consumedSequence = await consumedSequenceParser(parserContext);
19
- return [value, consumedSequence];
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 => {
@@ -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
- lookahead(options: LookaheadOptions = {}): ParserContext<Sequence, Element> {
115
- const lookaheadInputReader = this._inputReader.lookahead();
174
+ async readSequence(start: number, end: number): Promise<Sequence> {
175
+ const sequence = await this.peekSequence(start, end);
116
176
 
117
- if (this.position !== lookaheadInputReader.position) {
118
- debugger;
177
+ if (sequence === undefined) {
178
+ throw new ParserUnexpectedEndOfInputError('', this._depth, this.position);
119
179
  }
120
180
 
121
- invariant(
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 lookaheadParserContext = new ParserContextImplementation(
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
- if (this.position !== lookaheadParserContext.position) {
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
- invariant(this._parentParserContext !== undefined, 'this._parentParserContext !== undefined');
162
- invariant(
227
+ const parentParserContext = parserImplementationInvariant(
228
+ this._parentParserContext,
229
+ 'this._parentParserContext !== undefined',
230
+ );
231
+ parserImplementationInvariant(
163
232
  (
164
- this._parentParserContext._exclusiveChildParserContext === undefined
165
- || this._parentParserContext._exclusiveChildParserContext === this
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
- this._parentParserContext.toString(),
175
- this._parentParserContext._exclusiveChildParserContext?.toString(),
243
+ parentParserContext.toString(),
244
+ parentParserContext._exclusiveChildParserContext?.toString(),
176
245
  );
177
- invariant(
178
- this._parentParserContext.position <= this.position,
246
+ parserImplementationInvariant(
247
+ parentParserContext.position <= this.position,
179
248
  'unlookahead this._parentParserContext.position (%s) <= this.position (%s)',
180
- this._parentParserContext.position,
249
+ parentParserContext.position,
181
250
  this.position,
182
251
  );
183
252
 
184
- const offset = this._inputReader.position - this._parentParserContext._inputReader.position;
253
+ const offset = this._inputReader.position - parentParserContext._inputReader.position;
185
254
 
186
- this._parentParserContext.skip(offset);
255
+ parentParserContext.skip(offset);
187
256
 
188
- invariant(
189
- this._parentParserContext.position === this.position,
257
+ parserImplementationInvariant(
258
+ parentParserContext.position === this.position,
190
259
  'unlookahead this._parentParserContext.position (%s) === this.position (%s)',
191
- this._parentParserContext.position,
260
+ parentParserContext.position,
192
261
  this.position,
193
262
  );
194
263
 
195
- this._inputReader = this._parentParserContext._inputReader;
196
- this._parentParserContext._exclusiveChildParserContext = this;
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
- invariant(this._parentParserContext !== undefined, 'this._parentParserContext !== undefined');
205
- invariant(
273
+ const parentParserContext = parserImplementationInvariant(
274
+ this._parentParserContext,
275
+ 'this._parentParserContext !== undefined',
276
+ );
277
+ parserImplementationInvariant(
206
278
  (
207
- this._parentParserContext._exclusiveChildParserContext === undefined
208
- || this._parentParserContext._exclusiveChildParserContext === this
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
- this._parentParserContext.toString(),
218
- this._parentParserContext._exclusiveChildParserContext?.toString(),
289
+ parentParserContext.toString(),
290
+ parentParserContext._exclusiveChildParserContext?.toString(),
219
291
  );
220
292
 
221
- this._parentParserContext._exclusiveChildParserContext = undefined;
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
- invariant(childErrors.length > 0, 'childErrors.length > 0');
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
- invariant(false, 'Unsupported errorJoinMode: %s', errorJoinMode);
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
- return (...arguments_) => {
15
+ const parserCreatorComposedOuter: (...arguments_: Arguments) => Parser<OutputB, Sequence, Element> = (...arguments_) => {
15
16
  const parserA = f1(...arguments_);
16
17
 
17
- return async parserContext => {
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
  }