@futpib/parser 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +24 -0
- package/.github/workflows/main.yml +1 -0
- package/build/androidPackageParser.js +30 -32
- package/build/arbitraryDalvikBytecode.d.ts +3 -3
- package/build/arbitraryDalvikBytecode.js +33 -27
- package/build/arbitraryDalvikExecutable.js +55 -17
- package/build/arbitraryJava.d.ts +31 -0
- package/build/arbitraryJava.js +532 -0
- package/build/arbitraryJavaScript.d.ts +3 -0
- package/build/arbitraryJavaScript.js +263 -0
- package/build/arbitraryJavascript.d.ts +3 -0
- package/build/arbitraryJavascript.js +263 -0
- package/build/arbitraryZig.d.ts +3 -0
- package/build/arbitraryZig.js +240 -0
- package/build/arbitraryZipStream.d.ts +1 -1
- package/build/arrayParser.js +72 -13
- package/build/backsmali.d.ts +4 -3
- package/build/backsmali.js +26 -6
- package/build/bash.d.ts +89 -0
- package/build/bash.js +1 -0
- package/build/bashParser.d.ts +6 -0
- package/build/bashParser.js +335 -0
- package/build/bashParser.test.d.ts +1 -0
- package/build/bashParser.test.js +343 -0
- package/build/bashParserEdgeCases.test.d.ts +1 -0
- package/build/bashParserEdgeCases.test.js +117 -0
- package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
- package/build/dalvikBytecodeParser/addressConversion.js +334 -0
- package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
- package/build/dalvikBytecodeParser/formatParsers.js +13 -14
- package/build/dalvikBytecodeParser.d.ts +60 -31
- package/build/dalvikBytecodeParser.js +92 -35
- package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
- package/build/dalvikBytecodeParser.test-d.js +268 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
- package/build/dalvikBytecodeUnparser.d.ts +2 -2
- package/build/dalvikBytecodeUnparser.js +23 -23
- package/build/dalvikBytecodeUnparser.test.js +7 -7
- package/build/dalvikExecutable.d.ts +3 -3
- package/build/dalvikExecutable.test-d.d.ts +1 -0
- package/build/dalvikExecutable.test-d.js +59 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
- package/build/dalvikExecutableParser/typedNumbers.js +3 -0
- package/build/dalvikExecutableParser.d.ts +2 -1
- package/build/dalvikExecutableParser.js +96 -77
- package/build/dalvikExecutableParser.test.js +24 -3
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
- package/build/dalvikExecutableUnparser.d.ts +2 -2
- package/build/dalvikExecutableUnparser.test.js +2 -1
- package/build/disjunctionParser.d.ts +5 -3
- package/build/disjunctionParser.js +79 -17
- package/build/disjunctionParser.test-d.d.ts +1 -0
- package/build/disjunctionParser.test-d.js +72 -0
- package/build/elementSwitchParser.d.ts +4 -0
- package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
- package/build/elementSwitchParser.test-d.d.ts +1 -0
- package/build/elementSwitchParser.test-d.js +44 -0
- package/build/exactSequenceParser.d.ts +4 -2
- package/build/exactSequenceParser.test-d.d.ts +1 -0
- package/build/exactSequenceParser.test-d.js +36 -0
- package/build/fetchCid.js +2 -66
- package/build/index.d.ts +25 -2
- package/build/index.js +23 -1
- package/build/index.test.js +16 -1
- package/build/inputReader.d.ts +10 -0
- package/build/inputReader.js +36 -0
- package/build/java.d.ts +502 -0
- package/build/java.js +2 -0
- package/build/javaKeyStoreParser.js +14 -17
- package/build/javaParser.d.ts +51 -0
- package/build/javaParser.js +1538 -0
- package/build/javaParser.test.d.ts +1 -0
- package/build/javaParser.test.js +1287 -0
- package/build/javaScript.d.ts +35 -0
- package/build/javaScript.js +1 -0
- package/build/javaScriptParser.d.ts +9 -0
- package/build/javaScriptParser.js +34 -0
- package/build/javaScriptUnparser.d.ts +3 -0
- package/build/javaScriptUnparser.js +4 -0
- package/build/javaScriptUnparser.test.d.ts +1 -0
- package/build/javaScriptUnparser.test.js +24 -0
- package/build/javaUnparser.d.ts +2 -0
- package/build/javaUnparser.js +519 -0
- package/build/javaUnparser.test.d.ts +1 -0
- package/build/javaUnparser.test.js +24 -0
- package/build/javascript.d.ts +35 -0
- package/build/javascript.js +1 -0
- package/build/javascriptParser.d.ts +9 -0
- package/build/javascriptParser.js +34 -0
- package/build/javascriptUnparser.d.ts +3 -0
- package/build/javascriptUnparser.js +4 -0
- package/build/javascriptUnparser.test.d.ts +1 -0
- package/build/javascriptUnparser.test.js +24 -0
- package/build/jsonParser.js +2 -12
- package/build/lazyMessageError.d.ts +3 -0
- package/build/lookaheadParser.js +60 -3
- package/build/negativeLookaheadParser.js +70 -11
- package/build/nonEmptyArrayParser.js +72 -13
- package/build/objectParser.d.ts +12 -0
- package/build/objectParser.js +31 -0
- package/build/objectParser.test-d.d.ts +1 -0
- package/build/objectParser.test-d.js +112 -0
- package/build/objectParser.test.d.ts +1 -0
- package/build/objectParser.test.js +55 -0
- package/build/optionalParser.js +69 -10
- package/build/parser.d.ts +4 -0
- package/build/parser.js +3 -1
- package/build/parser.test.js +114 -1
- package/build/parserConsumedSequenceParser.js +66 -7
- package/build/parserContext.d.ts +6 -0
- package/build/parserContext.js +20 -11
- package/build/parserError.d.ts +119 -27
- package/build/parserError.js +16 -8
- package/build/regexpParser.d.ts +2 -0
- package/build/regexpParser.js +101 -0
- package/build/regexpParser.test.d.ts +1 -0
- package/build/regexpParser.test.js +114 -0
- package/build/regularExpression.d.ts +63 -0
- package/build/regularExpression.js +1 -0
- package/build/regularExpressionParser.d.ts +3 -0
- package/build/regularExpressionParser.js +600 -0
- package/build/regularExpressionParser.test.d.ts +1 -0
- package/build/regularExpressionParser.test.js +89 -0
- package/build/separatedArrayParser.js +73 -14
- package/build/separatedNonEmptyArrayParser.js +73 -14
- package/build/sliceBoundedParser.js +62 -5
- package/build/smaliParser.d.ts +7 -7
- package/build/smaliParser.js +185 -268
- package/build/smaliParser.test.js +58 -0
- package/build/stringEscapes.d.ts +5 -0
- package/build/stringEscapes.js +244 -0
- package/build/symbolicExpression.d.ts +29 -0
- package/build/symbolicExpression.js +1 -0
- package/build/symbolicExpressionParser.d.ts +4 -0
- package/build/symbolicExpressionParser.js +123 -0
- package/build/symbolicExpressionParser.test.d.ts +1 -0
- package/build/symbolicExpressionParser.test.js +289 -0
- package/build/terminatedArrayParser.js +113 -38
- package/build/terminatedArrayParser.test.js +4 -2
- package/build/tupleParser.d.ts +7 -15
- package/build/tupleParser.js +1 -0
- package/build/unionParser.d.ts +5 -3
- package/build/unionParser.js +7 -2
- package/build/unionParser.test-d.d.ts +1 -0
- package/build/unionParser.test-d.js +72 -0
- package/build/unionParser.test.js +10 -11
- package/build/zig.d.ts +280 -0
- package/build/zig.js +2 -0
- package/build/zigParser.d.ts +3 -0
- package/build/zigParser.js +1119 -0
- package/build/zigParser.test.d.ts +1 -0
- package/build/zigParser.test.js +1590 -0
- package/build/zigUnparser.d.ts +2 -0
- package/build/zigUnparser.js +460 -0
- package/build/zigUnparser.test.d.ts +1 -0
- package/build/zigUnparser.test.js +24 -0
- package/build/zipParser.js +19 -32
- package/build/zipUnparser.js +19 -7
- package/build/zipUnparser.test.js +1 -1
- package/node_modules-@types/s-expression/index.d.ts +5 -0
- package/package.json +25 -6
- package/src/androidPackageParser.ts +33 -60
- package/src/arbitraryDalvikBytecode.ts +39 -31
- package/src/arbitraryDalvikExecutable.ts +65 -20
- package/src/arbitraryJava.ts +804 -0
- package/src/arbitraryJavaScript.ts +410 -0
- package/src/arbitraryZig.ts +380 -0
- package/src/arrayParser.ts +1 -3
- package/src/backsmali.ts +35 -4
- package/src/bash.ts +127 -0
- package/src/bashParser.test.ts +590 -0
- package/src/bashParser.ts +498 -0
- package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
- package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
- package/src/dalvikBytecodeParser.test-d.ts +310 -0
- package/src/dalvikBytecodeParser.ts +194 -69
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
- package/src/dalvikBytecodeUnparser.test.ts +7 -7
- package/src/dalvikBytecodeUnparser.ts +31 -30
- package/src/dalvikExecutable.test-d.ts +132 -0
- package/src/dalvikExecutable.ts +3 -3
- package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
- package/src/dalvikExecutableParser.test.ts +37 -3
- package/src/dalvikExecutableParser.test.ts.md +163 -2
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +121 -139
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
- package/src/dalvikExecutableUnparser.test.ts +3 -2
- package/src/dalvikExecutableUnparser.ts +4 -4
- package/src/disjunctionParser.test-d.ts +105 -0
- package/src/disjunctionParser.ts +18 -15
- package/src/elementSwitchParser.test-d.ts +74 -0
- package/src/elementSwitchParser.ts +51 -0
- package/src/exactSequenceParser.test-d.ts +43 -0
- package/src/exactSequenceParser.ts +13 -8
- package/src/fetchCid.ts +2 -76
- package/src/index.test.ts +22 -1
- package/src/index.ts +119 -2
- package/src/inputReader.ts +53 -0
- package/src/java.ts +708 -0
- package/src/javaKeyStoreParser.ts +18 -32
- package/src/javaParser.test.ts +1592 -0
- package/src/javaParser.ts +2640 -0
- package/src/javaScript.ts +36 -0
- package/src/javaScriptParser.ts +57 -0
- package/src/javaScriptUnparser.test.ts +37 -0
- package/src/javaScriptUnparser.ts +7 -0
- package/src/javaUnparser.test.ts +37 -0
- package/src/javaUnparser.ts +640 -0
- package/src/jsonParser.ts +6 -27
- package/src/lookaheadParser.ts +2 -6
- package/src/negativeLookaheadParser.ts +1 -3
- package/src/nonEmptyArrayParser.ts +1 -3
- package/src/objectParser.test-d.ts +152 -0
- package/src/objectParser.test.ts +71 -0
- package/src/objectParser.ts +69 -0
- package/src/optionalParser.ts +1 -3
- package/src/parser.test.ts +151 -4
- package/src/parser.ts +11 -1
- package/src/parserConsumedSequenceParser.ts +2 -4
- package/src/parserContext.ts +26 -11
- package/src/parserError.ts +17 -3
- package/src/regexpParser.test.ts +264 -0
- package/src/regexpParser.ts +126 -0
- package/src/regularExpression.ts +24 -0
- package/src/regularExpressionParser.test.ts +102 -0
- package/src/regularExpressionParser.ts +920 -0
- package/src/separatedArrayParser.ts +1 -3
- package/src/separatedNonEmptyArrayParser.ts +1 -3
- package/src/sliceBoundedParser.test.ts +2 -2
- package/src/sliceBoundedParser.ts +15 -19
- package/src/smaliParser.test.ts +64 -0
- package/src/smaliParser.test.ts.md +12 -12
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +246 -534
- package/src/stringEscapes.ts +253 -0
- package/src/symbolicExpression.ts +17 -0
- package/src/symbolicExpressionParser.test.ts +466 -0
- package/src/symbolicExpressionParser.ts +190 -0
- package/src/terminatedArrayParser.test.ts +9 -6
- package/src/terminatedArrayParser.ts +25 -29
- package/src/tupleParser.ts +21 -18
- package/src/unionParser.test-d.ts +105 -0
- package/src/unionParser.test.ts +18 -17
- package/src/unionParser.ts +28 -16
- package/src/zig.ts +411 -0
- package/src/zigParser.test.ts +1693 -0
- package/src/zigParser.ts +1745 -0
- package/src/zigUnparser.test.ts +37 -0
- package/src/zigUnparser.ts +615 -0
- package/src/zipParser.ts +20 -56
- package/src/zipUnparser.test.ts +1 -1
- package/src/zipUnparser.ts +22 -7
- package/tsconfig.json +2 -2
- package/build/exactElementSwitchParser.d.ts +0 -3
- package/src/exactElementSwitchParser.ts +0 -41
|
@@ -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 {};
|