@futpib/parser 1.0.4 → 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 (250) 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 +6 -1
  20. package/build/bashParser.js +131 -90
  21. package/build/bashParser.test.js +162 -0
  22. package/build/bashParserEdgeCases.test.d.ts +1 -0
  23. package/build/bashParserEdgeCases.test.js +117 -0
  24. package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
  25. package/build/dalvikBytecodeParser/addressConversion.js +334 -0
  26. package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
  27. package/build/dalvikBytecodeParser/formatParsers.js +13 -14
  28. package/build/dalvikBytecodeParser.d.ts +60 -31
  29. package/build/dalvikBytecodeParser.js +92 -35
  30. package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
  31. package/build/dalvikBytecodeParser.test-d.js +268 -0
  32. package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
  33. package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
  34. package/build/dalvikBytecodeUnparser.d.ts +2 -2
  35. package/build/dalvikBytecodeUnparser.js +23 -23
  36. package/build/dalvikBytecodeUnparser.test.js +7 -7
  37. package/build/dalvikExecutable.d.ts +3 -3
  38. package/build/dalvikExecutable.test-d.d.ts +1 -0
  39. package/build/dalvikExecutable.test-d.js +59 -0
  40. package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
  41. package/build/dalvikExecutableParser/typedNumbers.js +3 -0
  42. package/build/dalvikExecutableParser.d.ts +2 -1
  43. package/build/dalvikExecutableParser.js +96 -77
  44. package/build/dalvikExecutableParser.test.js +24 -3
  45. package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
  46. package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
  47. package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
  48. package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
  49. package/build/dalvikExecutableUnparser.d.ts +2 -2
  50. package/build/dalvikExecutableUnparser.test.js +2 -1
  51. package/build/disjunctionParser.d.ts +5 -3
  52. package/build/disjunctionParser.js +79 -17
  53. package/build/disjunctionParser.test-d.d.ts +1 -0
  54. package/build/disjunctionParser.test-d.js +72 -0
  55. package/build/elementSwitchParser.d.ts +4 -0
  56. package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
  57. package/build/elementSwitchParser.test-d.d.ts +1 -0
  58. package/build/elementSwitchParser.test-d.js +44 -0
  59. package/build/exactSequenceParser.d.ts +4 -2
  60. package/build/exactSequenceParser.test-d.d.ts +1 -0
  61. package/build/exactSequenceParser.test-d.js +36 -0
  62. package/build/fetchCid.js +2 -66
  63. package/build/index.d.ts +3 -2
  64. package/build/index.js +2 -1
  65. package/build/index.test.js +16 -1
  66. package/build/inputReader.d.ts +10 -0
  67. package/build/inputReader.js +36 -0
  68. package/build/java.d.ts +502 -0
  69. package/build/java.js +2 -0
  70. package/build/javaKeyStoreParser.js +14 -17
  71. package/build/javaParser.d.ts +51 -0
  72. package/build/javaParser.js +1538 -0
  73. package/build/javaParser.test.d.ts +1 -0
  74. package/build/javaParser.test.js +1287 -0
  75. package/build/javaScript.d.ts +35 -0
  76. package/build/javaScript.js +1 -0
  77. package/build/javaScriptParser.d.ts +9 -0
  78. package/build/javaScriptParser.js +34 -0
  79. package/build/javaScriptUnparser.d.ts +3 -0
  80. package/build/javaScriptUnparser.js +4 -0
  81. package/build/javaScriptUnparser.test.d.ts +1 -0
  82. package/build/javaScriptUnparser.test.js +24 -0
  83. package/build/javaUnparser.d.ts +2 -0
  84. package/build/javaUnparser.js +519 -0
  85. package/build/javaUnparser.test.d.ts +1 -0
  86. package/build/javaUnparser.test.js +24 -0
  87. package/build/javascript.d.ts +35 -0
  88. package/build/javascript.js +1 -0
  89. package/build/javascriptParser.d.ts +9 -0
  90. package/build/javascriptParser.js +34 -0
  91. package/build/javascriptUnparser.d.ts +3 -0
  92. package/build/javascriptUnparser.js +4 -0
  93. package/build/javascriptUnparser.test.d.ts +1 -0
  94. package/build/javascriptUnparser.test.js +24 -0
  95. package/build/jsonParser.js +2 -12
  96. package/build/lazyMessageError.d.ts +3 -0
  97. package/build/lookaheadParser.js +60 -3
  98. package/build/negativeLookaheadParser.js +70 -11
  99. package/build/nonEmptyArrayParser.js +72 -13
  100. package/build/objectParser.d.ts +12 -0
  101. package/build/objectParser.js +31 -0
  102. package/build/objectParser.test-d.d.ts +1 -0
  103. package/build/objectParser.test-d.js +112 -0
  104. package/build/objectParser.test.d.ts +1 -0
  105. package/build/objectParser.test.js +55 -0
  106. package/build/optionalParser.js +69 -10
  107. package/build/parser.d.ts +4 -0
  108. package/build/parser.js +3 -1
  109. package/build/parser.test.js +114 -1
  110. package/build/parserConsumedSequenceParser.js +66 -7
  111. package/build/parserContext.d.ts +6 -0
  112. package/build/parserContext.js +20 -11
  113. package/build/parserError.d.ts +119 -27
  114. package/build/parserError.js +16 -8
  115. package/build/regexpParser.js +33 -3
  116. package/build/regexpParser.test.js +31 -0
  117. package/build/regularExpressionParser.js +35 -15
  118. package/build/separatedArrayParser.js +73 -14
  119. package/build/separatedNonEmptyArrayParser.js +73 -14
  120. package/build/sliceBoundedParser.js +62 -5
  121. package/build/smaliParser.d.ts +7 -7
  122. package/build/smaliParser.js +185 -268
  123. package/build/smaliParser.test.js +58 -0
  124. package/build/stringEscapes.d.ts +5 -0
  125. package/build/stringEscapes.js +244 -0
  126. package/build/symbolicExpression.d.ts +29 -0
  127. package/build/symbolicExpression.js +1 -0
  128. package/build/symbolicExpressionParser.d.ts +4 -0
  129. package/build/symbolicExpressionParser.js +123 -0
  130. package/build/symbolicExpressionParser.test.d.ts +1 -0
  131. package/build/symbolicExpressionParser.test.js +289 -0
  132. package/build/terminatedArrayParser.js +113 -38
  133. package/build/terminatedArrayParser.test.js +4 -2
  134. package/build/tupleParser.d.ts +7 -15
  135. package/build/tupleParser.js +1 -0
  136. package/build/unionParser.d.ts +5 -3
  137. package/build/unionParser.js +7 -2
  138. package/build/unionParser.test-d.d.ts +1 -0
  139. package/build/unionParser.test-d.js +72 -0
  140. package/build/unionParser.test.js +10 -11
  141. package/build/zig.d.ts +280 -0
  142. package/build/zig.js +2 -0
  143. package/build/zigParser.d.ts +3 -0
  144. package/build/zigParser.js +1119 -0
  145. package/build/zigParser.test.d.ts +1 -0
  146. package/build/zigParser.test.js +1590 -0
  147. package/build/zigUnparser.d.ts +2 -0
  148. package/build/zigUnparser.js +460 -0
  149. package/build/zigUnparser.test.d.ts +1 -0
  150. package/build/zigUnparser.test.js +24 -0
  151. package/build/zipParser.js +19 -32
  152. package/build/zipUnparser.js +19 -7
  153. package/build/zipUnparser.test.js +1 -1
  154. package/node_modules-@types/s-expression/index.d.ts +5 -0
  155. package/package.json +24 -6
  156. package/src/androidPackageParser.ts +33 -60
  157. package/src/arbitraryDalvikBytecode.ts +39 -31
  158. package/src/arbitraryDalvikExecutable.ts +65 -20
  159. package/src/arbitraryJava.ts +804 -0
  160. package/src/arbitraryJavaScript.ts +410 -0
  161. package/src/arbitraryZig.ts +380 -0
  162. package/src/arrayParser.ts +1 -3
  163. package/src/backsmali.ts +35 -4
  164. package/src/bash.ts +8 -1
  165. package/src/bashParser.test.ts +258 -0
  166. package/src/bashParser.ts +180 -143
  167. package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
  168. package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
  169. package/src/dalvikBytecodeParser.test-d.ts +310 -0
  170. package/src/dalvikBytecodeParser.ts +194 -69
  171. package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
  172. package/src/dalvikBytecodeUnparser.test.ts +7 -7
  173. package/src/dalvikBytecodeUnparser.ts +31 -30
  174. package/src/dalvikExecutable.test-d.ts +132 -0
  175. package/src/dalvikExecutable.ts +3 -3
  176. package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
  177. package/src/dalvikExecutableParser.test.ts +37 -3
  178. package/src/dalvikExecutableParser.test.ts.md +163 -2
  179. package/src/dalvikExecutableParser.test.ts.snap +0 -0
  180. package/src/dalvikExecutableParser.ts +121 -139
  181. package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
  182. package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
  183. package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
  184. package/src/dalvikExecutableUnparser.test.ts +3 -2
  185. package/src/dalvikExecutableUnparser.ts +4 -4
  186. package/src/disjunctionParser.test-d.ts +105 -0
  187. package/src/disjunctionParser.ts +18 -15
  188. package/src/elementSwitchParser.test-d.ts +74 -0
  189. package/src/elementSwitchParser.ts +51 -0
  190. package/src/exactSequenceParser.test-d.ts +43 -0
  191. package/src/exactSequenceParser.ts +13 -8
  192. package/src/fetchCid.ts +2 -76
  193. package/src/index.test.ts +22 -1
  194. package/src/index.ts +7 -1
  195. package/src/inputReader.ts +53 -0
  196. package/src/java.ts +708 -0
  197. package/src/javaKeyStoreParser.ts +18 -32
  198. package/src/javaParser.test.ts +1592 -0
  199. package/src/javaParser.ts +2640 -0
  200. package/src/javaScript.ts +36 -0
  201. package/src/javaScriptParser.ts +57 -0
  202. package/src/javaScriptUnparser.test.ts +37 -0
  203. package/src/javaScriptUnparser.ts +7 -0
  204. package/src/javaUnparser.test.ts +37 -0
  205. package/src/javaUnparser.ts +640 -0
  206. package/src/jsonParser.ts +6 -27
  207. package/src/lookaheadParser.ts +2 -6
  208. package/src/negativeLookaheadParser.ts +1 -3
  209. package/src/nonEmptyArrayParser.ts +1 -3
  210. package/src/objectParser.test-d.ts +152 -0
  211. package/src/objectParser.test.ts +71 -0
  212. package/src/objectParser.ts +69 -0
  213. package/src/optionalParser.ts +1 -3
  214. package/src/parser.test.ts +151 -4
  215. package/src/parser.ts +11 -1
  216. package/src/parserConsumedSequenceParser.ts +2 -4
  217. package/src/parserContext.ts +26 -11
  218. package/src/parserError.ts +17 -3
  219. package/src/regexpParser.test.ts +78 -0
  220. package/src/regexpParser.ts +35 -3
  221. package/src/regularExpressionParser.ts +36 -37
  222. package/src/separatedArrayParser.ts +1 -3
  223. package/src/separatedNonEmptyArrayParser.ts +1 -3
  224. package/src/sliceBoundedParser.test.ts +2 -2
  225. package/src/sliceBoundedParser.ts +15 -19
  226. package/src/smaliParser.test.ts +64 -0
  227. package/src/smaliParser.test.ts.md +12 -12
  228. package/src/smaliParser.test.ts.snap +0 -0
  229. package/src/smaliParser.ts +246 -534
  230. package/src/stringEscapes.ts +253 -0
  231. package/src/symbolicExpression.ts +17 -0
  232. package/src/symbolicExpressionParser.test.ts +466 -0
  233. package/src/symbolicExpressionParser.ts +190 -0
  234. package/src/terminatedArrayParser.test.ts +9 -6
  235. package/src/terminatedArrayParser.ts +25 -29
  236. package/src/tupleParser.ts +21 -18
  237. package/src/unionParser.test-d.ts +105 -0
  238. package/src/unionParser.test.ts +18 -17
  239. package/src/unionParser.ts +28 -16
  240. package/src/zig.ts +411 -0
  241. package/src/zigParser.test.ts +1693 -0
  242. package/src/zigParser.ts +1745 -0
  243. package/src/zigUnparser.test.ts +37 -0
  244. package/src/zigUnparser.ts +615 -0
  245. package/src/zipParser.ts +20 -56
  246. package/src/zipUnparser.test.ts +1 -1
  247. package/src/zipUnparser.ts +22 -7
  248. package/tsconfig.json +2 -2
  249. package/build/exactElementSwitchParser.d.ts +0 -3
  250. package/src/exactElementSwitchParser.ts +0 -41
@@ -0,0 +1,380 @@
1
+ import * as fc from 'fast-check';
2
+ import {
3
+ type ZigRoot,
4
+ type ZigExpression,
5
+ type ZigTypeExpression,
6
+ type ZigStatement,
7
+ type ZigFnParam,
8
+ type ZigContainerMember,
9
+ type ZigBlockExpr,
10
+ } from './zig.js';
11
+
12
+ const zigKeywords = new Set([
13
+ 'addrspace', 'align', 'allowzero', 'and', 'anyframe', 'anytype',
14
+ 'asm', 'async', 'await', 'break', 'callconv', 'catch', 'comptime',
15
+ 'const', 'continue', 'defer', 'else', 'enum', 'errdefer', 'error',
16
+ 'export', 'extern', 'false', 'fn', 'for', 'if', 'inline',
17
+ 'linksection', 'noalias', 'nosuspend', 'null', 'opaque', 'or',
18
+ 'orelse', 'packed', 'pub', 'resume', 'return', 'struct',
19
+ 'suspend', 'switch', 'test', 'threadlocal', 'true', 'try',
20
+ 'undefined', 'union', 'unreachable', 'var', 'volatile', 'while',
21
+ ]);
22
+
23
+ const arbitraryZigIdentifier = fc.stringMatching(/^[a-zA-Z_][a-zA-Z0-9_]*$/).filter(
24
+ id => !zigKeywords.has(id),
25
+ );
26
+
27
+ // Leaf expressions - safe to use as operands without precedence issues
28
+
29
+ const arbitraryIdentifier: fc.Arbitrary<ZigExpression> = fc.record({
30
+ type: fc.constant('Identifier' as const),
31
+ name: arbitraryZigIdentifier,
32
+ });
33
+
34
+ const arbitraryIntegerLiteral: fc.Arbitrary<ZigExpression> = fc.record({
35
+ type: fc.constant('IntegerLiteral' as const),
36
+ value: fc.nat({ max: 999 }).map(n => String(n)),
37
+ });
38
+
39
+ const arbitraryStringLiteral: fc.Arbitrary<ZigExpression> = fc.record({
40
+ type: fc.constant('StringLiteral' as const),
41
+ value: fc.oneof(
42
+ fc.stringMatching(/^[a-zA-Z0-9 ]*$/),
43
+ fc.constantFrom('hello\nworld', 'tab\there', 'back\\slash', 'quote\ttab\nnewline'),
44
+ ),
45
+ });
46
+
47
+ const arbitraryCharLiteral: fc.Arbitrary<ZigExpression> = fc.record({
48
+ type: fc.constant('CharLiteral' as const),
49
+ value: fc.stringMatching(/^[a-zA-Z0-9]$/),
50
+ });
51
+
52
+ const arbitraryEnumLiteral: fc.Arbitrary<ZigExpression> = fc.record({
53
+ type: fc.constant('EnumLiteral' as const),
54
+ name: arbitraryZigIdentifier,
55
+ });
56
+
57
+ const arbitraryBoolLiteral: fc.Arbitrary<ZigExpression> = fc.record({
58
+ type: fc.constant('BoolLiteral' as const),
59
+ value: fc.boolean(),
60
+ });
61
+
62
+ const arbitraryNullLiteral: fc.Arbitrary<ZigExpression> = fc.constant({
63
+ type: 'NullLiteral' as const,
64
+ });
65
+
66
+ const arbitraryUndefinedLiteral: fc.Arbitrary<ZigExpression> = fc.constant({
67
+ type: 'UndefinedLiteral' as const,
68
+ });
69
+
70
+ const arbitraryLeafExpression: fc.Arbitrary<ZigExpression> = fc.oneof(
71
+ { weight: 3, arbitrary: arbitraryIdentifier },
72
+ { weight: 2, arbitrary: arbitraryIntegerLiteral },
73
+ { weight: 1, arbitrary: arbitraryStringLiteral },
74
+ { weight: 1, arbitrary: arbitraryCharLiteral },
75
+ { weight: 1, arbitrary: arbitraryEnumLiteral },
76
+ { weight: 1, arbitrary: arbitraryBoolLiteral },
77
+ { weight: 1, arbitrary: arbitraryNullLiteral },
78
+ { weight: 1, arbitrary: arbitraryUndefinedLiteral },
79
+ );
80
+
81
+ // Type expressions (simple ones for use in declarations)
82
+
83
+ const arbitrarySimpleTypeExpression: fc.Arbitrary<ZigTypeExpression> = arbitraryIdentifier as fc.Arbitrary<ZigTypeExpression>;
84
+
85
+ const arbitraryOptionalType: fc.Arbitrary<ZigTypeExpression> = fc.record({
86
+ type: fc.constant('OptionalType' as const),
87
+ child: arbitrarySimpleTypeExpression,
88
+ });
89
+
90
+ const arbitraryPointerType: fc.Arbitrary<ZigTypeExpression> = fc.record({
91
+ type: fc.constant('PointerType' as const),
92
+ size: fc.oneof(
93
+ fc.constant('one' as const),
94
+ fc.constant('many' as const),
95
+ fc.constant('slice' as const),
96
+ ),
97
+ isConst: fc.boolean(),
98
+ child: arbitrarySimpleTypeExpression,
99
+ });
100
+
101
+ const arbitraryErrorUnionType: fc.Arbitrary<ZigTypeExpression> = fc.record({
102
+ type: fc.constant('ErrorUnionType' as const),
103
+ error: arbitrarySimpleTypeExpression,
104
+ payload: arbitrarySimpleTypeExpression,
105
+ });
106
+
107
+ const arbitraryTypeExpression: fc.Arbitrary<ZigTypeExpression> = fc.oneof(
108
+ { weight: 4, arbitrary: arbitrarySimpleTypeExpression },
109
+ { weight: 1, arbitrary: arbitraryOptionalType },
110
+ { weight: 1, arbitrary: arbitraryPointerType },
111
+ { weight: 1, arbitrary: arbitraryErrorUnionType },
112
+ );
113
+
114
+ // Compound expressions (use leaf operands to avoid precedence issues)
115
+
116
+ const arbitraryBuiltinCallExpr: fc.Arbitrary<ZigExpression> = fc.record({
117
+ type: fc.constant('BuiltinCallExpr' as const),
118
+ name: arbitraryZigIdentifier,
119
+ args: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
120
+ });
121
+
122
+ const arbitraryFieldAccessExpr: fc.Arbitrary<ZigExpression> = fc.record({
123
+ type: fc.constant('FieldAccessExpr' as const),
124
+ operand: arbitraryIdentifier,
125
+ member: arbitraryZigIdentifier,
126
+ });
127
+
128
+ const arbitraryCallExpr: fc.Arbitrary<ZigExpression> = fc.record({
129
+ type: fc.constant('CallExpr' as const),
130
+ callee: arbitraryIdentifier,
131
+ args: fc.array(arbitraryLeafExpression, { maxLength: 2 }),
132
+ });
133
+
134
+ const arbitraryIndexExpr: fc.Arbitrary<ZigExpression> = fc.record({
135
+ type: fc.constant('IndexExpr' as const),
136
+ operand: arbitraryIdentifier,
137
+ index: arbitraryLeafExpression,
138
+ });
139
+
140
+ const arbitraryGroupedExpr: fc.Arbitrary<ZigExpression> = fc.record({
141
+ type: fc.constant('GroupedExpr' as const),
142
+ inner: arbitraryLeafExpression,
143
+ });
144
+
145
+ const arbitraryErrorSetExpr: fc.Arbitrary<ZigExpression> = fc.record({
146
+ type: fc.constant('ErrorSetExpr' as const),
147
+ names: fc.array(arbitraryZigIdentifier, { minLength: 1, maxLength: 3 }),
148
+ });
149
+
150
+ const arbitraryStructInitExpr: fc.Arbitrary<ZigExpression> = fc.record({
151
+ type: fc.constant('StructInitExpr' as const),
152
+ fields: fc.array(
153
+ fc.record({
154
+ type: fc.constant('StructInitField' as const),
155
+ name: arbitraryZigIdentifier,
156
+ value: arbitraryLeafExpression,
157
+ }),
158
+ { maxLength: 3 },
159
+ ),
160
+ });
161
+
162
+ const arbitraryArrayInitExpr: fc.Arbitrary<ZigExpression> = fc.record({
163
+ type: fc.constant('ArrayInitExpr' as const),
164
+ elements: fc.array(arbitraryLeafExpression, { maxLength: 3 }),
165
+ });
166
+
167
+ const arbitraryExpression: fc.Arbitrary<ZigExpression> = fc.oneof(
168
+ { weight: 5, arbitrary: arbitraryLeafExpression },
169
+ { weight: 1, arbitrary: arbitraryBuiltinCallExpr },
170
+ { weight: 1, arbitrary: arbitraryFieldAccessExpr },
171
+ { weight: 1, arbitrary: arbitraryCallExpr },
172
+ { weight: 1, arbitrary: arbitraryIndexExpr },
173
+ { weight: 1, arbitrary: arbitraryGroupedExpr },
174
+ { weight: 1, arbitrary: arbitraryErrorSetExpr },
175
+ { weight: 1, arbitrary: arbitraryStructInitExpr },
176
+ { weight: 1, arbitrary: arbitraryArrayInitExpr },
177
+ );
178
+
179
+ // Expressions safe to use in statement positions (don't start with keywords,
180
+ // which would cause the parser's while/for/block label detector to throw
181
+ // a non-recoverable error from zigIdentifierParser).
182
+ const arbitraryNonKeywordLeafExpression: fc.Arbitrary<ZigExpression> = fc.oneof(
183
+ { weight: 3, arbitrary: arbitraryIdentifier },
184
+ { weight: 2, arbitrary: arbitraryIntegerLiteral },
185
+ { weight: 1, arbitrary: arbitraryStringLiteral },
186
+ { weight: 1, arbitrary: arbitraryCharLiteral },
187
+ { weight: 1, arbitrary: arbitraryEnumLiteral },
188
+ );
189
+
190
+ const arbitraryStatementSafeExpression: fc.Arbitrary<ZigExpression> = fc.oneof(
191
+ { weight: 5, arbitrary: arbitraryNonKeywordLeafExpression },
192
+ { weight: 1, arbitrary: arbitraryBuiltinCallExpr },
193
+ { weight: 1, arbitrary: arbitraryFieldAccessExpr },
194
+ { weight: 1, arbitrary: arbitraryCallExpr },
195
+ { weight: 1, arbitrary: arbitraryIndexExpr },
196
+ { weight: 1, arbitrary: arbitraryGroupedExpr },
197
+ );
198
+
199
+ // Statements
200
+
201
+ // Expression statements are bare expressions (no wrapper)
202
+ const arbitraryExprStmt: fc.Arbitrary<ZigStatement> = arbitraryStatementSafeExpression as fc.Arbitrary<ZigStatement>;
203
+
204
+ const arbitraryReturnStmt: fc.Arbitrary<ZigStatement> = fc.oneof(
205
+ fc.constant({ type: 'ReturnStmt' as const }),
206
+ fc.record({
207
+ type: fc.constant('ReturnStmt' as const),
208
+ value: arbitraryLeafExpression,
209
+ }),
210
+ );
211
+
212
+ const arbitraryBreakStmt: fc.Arbitrary<ZigStatement> = fc.constant({
213
+ type: 'BreakStmt' as const,
214
+ });
215
+
216
+ const arbitraryContinueStmt: fc.Arbitrary<ZigStatement> = fc.constant({
217
+ type: 'ContinueStmt' as const,
218
+ });
219
+
220
+ const arbitraryVarDeclStmt: fc.Arbitrary<ZigStatement> = fc.record({
221
+ type: fc.constant('VarDecl' as const),
222
+ isConst: fc.boolean(),
223
+ isPub: fc.constant(false),
224
+ isExtern: fc.constant(false),
225
+ isComptime: fc.constant(false),
226
+ isThreadlocal: fc.constant(false),
227
+ name: arbitraryZigIdentifier,
228
+ }).chain(base =>
229
+ fc.oneof(
230
+ // With type and init
231
+ fc.record({
232
+ typeExpr: arbitraryTypeExpression,
233
+ initExpr: arbitraryLeafExpression,
234
+ }).map(extra => ({ ...base, ...extra })),
235
+ // With init only
236
+ fc.record({
237
+ initExpr: arbitraryLeafExpression,
238
+ }).map(extra => ({ ...base, ...extra })),
239
+ // With type only (extern style)
240
+ fc.record({
241
+ typeExpr: arbitraryTypeExpression,
242
+ }).map(extra => ({ ...base, isExtern: true, ...extra })),
243
+ ),
244
+ );
245
+
246
+ const arbitraryAssignStmt: fc.Arbitrary<ZigStatement> = fc.record({
247
+ type: fc.constant('AssignStmt' as const),
248
+ target: arbitraryIdentifier as fc.Arbitrary<ZigExpression>,
249
+ operator: fc.oneof(
250
+ fc.constant('=' as const),
251
+ fc.constant('+=' as const),
252
+ fc.constant('-=' as const),
253
+ fc.constant('*=' as const),
254
+ ),
255
+ value: arbitraryLeafExpression,
256
+ });
257
+
258
+ const arbitraryBlockStmt: fc.Arbitrary<ZigStatement> = fc.record({
259
+ type: fc.constant('BlockExpr' as const),
260
+ statements: fc.constant([] as ZigStatement[]),
261
+ }) as fc.Arbitrary<ZigStatement>;
262
+
263
+ const arbitraryDeferStmt: fc.Arbitrary<ZigStatement> = fc.record({
264
+ type: fc.constant('DeferStmt' as const),
265
+ isErrdefer: fc.boolean(),
266
+ body: arbitraryStatementSafeExpression as fc.Arbitrary<ZigStatement>,
267
+ });
268
+
269
+ const arbitraryStatement: fc.Arbitrary<ZigStatement> = fc.oneof(
270
+ { weight: 2, arbitrary: arbitraryExprStmt },
271
+ { weight: 2, arbitrary: arbitraryVarDeclStmt },
272
+ { weight: 2, arbitrary: arbitraryReturnStmt },
273
+ { weight: 1, arbitrary: arbitraryAssignStmt },
274
+ { weight: 1, arbitrary: arbitraryBreakStmt },
275
+ { weight: 1, arbitrary: arbitraryContinueStmt },
276
+ { weight: 1, arbitrary: arbitraryBlockStmt },
277
+ { weight: 1, arbitrary: arbitraryDeferStmt },
278
+ );
279
+
280
+ // Function parameters
281
+
282
+ const arbitraryFnParam: fc.Arbitrary<ZigFnParam> = fc.oneof(
283
+ // Named parameter
284
+ fc.record({
285
+ type: fc.constant('FnParam' as const),
286
+ name: arbitraryZigIdentifier,
287
+ isComptime: fc.constant(false),
288
+ isNoalias: fc.constant(false),
289
+ typeExpr: arbitraryTypeExpression,
290
+ }),
291
+ // Unnamed parameter
292
+ fc.record({
293
+ type: fc.constant('FnParam' as const),
294
+ isComptime: fc.constant(false),
295
+ isNoalias: fc.constant(false),
296
+ typeExpr: arbitraryTypeExpression,
297
+ }),
298
+ );
299
+
300
+ // Block expression
301
+
302
+ const arbitraryBlockExpr: fc.Arbitrary<ZigBlockExpr> = fc.record({
303
+ type: fc.constant('BlockExpr' as const),
304
+ statements: fc.array(arbitraryStatement, { maxLength: 3 }),
305
+ });
306
+
307
+ // Top-level declarations
308
+
309
+ const arbitraryFnDecl: fc.Arbitrary<ZigContainerMember> = fc.oneof(
310
+ // Function with body
311
+ fc.record({
312
+ type: fc.constant('FnDecl' as const),
313
+ isPub: fc.boolean(),
314
+ isExtern: fc.constant(false),
315
+ isExport: fc.constant(false),
316
+ isInline: fc.constant(false),
317
+ isComptime: fc.constant(false),
318
+ name: arbitraryZigIdentifier,
319
+ params: fc.array(arbitraryFnParam, { maxLength: 2 }),
320
+ returnType: arbitraryTypeExpression,
321
+ body: arbitraryBlockExpr,
322
+ }),
323
+ // Extern function (no body)
324
+ fc.record({
325
+ type: fc.constant('FnDecl' as const),
326
+ isPub: fc.boolean(),
327
+ isExtern: fc.constant(true),
328
+ isExport: fc.constant(false),
329
+ isInline: fc.constant(false),
330
+ isComptime: fc.constant(false),
331
+ name: arbitraryZigIdentifier,
332
+ params: fc.array(arbitraryFnParam, { maxLength: 2 }),
333
+ returnType: arbitraryTypeExpression,
334
+ }),
335
+ );
336
+
337
+ const arbitraryVarDecl: fc.Arbitrary<ZigContainerMember> = fc.record({
338
+ type: fc.constant('VarDecl' as const),
339
+ isConst: fc.boolean(),
340
+ isPub: fc.boolean(),
341
+ isExtern: fc.constant(false),
342
+ isComptime: fc.constant(false),
343
+ isThreadlocal: fc.constant(false),
344
+ name: arbitraryZigIdentifier,
345
+ }).chain(base =>
346
+ fc.oneof(
347
+ // With type and init
348
+ fc.record({
349
+ typeExpr: arbitraryTypeExpression,
350
+ initExpr: arbitraryLeafExpression,
351
+ }).map(extra => ({ ...base, ...extra })),
352
+ // With init only
353
+ fc.record({
354
+ initExpr: arbitraryLeafExpression,
355
+ }).map(extra => ({ ...base, ...extra })),
356
+ ),
357
+ );
358
+
359
+ const arbitraryTestDecl: fc.Arbitrary<ZigContainerMember> = fc.oneof(
360
+ fc.record({
361
+ type: fc.constant('TestDecl' as const),
362
+ name: fc.stringMatching(/^[a-zA-Z0-9 ]+$/),
363
+ body: arbitraryBlockExpr,
364
+ }),
365
+ fc.record({
366
+ type: fc.constant('TestDecl' as const),
367
+ body: arbitraryBlockExpr,
368
+ }),
369
+ );
370
+
371
+ const arbitraryContainerMember: fc.Arbitrary<ZigContainerMember> = fc.oneof(
372
+ { weight: 3, arbitrary: arbitraryFnDecl },
373
+ { weight: 3, arbitrary: arbitraryVarDecl },
374
+ { weight: 1, arbitrary: arbitraryTestDecl },
375
+ );
376
+
377
+ export const arbitraryZigRoot: fc.Arbitrary<ZigRoot> = fc.record({
378
+ type: fc.constant('Root' as const),
379
+ members: fc.array(arbitraryContainerMember, { minLength: 1, maxLength: 4 }),
380
+ });
@@ -8,7 +8,7 @@ export const createArrayParser = <ElementOutput, Sequence>(
8
8
  const elements: ElementOutput[] = [];
9
9
 
10
10
  while (true) {
11
- const elementParserContext = parserContext.lookahead();
11
+ using elementParserContext = parserContext.lookahead();
12
12
  const initialPosition = elementParserContext.position;
13
13
  try {
14
14
  const element = await elementParser(elementParserContext);
@@ -24,8 +24,6 @@ export const createArrayParser = <ElementOutput, Sequence>(
24
24
  }
25
25
 
26
26
  throw error;
27
- } finally {
28
- elementParserContext.dispose();
29
27
  }
30
28
  }
31
29
  };
package/src/backsmali.ts CHANGED
@@ -7,19 +7,22 @@ import { smaliClass } from './smali.js';
7
7
  export async function baksmaliClass(
8
8
  dexStream: Uint8Array | AsyncIterable<Uint8Array>,
9
9
  smaliFilePath: string,
10
+ dexEntry?: string,
10
11
  ): Promise<string> {
11
12
  const inputFilePath = temporaryFile();
12
13
  const outputDirectoryPath = temporaryDirectory();
13
14
 
14
15
  await fs.writeFile(inputFilePath, dexStream);
15
16
 
17
+ const inputPath = dexEntry ? `${inputFilePath}/${dexEntry}` : inputFilePath;
18
+
16
19
  await execa('baksmali', [
17
20
  'disassemble',
18
21
  '--classes',
19
22
  'L' + smaliFilePath + ';',
20
23
  '--output',
21
24
  outputDirectoryPath,
22
- inputFilePath,
25
+ inputPath,
23
26
  ]);
24
27
 
25
28
  await fs.unlink(inputFilePath);
@@ -38,20 +41,23 @@ export async function baksmaliClass(
38
41
  export async function backsmaliSmaliIsolateClass(
39
42
  dexStream: Uint8Array | AsyncIterable<Uint8Array>,
40
43
  smaliFilePath: string,
44
+ dexEntry?: string,
41
45
  ): Promise<Uint8Array> {
42
- const smali = await baksmaliClass(dexStream, smaliFilePath);
46
+ const smali = await baksmaliClass(dexStream, smaliFilePath, dexEntry);
43
47
  return smaliClass(smali);
44
48
  }
45
49
 
46
- export async function baksmaliListClasses(dexStream: Uint8Array | AsyncIterable<Uint8Array>): Promise<string[]> {
50
+ export async function baksmaliListClasses(dexStream: Uint8Array | AsyncIterable<Uint8Array>, dexEntry?: string): Promise<string[]> {
47
51
  const inputFilePath = temporaryFile();
48
52
 
49
53
  await fs.writeFile(inputFilePath, dexStream);
50
54
 
55
+ const inputPath = dexEntry ? `${inputFilePath}/${dexEntry}` : inputFilePath;
56
+
51
57
  const result = await execa('baksmali', [
52
58
  'list',
53
59
  'classes',
54
- inputFilePath,
60
+ inputPath,
55
61
  ]);
56
62
 
57
63
  await fs.unlink(inputFilePath);
@@ -72,3 +78,28 @@ export async function baksmaliListClasses(dexStream: Uint8Array | AsyncIterable<
72
78
 
73
79
  return classes;
74
80
  }
81
+
82
+ export async function baksmaliListDexFiles(apkStream: Uint8Array | AsyncIterable<Uint8Array>): Promise<string[]> {
83
+ const inputFilePath = temporaryFile();
84
+
85
+ await fs.writeFile(inputFilePath, apkStream);
86
+
87
+ const result = await execa('baksmali', [
88
+ 'list',
89
+ 'dex',
90
+ inputFilePath,
91
+ ]);
92
+
93
+ await fs.unlink(inputFilePath);
94
+
95
+ if (result.stderr) {
96
+ throw new Error(`baksmali error: ${result.stderr}`);
97
+ }
98
+
99
+ const dexFiles = result.stdout
100
+ .split('\n')
101
+ .filter(line => line.trim())
102
+ .map(line => line.trim());
103
+
104
+ return dexFiles;
105
+ }
package/src/bash.ts CHANGED
@@ -11,7 +11,8 @@ export type BashWordPart =
11
11
  | BashWordPartVariableBraced
12
12
  | BashWordPartCommandSubstitution
13
13
  | BashWordPartBacktickSubstitution
14
- | BashWordPartArithmeticExpansion;
14
+ | BashWordPartArithmeticExpansion
15
+ | BashWordPartProcessSubstitution;
15
16
 
16
17
  export type BashWordPartLiteral = {
17
18
  type: 'literal';
@@ -55,6 +56,12 @@ export type BashWordPartArithmeticExpansion = {
55
56
  expression: string;
56
57
  };
57
58
 
59
+ export type BashWordPartProcessSubstitution = {
60
+ type: 'processSubstitution';
61
+ direction: '<' | '>';
62
+ command: BashCommand;
63
+ };
64
+
58
65
  // Redirect: file descriptor operations
59
66
  export type BashRedirect = {
60
67
  fd?: number;