@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
@@ -408,3 +408,61 @@ test('parse smali with virtual method after direct methods (a0/n issue)', async
408
408
  t.truthy(actual);
409
409
  t.is(actual.classData?.virtualMethods.length, 1);
410
410
  });
411
+ // Minimal failing test case for .end local directive
412
+ test('parse smali with .end local directive', async (t) => {
413
+ const smali = `.class public Lpl/czak/minimal/MainActivity;
414
+ .super Landroid/app/Activity;
415
+
416
+ # direct methods
417
+ .method private sumToN(I)I
418
+ .registers 4
419
+ .param p1, "n" # I
420
+
421
+ const/4 v0, 0x0
422
+
423
+ .local v0, "sum":I
424
+ const/4 v1, 0x1
425
+
426
+ .local v1, "i":I
427
+ :goto_2
428
+ if-gt v1, p1, :cond_8
429
+
430
+ add-int/2addr v0, v1
431
+
432
+ add-int/lit8 v1, v1, 0x1
433
+
434
+ goto :goto_2
435
+
436
+ .end local v1 # "i":I
437
+ :cond_8
438
+ return v0
439
+ .end method
440
+ `;
441
+ const actual = await runParser(smaliParser, smali, stringParserInputCompanion, {
442
+ errorJoinMode: 'all',
443
+ });
444
+ t.truthy(actual);
445
+ t.is(actual.classData?.directMethods.length, 1);
446
+ });
447
+ // Minimal test case for .local with generic type signature
448
+ test('parse smali with .local directive with generic type signature', async (t) => {
449
+ const smali = `.class public Lpl/czak/minimal/MainActivity;
450
+ .super Landroid/app/Activity;
451
+
452
+ # direct methods
453
+ .method private useLambda()Ljava/lang/String;
454
+ .registers 3
455
+
456
+ new-instance v0, Lpl/czak/minimal/MainActivity$$ExternalSyntheticLambda0;
457
+
458
+ .local v0, "supplier":Ljava/util/function/Supplier;, "Ljava/util/function/Supplier<Ljava/lang/String;>;"
459
+
460
+ return-object v0
461
+ .end method
462
+ `;
463
+ const actual = await runParser(smaliParser, smali, stringParserInputCompanion, {
464
+ errorJoinMode: 'all',
465
+ });
466
+ t.truthy(actual);
467
+ t.is(actual.classData?.directMethods.length, 1);
468
+ });
@@ -0,0 +1,5 @@
1
+ export declare function unescapeZigString(raw: string): string;
2
+ export declare function escapeZigString(value: string): string;
3
+ export declare function escapeZigChar(value: string): string;
4
+ export declare function unescapeJavaString(raw: string): string;
5
+ export declare function escapeJavaString(value: string): string;
@@ -0,0 +1,244 @@
1
+ export function unescapeZigString(raw) {
2
+ let result = '';
3
+ let i = 0;
4
+ while (i < raw.length) {
5
+ if (raw[i] === '\\' && i + 1 < raw.length) {
6
+ const next = raw[i + 1];
7
+ switch (next) {
8
+ case 'n':
9
+ result += '\n';
10
+ i += 2;
11
+ break;
12
+ case 't':
13
+ result += '\t';
14
+ i += 2;
15
+ break;
16
+ case 'r':
17
+ result += '\r';
18
+ i += 2;
19
+ break;
20
+ case '\\':
21
+ result += '\\';
22
+ i += 2;
23
+ break;
24
+ case '"':
25
+ result += '"';
26
+ i += 2;
27
+ break;
28
+ case '\'':
29
+ result += '\'';
30
+ i += 2;
31
+ break;
32
+ case 'x': {
33
+ const hex = raw.slice(i + 2, i + 4);
34
+ result += String.fromCharCode(parseInt(hex, 16));
35
+ i += 4;
36
+ break;
37
+ }
38
+ case 'u': {
39
+ // \u{H+}
40
+ const closeBrace = raw.indexOf('}', i + 3);
41
+ const hex = raw.slice(i + 3, closeBrace);
42
+ result += String.fromCodePoint(parseInt(hex, 16));
43
+ i = closeBrace + 1;
44
+ break;
45
+ }
46
+ default:
47
+ result += raw[i];
48
+ i++;
49
+ break;
50
+ }
51
+ }
52
+ else {
53
+ result += raw[i];
54
+ i++;
55
+ }
56
+ }
57
+ return result;
58
+ }
59
+ export function escapeZigString(value) {
60
+ let result = '';
61
+ for (const ch of value) {
62
+ const code = ch.codePointAt(0);
63
+ switch (ch) {
64
+ case '\\':
65
+ result += '\\\\';
66
+ break;
67
+ case '"':
68
+ result += '\\"';
69
+ break;
70
+ case '\n':
71
+ result += '\\n';
72
+ break;
73
+ case '\r':
74
+ result += '\\r';
75
+ break;
76
+ case '\t':
77
+ result += '\\t';
78
+ break;
79
+ default:
80
+ if (code < 0x20) {
81
+ result += '\\x' + code.toString(16).padStart(2, '0');
82
+ }
83
+ else if (code > 0x7E && code > 0xFFFF) {
84
+ result += '\\u{' + code.toString(16) + '}';
85
+ }
86
+ else {
87
+ result += ch;
88
+ }
89
+ break;
90
+ }
91
+ }
92
+ return result;
93
+ }
94
+ export function escapeZigChar(value) {
95
+ let result = '';
96
+ for (const ch of value) {
97
+ const code = ch.codePointAt(0);
98
+ switch (ch) {
99
+ case '\\':
100
+ result += '\\\\';
101
+ break;
102
+ case '\'':
103
+ result += '\\\'';
104
+ break;
105
+ case '\n':
106
+ result += '\\n';
107
+ break;
108
+ case '\r':
109
+ result += '\\r';
110
+ break;
111
+ case '\t':
112
+ result += '\\t';
113
+ break;
114
+ default:
115
+ if (code < 0x20) {
116
+ result += '\\x' + code.toString(16).padStart(2, '0');
117
+ }
118
+ else if (code > 0x7E && code > 0xFFFF) {
119
+ result += '\\u{' + code.toString(16) + '}';
120
+ }
121
+ else {
122
+ result += ch;
123
+ }
124
+ break;
125
+ }
126
+ }
127
+ return result;
128
+ }
129
+ export function unescapeJavaString(raw) {
130
+ let result = '';
131
+ let i = 0;
132
+ while (i < raw.length) {
133
+ if (raw[i] === '\\' && i + 1 < raw.length) {
134
+ const next = raw[i + 1];
135
+ switch (next) {
136
+ case 'n':
137
+ result += '\n';
138
+ i += 2;
139
+ break;
140
+ case 't':
141
+ result += '\t';
142
+ i += 2;
143
+ break;
144
+ case 'r':
145
+ result += '\r';
146
+ i += 2;
147
+ break;
148
+ case 'b':
149
+ result += '\b';
150
+ i += 2;
151
+ break;
152
+ case 'f':
153
+ result += '\f';
154
+ i += 2;
155
+ break;
156
+ case '\\':
157
+ result += '\\';
158
+ i += 2;
159
+ break;
160
+ case '"':
161
+ result += '"';
162
+ i += 2;
163
+ break;
164
+ case '\'':
165
+ result += '\'';
166
+ i += 2;
167
+ break;
168
+ case 'u': {
169
+ const hex = raw.slice(i + 2, i + 6);
170
+ result += String.fromCharCode(parseInt(hex, 16));
171
+ i += 6;
172
+ break;
173
+ }
174
+ default: {
175
+ // Octal escape: \0 - \377
176
+ if (next >= '0' && next <= '7') {
177
+ let octal = next;
178
+ let j = i + 2;
179
+ // Up to 3 octal digits, max value 377 (0xFF)
180
+ if (j < raw.length && raw[j] >= '0' && raw[j] <= '7') {
181
+ octal += raw[j];
182
+ j++;
183
+ if (j < raw.length && raw[j] >= '0' && raw[j] <= '7' && parseInt(octal + raw[j], 8) <= 0xFF) {
184
+ octal += raw[j];
185
+ j++;
186
+ }
187
+ }
188
+ result += String.fromCharCode(parseInt(octal, 8));
189
+ i = j;
190
+ }
191
+ else {
192
+ result += raw[i];
193
+ i++;
194
+ }
195
+ break;
196
+ }
197
+ }
198
+ }
199
+ else {
200
+ result += raw[i];
201
+ i++;
202
+ }
203
+ }
204
+ return result;
205
+ }
206
+ export function escapeJavaString(value) {
207
+ let result = '';
208
+ for (const ch of value) {
209
+ switch (ch) {
210
+ case '\\':
211
+ result += '\\\\';
212
+ break;
213
+ case '"':
214
+ result += '\\"';
215
+ break;
216
+ case '\n':
217
+ result += '\\n';
218
+ break;
219
+ case '\r':
220
+ result += '\\r';
221
+ break;
222
+ case '\t':
223
+ result += '\\t';
224
+ break;
225
+ case '\b':
226
+ result += '\\b';
227
+ break;
228
+ case '\f':
229
+ result += '\\f';
230
+ break;
231
+ default: {
232
+ const code = ch.charCodeAt(0);
233
+ if (code < 0x20) {
234
+ result += '\\u' + code.toString(16).padStart(4, '0');
235
+ }
236
+ else {
237
+ result += ch;
238
+ }
239
+ break;
240
+ }
241
+ }
242
+ }
243
+ return result;
244
+ }
@@ -0,0 +1,29 @@
1
+ export type SymbolicExpressionAtom = {
2
+ type: 'atom';
3
+ value: string;
4
+ };
5
+ export type SymbolicExpressionString = {
6
+ type: 'string';
7
+ value: string;
8
+ };
9
+ export type SymbolicExpressionList = {
10
+ type: 'list';
11
+ value: SymbolicExpression[];
12
+ };
13
+ export type SymbolicExpressionQuote = {
14
+ type: 'quote';
15
+ value: SymbolicExpression;
16
+ };
17
+ export type SymbolicExpressionQuasiquote = {
18
+ type: 'quasiquote';
19
+ value: SymbolicExpression;
20
+ };
21
+ export type SymbolicExpressionUnquote = {
22
+ type: 'unquote';
23
+ value: SymbolicExpression;
24
+ };
25
+ export type SymbolicExpressionUnquoteSplicing = {
26
+ type: 'unquote-splicing';
27
+ value: SymbolicExpression;
28
+ };
29
+ export type SymbolicExpression = SymbolicExpressionAtom | SymbolicExpressionString | SymbolicExpressionList | SymbolicExpressionQuote | SymbolicExpressionQuasiquote | SymbolicExpressionUnquote | SymbolicExpressionUnquoteSplicing;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { type Parser } from './parser.js';
2
+ import { type SymbolicExpression } from './symbolicExpression.js';
3
+ export declare const symbolicExpressionParser: Parser<SymbolicExpression, string>;
4
+ export declare const symbolicExpressionDocumentParser: Parser<SymbolicExpression, string>;
@@ -0,0 +1,123 @@
1
+ import { setParserName } from './parser.js';
2
+ import { createDisjunctionParser } from './disjunctionParser.js';
3
+ import { createExactSequenceParser } from './exactSequenceParser.js';
4
+ import { promiseCompose } from './promiseCompose.js';
5
+ import { createTupleParser } from './tupleParser.js';
6
+ import { createArrayParser } from './arrayParser.js';
7
+ import { createParserAccessorParser } from './parserAccessorParser.js';
8
+ import { createRegExpParser } from './regexpParser.js';
9
+ // Whitespace parser (spaces, tabs, newlines)
10
+ const symbolicExpressionWhitespaceParser = promiseCompose(createRegExpParser(/\s+/), match => match[0]);
11
+ setParserName(symbolicExpressionWhitespaceParser, 'symbolicExpressionWhitespaceParser');
12
+ const symbolicExpressionOptionalWhitespaceParser = promiseCompose(createRegExpParser(/\s*/), match => match[0]);
13
+ setParserName(symbolicExpressionOptionalWhitespaceParser, 'symbolicExpressionOptionalWhitespaceParser');
14
+ // String literal parser: "..." with escape sequences
15
+ const symbolicExpressionStringParser = promiseCompose(createRegExpParser(/"(?:[^"\\]|\\.)*"/s), match => {
16
+ // Remove surrounding quotes and process escape sequences in a single pass
17
+ const raw = match[0].slice(1, -1);
18
+ const value = raw.replace(/\\(.)/gs, (_, char) => {
19
+ switch (char) {
20
+ case 'n': return '\n';
21
+ case 'r': return '\r';
22
+ case 't': return '\t';
23
+ case 'f': return '\f';
24
+ case 'b': return '\b';
25
+ case '"': return '"';
26
+ case '\\': return '\\';
27
+ default: return char;
28
+ }
29
+ });
30
+ return {
31
+ type: 'string',
32
+ value,
33
+ };
34
+ });
35
+ setParserName(symbolicExpressionStringParser, 'symbolicExpressionStringParser');
36
+ // Atom parser: unquoted symbols (any chars except whitespace, parens, quotes, etc.)
37
+ // Supports backslash escapes: \x becomes x, trailing \ becomes nothing
38
+ const symbolicExpressionAtomParser = promiseCompose(createRegExpParser(/(?:[^\s()"'`,;\\]|\\.)+\\?|\\$/), match => {
39
+ const raw = match[0];
40
+ // Process backslash escapes: \x becomes x, trailing \ becomes nothing
41
+ const value = raw.replace(/\\(.?)/g, '$1');
42
+ return {
43
+ type: 'atom',
44
+ value,
45
+ };
46
+ });
47
+ setParserName(symbolicExpressionAtomParser, 'symbolicExpressionAtomParser');
48
+ // Quote parser: 'expr
49
+ const symbolicExpressionQuoteParser = promiseCompose(createTupleParser([
50
+ createExactSequenceParser("'"),
51
+ symbolicExpressionOptionalWhitespaceParser,
52
+ createParserAccessorParser(() => symbolicExpressionParser),
53
+ ]), ([, , expr]) => ({
54
+ type: 'quote',
55
+ value: expr,
56
+ }));
57
+ setParserName(symbolicExpressionQuoteParser, 'symbolicExpressionQuoteParser');
58
+ // Quasiquote parser: `expr
59
+ const symbolicExpressionQuasiquoteParser = promiseCompose(createTupleParser([
60
+ createExactSequenceParser('`'),
61
+ symbolicExpressionOptionalWhitespaceParser,
62
+ createParserAccessorParser(() => symbolicExpressionParser),
63
+ ]), ([, , expr]) => ({
64
+ type: 'quasiquote',
65
+ value: expr,
66
+ }));
67
+ setParserName(symbolicExpressionQuasiquoteParser, 'symbolicExpressionQuasiquoteParser');
68
+ // Unquote-splicing parser: ,@expr (must come before unquote)
69
+ const symbolicExpressionUnquoteSplicingParser = promiseCompose(createTupleParser([
70
+ createExactSequenceParser(',@'),
71
+ symbolicExpressionOptionalWhitespaceParser,
72
+ createParserAccessorParser(() => symbolicExpressionParser),
73
+ ]), ([, , expr]) => ({
74
+ type: 'unquote-splicing',
75
+ value: expr,
76
+ }));
77
+ setParserName(symbolicExpressionUnquoteSplicingParser, 'symbolicExpressionUnquoteSplicingParser');
78
+ // Unquote parser: ,expr
79
+ const symbolicExpressionUnquoteParser = promiseCompose(createTupleParser([
80
+ createExactSequenceParser(','),
81
+ symbolicExpressionOptionalWhitespaceParser,
82
+ createParserAccessorParser(() => symbolicExpressionParser),
83
+ ]), ([, , expr]) => ({
84
+ type: 'unquote',
85
+ value: expr,
86
+ }));
87
+ setParserName(symbolicExpressionUnquoteParser, 'symbolicExpressionUnquoteParser');
88
+ // List element parser with optional whitespace
89
+ const symbolicExpressionListElementParser = promiseCompose(createTupleParser([
90
+ createParserAccessorParser(() => symbolicExpressionParser),
91
+ symbolicExpressionOptionalWhitespaceParser,
92
+ ]), ([expr]) => expr);
93
+ setParserName(symbolicExpressionListElementParser, 'symbolicExpressionListElementParser');
94
+ // List parser: (...)
95
+ const symbolicExpressionListParser = promiseCompose(createTupleParser([
96
+ createExactSequenceParser('('),
97
+ symbolicExpressionOptionalWhitespaceParser,
98
+ createArrayParser(symbolicExpressionListElementParser),
99
+ createExactSequenceParser(')'),
100
+ ]), ([, , elements]) => ({
101
+ type: 'list',
102
+ value: elements,
103
+ }));
104
+ setParserName(symbolicExpressionListParser, 'symbolicExpressionListParser');
105
+ // Main expression parser (union of all expression types)
106
+ // Order matters: unquote-splicing before unquote, etc.
107
+ export const symbolicExpressionParser = createDisjunctionParser([
108
+ symbolicExpressionListParser,
109
+ symbolicExpressionStringParser,
110
+ symbolicExpressionQuoteParser,
111
+ symbolicExpressionQuasiquoteParser,
112
+ symbolicExpressionUnquoteSplicingParser,
113
+ symbolicExpressionUnquoteParser,
114
+ symbolicExpressionAtomParser,
115
+ ]);
116
+ setParserName(symbolicExpressionParser, 'symbolicExpressionParser');
117
+ // Top-level parser that handles leading/trailing whitespace
118
+ export const symbolicExpressionDocumentParser = promiseCompose(createTupleParser([
119
+ symbolicExpressionOptionalWhitespaceParser,
120
+ symbolicExpressionParser,
121
+ symbolicExpressionOptionalWhitespaceParser,
122
+ ]), ([, expr]) => expr);
123
+ setParserName(symbolicExpressionDocumentParser, 'symbolicExpressionDocumentParser');
@@ -0,0 +1 @@
1
+ export {};