@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
@@ -1,10 +1,12 @@
1
1
  import invariant from 'invariant';
2
2
  import { type Simplify } from 'type-fest';
3
- import { type DalvikBytecode, type DalvikBytecodeOperation, dalvikBytecodeOperationCompanion } from './dalvikBytecodeParser.js';
3
+ import { type RawDalvikBytecodeOperation, rawDalvikBytecodeOperationCompanion } from './dalvikBytecodeParser.js';
4
+ import { type DalvikBytecodeOperation, type DalvikBytecode, getOperationSizeInCodeUnits } from './dalvikBytecodeParser/addressConversion.js';
4
5
  import {
5
6
  type DalvikExecutableAccessFlags, dalvikExecutableAccessFlagsDefault, type DalvikExecutableAnnotation, type DalvikExecutableClassAnnotations, type DalvikExecutableClassData, type DalvikExecutableClassDefinition, type DalvikExecutableClassMethodAnnotation, type DalvikExecutableClassParameterAnnotation, type DalvikExecutableCode, type DalvikExecutableDebugInfo, type DalvikExecutableEncodedValue, type DalvikExecutableField, dalvikExecutableFieldEquals, type DalvikExecutableFieldWithAccess, type DalvikExecutableMethod, dalvikExecutableMethodEquals, type DalvikExecutableMethodWithAccess, type DalvikExecutablePrototype, isDalvikExecutableField, isDalvikExecutableMethod,
6
7
  } from './dalvikExecutable.js';
7
8
  import { createExactSequenceParser } from './exactSequenceParser.js';
9
+ import { createObjectParser } from './objectParser.js';
8
10
  import { cloneParser, type Parser, setParserName } from './parser.js';
9
11
  import { type ParserContext } from './parserContext.js';
10
12
  import { promiseCompose } from './promiseCompose.js';
@@ -18,16 +20,13 @@ import { createNegativeLookaheadParser } from './negativeLookaheadParser.js';
18
20
  import { createSeparatedArrayParser } from './separatedArrayParser.js';
19
21
  import { smaliMemberNameParser, smaliTypeDescriptorParser } from './dalvikExecutableParser/stringSyntaxParser.js';
20
22
  import { createDisjunctionParser } from './disjunctionParser.js';
21
- import { formatSizes } from './dalvikBytecodeParser/formatSizes.js';
22
- import { operationFormats } from './dalvikBytecodeParser/operationFormats.js';
23
23
  import { createSeparatedNonEmptyArrayParser } from './separatedNonEmptyArrayParser.js';
24
24
  import { parserCreatorCompose } from './parserCreatorCompose.js';
25
25
  import { type IndexIntoMethodIds } from './dalvikExecutableParser/typedNumbers.js';
26
- import { createDebugLogInputParser } from './debugLogInputParser.js';
27
- import { createDebugLogParser } from './debugLogParser.js';
28
26
  import { createElementParser } from './elementParser.js';
29
27
  import { createTerminatedArrayParser } from './terminatedArrayParser.js';
30
28
  import { createParserAccessorParser } from './parserAccessorParser.js';
29
+ import { createRegExpParser } from './regexpParser.js';
31
30
 
32
31
  function shortyFromLongy(longy: string): string {
33
32
  if (longy.startsWith('[')) {
@@ -37,30 +36,6 @@ function shortyFromLongy(longy: string): string {
37
36
  return longy.slice(0, 1);
38
37
  }
39
38
 
40
- function getOperationFormatSize(operation: SmaliCodeOperation): number {
41
- if (operation.operation === 'packed-switch-payload') {
42
- return (operation.branchOffsetIndices.length * 2) + 4;
43
- }
44
-
45
- if (operation.operation === 'sparse-switch-payload') {
46
- return (operation.branchOffsetIndices.length * 4) + 2;
47
- }
48
-
49
- if (operation.operation === 'fill-array-data-payload') {
50
- const dataSize = operation.data.length; // in bytes
51
- const paddingSize = dataSize % 2; // 1 if odd, 0 if even
52
- const totalBytes = 8 + dataSize + paddingSize; // header (8 bytes) + data + padding
53
- return totalBytes / 2; // Convert to code units (1 code unit = 2 bytes)
54
- }
55
-
56
- const operationFormat = operationFormats[operation.operation as keyof typeof operationFormats];
57
- invariant(operationFormat, 'Unknown operation format for "%s" (operation: %o)', operation.operation, operation);
58
-
59
- const operationSize = formatSizes[operationFormat];
60
- invariant(operationSize, 'Unknown operation size for format %s of operation %s', operationFormat, operation.operation);
61
-
62
- return operationSize;
63
- }
64
39
 
65
40
  // Helper function to convert raw annotation element values to tagged encoded values
66
41
  function convertToTaggedEncodedValue(wrappedValue: SmaliAnnotationElementValue): DalvikExecutableEncodedValue {
@@ -166,7 +141,7 @@ function convertToTaggedEncodedValue(wrappedValue: SmaliAnnotationElementValue):
166
141
  }
167
142
 
168
143
 
169
- const smaliNewlinesParser: Parser<void, string> = promiseCompose(
144
+ const smaliNewlinesParser: Parser<undefined, string> = promiseCompose(
170
145
  createNonEmptyArrayParser(createExactSequenceParser('\n')),
171
146
  _newlines => undefined,
172
147
  );
@@ -188,31 +163,11 @@ const smaliIndentationParser: Parser<void, string> = promiseCompose(
188
163
  export const smaliCommentParser: Parser<string, string> = promiseCompose(
189
164
  createTupleParser([
190
165
  createExactSequenceParser('#'),
191
- (async (parserContext: ParserContext<string, string>) => {
192
- const characters: string[] = [];
193
-
194
- while (true) {
195
- const character = await parserContext.peek(0);
196
-
197
- parserContext.invariant(character !== undefined, 'Unexpected end of input');
198
-
199
- invariant(character !== undefined, 'Unexpected end of input');
200
-
201
- if (character !== '\n') {
202
- characters.push(character);
203
-
204
- parserContext.skip(1);
205
-
206
- continue;
207
- }
208
-
209
- parserContext.skip(1);
210
-
211
- break;
212
- }
213
-
214
- return characters.join('');
215
- }),
166
+ promiseCompose(
167
+ createRegExpParser(/[^\n]*/),
168
+ match => match[0],
169
+ ),
170
+ createExactSequenceParser('\n'),
216
171
  ]),
217
172
  ([
218
173
  _hash,
@@ -232,7 +187,7 @@ const smaliIndentedCommentParser: Parser<string, string> = promiseCompose(
232
187
  );
233
188
 
234
189
  const smaliCommentsOrNewlinesParser: Parser<string[], string> = promiseCompose(
235
- createArrayParser(createUnionParser<undefined | string, string, string>([
190
+ createArrayParser(createUnionParser([
236
191
  smaliNewlinesParser,
237
192
  smaliIndentedCommentParser,
238
193
  smaliCommentParser,
@@ -243,7 +198,7 @@ const smaliCommentsOrNewlinesParser: Parser<string[], string> = promiseCompose(
243
198
  const smaliLineEndPraser: Parser<undefined | string, string> = promiseCompose(
244
199
  createTupleParser([
245
200
  createOptionalParser(smaliWhitespaceParser),
246
- createUnionParser<undefined | string, string, string>([
201
+ createUnionParser([
247
202
  smaliNewlinesParser,
248
203
  smaliCommentParser,
249
204
  ]),
@@ -254,89 +209,31 @@ const smaliLineEndPraser: Parser<undefined | string, string> = promiseCompose(
254
209
  ]) => newlineOrComment,
255
210
  );
256
211
 
257
- const smaliIdentifierParser: Parser<string, string> = async (parserContext: ParserContext<string, string>) => {
258
- const characters: string[] = [];
259
-
260
- while (true) {
261
- const character = await parserContext.peek(0);
262
-
263
- parserContext.invariant(character !== undefined, 'Unexpected end of input');
264
-
265
- invariant(character !== undefined, 'Unexpected end of input');
266
-
267
- if (
268
- character === '_'
269
- || (
270
- character >= 'a' && character <= 'z'
271
- )
272
- || (
273
- character >= 'A' && character <= 'Z'
274
- )
275
- || (
276
- character >= '0' && character <= '9'
277
- )
278
- ) {
279
- parserContext.skip(1);
280
-
281
- characters.push(character);
282
-
283
- continue;
284
- }
285
-
286
- parserContext.invariant(characters.length > 0, 'Expected at least one character');
287
-
288
- break;
289
- }
290
-
291
- return characters.join('');
292
- };
212
+ const smaliIdentifierParser: Parser<string, string> = promiseCompose(
213
+ createRegExpParser(/[a-zA-Z0-9_]+/),
214
+ match => match[0],
215
+ );
293
216
 
294
217
  setParserName(smaliIdentifierParser, 'smaliIdentifierParser');
295
218
 
296
- const elementParser = createElementParser<string>();
297
-
298
219
  const smaliHexNumberParser: Parser<number | bigint, string> = promiseCompose(
299
- createTupleParser([
300
- createOptionalParser(createExactSequenceParser('-')),
301
- createExactSequenceParser('0x'),
302
- createArrayParser(parserCreatorCompose(
303
- () => elementParser,
304
- character => async parserContext => {
305
- parserContext.invariant(
306
- (
307
- (character >= '0' && character <= '9')
308
- || (character >= 'a' && character <= 'f')
309
- || (character >= 'A' && character <= 'F')
310
- ),
311
- 'Expected "0" to "9", "a" to "f", "A" to "F", got "%s"',
312
- character,
313
- );
220
+ createRegExpParser(/-?0x([0-9a-fA-F]+)(L)?/),
221
+ match => {
222
+ const hexDigits = match[1]!;
223
+ const optionalL = match[2];
314
224
 
315
- return character;
316
- },
317
- )()),
318
- createOptionalParser(createExactSequenceParser('L')),
319
- ]),
320
- ([
321
- optionalMinus,
322
- _0x,
323
- valueCharacters,
324
- optionalL,
325
- ]) => {
326
- const value = valueCharacters.join('');
327
-
328
225
  // If the 'L' suffix is present, use BigInt for long values
329
226
  if (optionalL) {
330
- const sign = optionalMinus ? -1n : 1n;
331
- return sign * BigInt('0x' + value);
227
+ const sign = match[0].startsWith('-') ? -1n : 1n;
228
+ return sign * BigInt('0x' + hexDigits);
332
229
  }
333
-
334
- const sign = optionalMinus ? -1 : 1;
335
- return sign * Number.parseInt(value, 16);
230
+
231
+ const sign = match[0].startsWith('-') ? -1 : 1;
232
+ return sign * Number.parseInt(hexDigits, 16);
336
233
  },
337
234
  );
338
235
 
339
- const smaliNumberParser = createUnionParser<number, string>([
236
+ const smaliNumberParser = createUnionParser([
340
237
  promiseCompose(
341
238
  createTupleParser([
342
239
  createNegativeLookaheadParser(createUnionParser([
@@ -383,7 +280,7 @@ const smaliNumberParser = createUnionParser<number, string>([
383
280
  setParserName(smaliNumberParser, 'smaliNumberParser');
384
281
 
385
282
  // Parser for field initial values that can include BigInt
386
- const smaliFieldValueParser = createUnionParser<number | bigint, string>([
283
+ const smaliFieldValueParser = createUnionParser([
387
284
  promiseCompose(
388
285
  createTupleParser([
389
286
  createNegativeLookaheadParser(createUnionParser([
@@ -424,7 +321,7 @@ const smaliQuotedStringParser: Parser<string, string> = promiseCompose(
424
321
  const smaliCharacterLiteralParser: Parser<number, string> = promiseCompose(
425
322
  createTupleParser([
426
323
  createExactSequenceParser('\''),
427
- createDisjunctionParser<string, string>([
324
+ createDisjunctionParser([
428
325
  // Handle escape sequences (must come before regular characters)
429
326
  promiseCompose(createExactSequenceParser(String.raw`\\`), () => '\\'),
430
327
  promiseCompose(createExactSequenceParser(String.raw`\'`), () => '\''),
@@ -477,9 +374,9 @@ const smaliIdentifierContinuationParser: Parser<string, string> = async (parserC
477
374
  setParserName(smaliIdentifierContinuationParser, 'smaliIdentifierContinuationParser');
478
375
 
479
376
  // Helper to create an access flag parser with word boundary check
480
- const createAccessFlagParser = (keyword: string): Parser<typeof keyword, string> => promiseCompose(
377
+ const createAccessFlagParser = <const T extends string>(keyword: T): Parser<T, string> => promiseCompose(
481
378
  createTupleParser([
482
- createExactSequenceParser(keyword),
379
+ createExactSequenceParser(keyword) as Parser<T, string>,
483
380
  createNegativeLookaheadParser(smaliIdentifierContinuationParser),
484
381
  ]),
485
382
  ([flag]) => flag,
@@ -487,7 +384,7 @@ const createAccessFlagParser = (keyword: string): Parser<typeof keyword, string>
487
384
 
488
385
  const smaliAccessFlagsParser: Parser<DalvikExecutableAccessFlags, string> = promiseCompose(
489
386
  createSeparatedArrayParser(
490
- createUnionParser<keyof DalvikExecutableAccessFlags | 'declared-synchronized', string>([
387
+ createUnionParser([
491
388
  createAccessFlagParser('public'),
492
389
  createAccessFlagParser('protected'),
493
390
  createAccessFlagParser('private'),
@@ -554,20 +451,11 @@ const smaliClassDeclarationParser: Parser<Pick<DalvikExecutableClassDefinition<u
554
451
 
555
452
  setParserName(smaliClassDeclarationParser, 'smaliClassDeclarationParser');
556
453
 
557
- const smaliSuperDeclarationParser: Parser<Pick<DalvikExecutableClassDefinition<unknown>, 'superclass'>, string> = promiseCompose(
558
- createTupleParser([
559
- createExactSequenceParser('.super '),
560
- smaliTypeDescriptorParser,
561
- smaliLineEndPraser,
562
- ]),
563
- ([
564
- _super,
565
- superclass,
566
- _newline,
567
- ]) => ({
568
- superclass,
569
- }),
570
- );
454
+ const smaliSuperDeclarationParser: Parser<Pick<DalvikExecutableClassDefinition<unknown>, 'superclass'>, string> = createObjectParser({
455
+ _super: createExactSequenceParser('.super '),
456
+ superclass: smaliTypeDescriptorParser,
457
+ _newline: smaliLineEndPraser,
458
+ });
571
459
 
572
460
  setParserName(smaliSuperDeclarationParser, 'smaliSuperDeclarationParser');
573
461
 
@@ -586,20 +474,11 @@ const smaliInterfaceDeclarationParser: Parser<string, string> = promiseCompose(
586
474
 
587
475
  setParserName(smaliInterfaceDeclarationParser, 'smaliInterfaceDeclarationParser');
588
476
 
589
- const smaliSourceDeclarationParser: Parser<Pick<DalvikExecutableClassDefinition<unknown>, 'sourceFile'>, string> = promiseCompose(
590
- createTupleParser([
591
- createExactSequenceParser('.source '),
592
- smaliQuotedStringParser,
593
- smaliLineEndPraser,
594
- ]),
595
- ([
596
- _source,
597
- sourceFile,
598
- _newline,
599
- ]) => ({
600
- sourceFile,
601
- }),
602
- );
477
+ const smaliSourceDeclarationParser: Parser<Pick<DalvikExecutableClassDefinition<unknown>, 'sourceFile'>, string> = createObjectParser({
478
+ _source: createExactSequenceParser('.source '),
479
+ sourceFile: smaliQuotedStringParser,
480
+ _newline: smaliLineEndPraser,
481
+ });
603
482
 
604
483
  // Wrapper type to distinguish different value types in smali annotation elements
605
484
  type SmaliAnnotationElementValue =
@@ -613,28 +492,14 @@ type SmaliAnnotationElement = {
613
492
  value: SmaliAnnotationElementValue;
614
493
  };
615
494
 
616
- const smaliEnumValueParser: Parser<DalvikExecutableField, string> = promiseCompose(
617
- createTupleParser([
618
- createExactSequenceParser('.enum '),
619
- smaliTypeDescriptorParser,
620
- createExactSequenceParser('->'),
621
- smaliMemberNameParser,
622
- createExactSequenceParser(':'),
623
- smaliTypeDescriptorParser,
624
- ]),
625
- ([
626
- _enum,
627
- classType,
628
- _arrow,
629
- fieldName,
630
- _colon,
631
- fieldType,
632
- ]) => ({
633
- class: classType,
634
- type: fieldType,
635
- name: fieldName,
636
- }),
637
- );
495
+ const smaliEnumValueParser: Parser<DalvikExecutableField, string> = createObjectParser({
496
+ _enum: createExactSequenceParser('.enum '),
497
+ class: smaliTypeDescriptorParser,
498
+ _arrow: createExactSequenceParser('->'),
499
+ name: smaliMemberNameParser,
500
+ _colon: createExactSequenceParser(':'),
501
+ type: smaliTypeDescriptorParser,
502
+ });
638
503
 
639
504
  setParserName(smaliEnumValueParser, 'smaliEnumValueParser');
640
505
 
@@ -665,24 +530,12 @@ const smaliMethodPrototypeParser: Parser<DalvikExecutablePrototype, string> = pr
665
530
 
666
531
  setParserName(smaliMethodPrototypeParser, 'smaliMethodPrototypeParser');
667
532
 
668
- const smaliParametersMethodParser: Parser<DalvikExecutableMethod, string> = promiseCompose(
669
- createTupleParser([
670
- smaliTypeDescriptorParser,
671
- createExactSequenceParser('->'),
672
- smaliMemberNameParser,
673
- smaliMethodPrototypeParser,
674
- ]),
675
- ([
676
- classPath,
677
- _separator,
678
- methodName,
679
- prototype,
680
- ]) => ({
681
- class: classPath,
682
- prototype,
683
- name: methodName,
684
- }),
685
- );
533
+ const smaliParametersMethodParser: Parser<DalvikExecutableMethod, string> = createObjectParser({
534
+ class: smaliTypeDescriptorParser,
535
+ _separator: createExactSequenceParser('->'),
536
+ name: smaliMemberNameParser,
537
+ prototype: smaliMethodPrototypeParser,
538
+ });
686
539
 
687
540
  setParserName(smaliParametersMethodParser, 'smaliParametersMethodParser');
688
541
 
@@ -700,46 +553,49 @@ const smaliAnnotationElementParser: Parser<SmaliAnnotationElement, string> = pro
700
553
  smaliIdentifierParser,
701
554
  createExactSequenceParser(' = '),
702
555
  createDisjunctionParser([
703
- promiseCompose(
704
- createParserAccessorParser(() => smaliSubannotationParser),
705
- value => ({ kind: 'raw' as const, value }),
706
- ),
707
- promiseCompose(
708
- smaliEnumValueParser,
709
- value => ({ kind: 'enum' as const, value }),
710
- ),
711
- promiseCompose(
712
- smaliQuotedStringParser,
713
- value => ({ kind: 'string' as const, value }),
714
- ),
715
- promiseCompose(
716
- smaliParametersMethodParser,
717
- value => ({ kind: 'raw' as const, value }),
718
- ),
719
- promiseCompose(
720
- smaliTypeDescriptorParser,
721
- value => ({ kind: 'type' as const, value }),
722
- ),
723
- promiseCompose(
724
- smaliNumberParser,
725
- value => ({ kind: 'raw' as const, value }),
726
- ),
727
- promiseCompose(
728
- createExactSequenceParser('true'),
729
- () => ({ kind: 'raw' as const, value: true }),
730
- ),
731
- promiseCompose(
732
- createExactSequenceParser('false'),
733
- () => ({ kind: 'raw' as const, value: false }),
734
- ),
556
+ createObjectParser({
557
+ kind: 'raw' as const,
558
+ value: createParserAccessorParser(() => smaliSubannotationParser),
559
+ }),
560
+ createObjectParser({
561
+ kind: 'enum' as const,
562
+ value: smaliEnumValueParser,
563
+ }),
564
+ createObjectParser({
565
+ kind: 'string' as const,
566
+ value: smaliQuotedStringParser,
567
+ }),
568
+ createObjectParser({
569
+ kind: 'raw' as const,
570
+ value: smaliParametersMethodParser,
571
+ }),
572
+ createObjectParser({
573
+ kind: 'type' as const,
574
+ value: smaliTypeDescriptorParser,
575
+ }),
576
+ createObjectParser({
577
+ kind: 'raw' as const,
578
+ value: smaliNumberParser,
579
+ }),
580
+ createObjectParser({
581
+ kind: 'raw' as const,
582
+ value: true as const,
583
+ _true: createExactSequenceParser('true'),
584
+ }),
585
+ createObjectParser({
586
+ kind: 'raw' as const,
587
+ value: false as const,
588
+ _false: createExactSequenceParser('false'),
589
+ }),
735
590
  promiseCompose(
736
591
  createExactSequenceParser('null'),
737
592
  () => ({ kind: 'raw' as const, value: null }),
738
593
  ),
739
- promiseCompose(
740
- createExactSequenceParser('{}'),
741
- () => ({ kind: 'raw' as const, value: [] }),
742
- ),
594
+ createObjectParser({
595
+ kind: 'raw' as const,
596
+ value: [] as const,
597
+ _emptyBraces: createExactSequenceParser('{}'),
598
+ }),
743
599
  promiseCompose(
744
600
  createTupleParser([
745
601
  createExactSequenceParser('{\n'),
@@ -862,27 +718,14 @@ const smaliAnnotationElementParser: Parser<SmaliAnnotationElement, string> = pro
862
718
  setParserName(smaliAnnotationElementParser, 'smaliAnnotationElementParser');
863
719
 
864
720
  // Now define the subannotation parser
865
- smaliSubannotationParser = promiseCompose(
866
- createTupleParser([
867
- createExactSequenceParser('.subannotation '),
868
- smaliTypeDescriptorParser,
869
- smaliLineEndPraser,
870
- createArrayParser(smaliAnnotationElementParser),
871
- smaliIndentationParser,
872
- createExactSequenceParser('.end subannotation'),
873
- ]),
874
- ([
875
- _subannotation,
876
- type,
877
- _newline,
878
- elements,
879
- _indentation,
880
- _endSubannotation,
881
- ]) => ({
882
- type,
883
- elements,
884
- }),
885
- );
721
+ smaliSubannotationParser = createObjectParser({
722
+ _subannotation: createExactSequenceParser('.subannotation '),
723
+ type: smaliTypeDescriptorParser,
724
+ _newline: smaliLineEndPraser,
725
+ elements: createArrayParser(smaliAnnotationElementParser),
726
+ _indentation: smaliIndentationParser,
727
+ _endSubannotation: createExactSequenceParser('.end subannotation'),
728
+ });
886
729
 
887
730
  setParserName(smaliSubannotationParser, 'smaliSubannotationParser');
888
731
 
@@ -892,38 +735,21 @@ type SmaliAnnotation = {
892
735
  visibility: 'build' | 'runtime' | 'system';
893
736
  };
894
737
 
895
- export const smaliAnnotationParser: Parser<SmaliAnnotation, string> = promiseCompose(
896
- createTupleParser([
897
- smaliIndentationParser,
898
- createExactSequenceParser('.annotation '),
899
- createUnionParser<'build' | 'runtime' | 'system', string, string>([
900
- createExactSequenceParser('build'),
901
- createExactSequenceParser('runtime'),
902
- createExactSequenceParser('system'),
903
- ]),
904
- smaliSingleWhitespaceParser,
905
- smaliTypeDescriptorParser,
906
- smaliLineEndPraser,
907
- createArrayParser(smaliAnnotationElementParser),
908
- smaliIndentationParser,
909
- createExactSequenceParser('.end annotation\n'),
738
+ export const smaliAnnotationParser: Parser<SmaliAnnotation, string> = createObjectParser({
739
+ _indentation0: smaliIndentationParser,
740
+ _annotation: createExactSequenceParser('.annotation '),
741
+ visibility: createUnionParser([
742
+ createExactSequenceParser('build' as const),
743
+ createExactSequenceParser('runtime' as const),
744
+ createExactSequenceParser('system' as const),
910
745
  ]),
911
- ([
912
- _indentation0,
913
- _annotation,
914
- visibility,
915
- _space,
916
- type,
917
- _newline,
918
- elements,
919
- _indentation1,
920
- _endAnnotation,
921
- ]) => ({
922
- type,
923
- elements,
924
- visibility,
925
- }),
926
- );
746
+ _space: smaliSingleWhitespaceParser,
747
+ type: smaliTypeDescriptorParser,
748
+ _newline: smaliLineEndPraser,
749
+ elements: createArrayParser(smaliAnnotationElementParser),
750
+ _indentation1: smaliIndentationParser,
751
+ _endAnnotation: createExactSequenceParser('.end annotation\n'),
752
+ });
927
753
 
928
754
  setParserName(smaliAnnotationParser, 'smaliAnnotationParser');
929
755
 
@@ -949,7 +775,7 @@ export const smaliFieldParser: Parser<SmaliField, string> = promiseCompose(
949
775
  createOptionalParser(promiseCompose(
950
776
  createTupleParser([
951
777
  createExactSequenceParser(' = '),
952
- createUnionParser<number | bigint | string | boolean | null, string>([
778
+ createUnionParser([
953
779
  smaliCharacterLiteralParser,
954
780
  smaliFieldValueParser,
955
781
  smaliQuotedStringParser,
@@ -1154,25 +980,16 @@ function isSmaliRegister(value: unknown): value is SmaliRegister {
1154
980
  );
1155
981
  }
1156
982
 
1157
- const smaliParametersRegisterParser: Parser<SmaliRegister, string> = promiseCompose(
1158
- createUnionParser<['v' | 'p', number], string>([
1159
- createTupleParser([
1160
- createExactSequenceParser('v'),
1161
- smaliNumberParser,
1162
- ]),
1163
- createTupleParser([
1164
- createExactSequenceParser('p'),
1165
- smaliNumberParser,
1166
- ]),
1167
- ]),
1168
- ([
1169
- prefix,
1170
- index,
1171
- ]) => ({
1172
- prefix,
1173
- index,
983
+ const smaliParametersRegisterParser: Parser<SmaliRegister, string> = createUnionParser([
984
+ createObjectParser({
985
+ prefix: createExactSequenceParser('v' as const),
986
+ index: smaliNumberParser,
1174
987
  }),
1175
- );
988
+ createObjectParser({
989
+ prefix: createExactSequenceParser('p' as const),
990
+ index: smaliNumberParser,
991
+ }),
992
+ ]);
1176
993
 
1177
994
  setParserName(smaliParametersRegisterParser, 'smaliParametersRegisterParser');
1178
995
 
@@ -1180,6 +997,7 @@ type SmaliCodeLocal = {
1180
997
  register: SmaliRegister;
1181
998
  name: string | undefined;
1182
999
  type: string | undefined;
1000
+ signature: string | undefined;
1183
1001
  };
1184
1002
 
1185
1003
  const smaliCodeLocalParser: Parser<SmaliCodeLocal, string> = promiseCompose(
@@ -1192,6 +1010,11 @@ const smaliCodeLocalParser: Parser<SmaliCodeLocal, string> = promiseCompose(
1192
1010
  smaliQuotedStringParser,
1193
1011
  createExactSequenceParser(':'),
1194
1012
  smaliTypeDescriptorParser,
1013
+ createOptionalParser(createTupleParser([
1014
+ createExactSequenceParser(','),
1015
+ smaliWhitespaceParser,
1016
+ smaliQuotedStringParser,
1017
+ ])),
1195
1018
  ])),
1196
1019
  smaliLineEndPraser,
1197
1020
  ]),
@@ -1203,6 +1026,7 @@ const smaliCodeLocalParser: Parser<SmaliCodeLocal, string> = promiseCompose(
1203
1026
  register,
1204
1027
  name: nameAndType?.[2],
1205
1028
  type: nameAndType?.[4],
1029
+ signature: nameAndType?.[5]?.[2],
1206
1030
  }),
1207
1031
  );
1208
1032
 
@@ -1341,52 +1165,33 @@ type SmaliCatchDirective = {
1341
1165
  handlerLabel: string;
1342
1166
  };
1343
1167
 
1344
- const smaliCatchDirectiveParser: Parser<SmaliCatchDirective, string> = promiseCompose(
1345
- createTupleParser([
1346
- smaliIndentationParser,
1347
- createExactSequenceParser('.catch'),
1348
- createUnionParser<string | undefined, string, string>([
1349
- promiseCompose(
1350
- createExactSequenceParser('all'),
1351
- () => undefined as undefined,
1352
- ),
1353
- promiseCompose(
1354
- createTupleParser([
1355
- createExactSequenceParser(' '),
1356
- smaliTypeDescriptorParser,
1357
- ]),
1358
- ([
1359
- _space,
1360
- type,
1361
- ]) => type,
1362
- ),
1363
- ]),
1364
- createExactSequenceParser(' {'),
1365
- smaliCodeLabelParser,
1366
- createExactSequenceParser(' .. '),
1367
- smaliCodeLabelParser,
1368
- createExactSequenceParser('} '),
1369
- smaliCodeLabelParser,
1370
- smaliLineEndPraser,
1168
+ const smaliCatchDirectiveParser: Parser<SmaliCatchDirective, string> = createObjectParser({
1169
+ _indentation: smaliIndentationParser,
1170
+ _catch: createExactSequenceParser('.catch'),
1171
+ type: createUnionParser([
1172
+ promiseCompose(
1173
+ createExactSequenceParser('all'),
1174
+ () => undefined as undefined,
1175
+ ),
1176
+ promiseCompose(
1177
+ createTupleParser([
1178
+ createExactSequenceParser(' '),
1179
+ smaliTypeDescriptorParser,
1180
+ ]),
1181
+ ([
1182
+ _space,
1183
+ type,
1184
+ ]) => type,
1185
+ ),
1371
1186
  ]),
1372
- ([
1373
- _indentation,
1374
- _catch,
1375
- type,
1376
- _openBrace,
1377
- startLabel,
1378
- _dots,
1379
- endLabel,
1380
- _closeBrace,
1381
- handlerLabel,
1382
- _newline,
1383
- ]) => ({
1384
- type,
1385
- startLabel,
1386
- endLabel,
1387
- handlerLabel,
1388
- }),
1389
- );
1187
+ _openBrace: createExactSequenceParser(' {'),
1188
+ startLabel: smaliCodeLabelParser,
1189
+ _dots: createExactSequenceParser(' .. '),
1190
+ endLabel: smaliCodeLabelParser,
1191
+ _closeBrace: createExactSequenceParser('} '),
1192
+ handlerLabel: smaliCodeLabelParser,
1193
+ _newline: smaliLineEndPraser,
1194
+ });
1390
1195
 
1391
1196
  setParserName(smaliCatchDirectiveParser, 'smaliCatchDirectiveParser');
1392
1197
 
@@ -1395,23 +1200,12 @@ type SmaliLabeledCatchDirective = {
1395
1200
  catchDirective: SmaliCatchDirective;
1396
1201
  };
1397
1202
 
1398
- const smaliLabeledCatchDirectiveParser: Parser<SmaliLabeledCatchDirective, string> = promiseCompose(
1399
- createTupleParser([
1400
- createArrayParser(smaliCodeLineParser),
1401
- createOptionalParser(smaliCodeLocalParser),
1402
- createArrayParser(smaliCodeLabelLineParser),
1403
- smaliCatchDirectiveParser,
1404
- ]),
1405
- ([
1406
- _lines,
1407
- _local,
1408
- labels,
1409
- catchDirective,
1410
- ]) => ({
1411
- labels,
1412
- catchDirective,
1413
- }),
1414
- );
1203
+ const smaliLabeledCatchDirectiveParser: Parser<SmaliLabeledCatchDirective, string> = createObjectParser({
1204
+ _lines: createArrayParser(smaliCodeLineParser),
1205
+ _local: createOptionalParser(smaliCodeLocalParser),
1206
+ labels: createArrayParser(smaliCodeLabelLineParser),
1207
+ catchDirective: smaliCatchDirectiveParser,
1208
+ });
1415
1209
 
1416
1210
  setParserName(smaliLabeledCatchDirectiveParser, 'smaliLabeledCatchDirectiveParser');
1417
1211
 
@@ -1490,57 +1284,20 @@ const smaliParametersStringParser: Parser<string, string> = cloneParser(smaliQuo
1490
1284
  setParserName(smaliParametersStringParser, 'smaliParametersStringParser');
1491
1285
 
1492
1286
  const smaliParametersIntegerParser: Parser<number | bigint, string> = promiseCompose(
1493
- createTupleParser([
1494
- createOptionalParser(createExactSequenceParser('-')),
1495
- createExactSequenceParser('0x'),
1496
- async parserContext => {
1497
- const characters: string[] = [];
1498
-
1499
- while (true) {
1500
- const character = await parserContext.peek(0);
1501
-
1502
- parserContext.invariant(character !== undefined, 'Unexpected end of input');
1503
-
1504
- invariant(character !== undefined, 'Unexpected end of input');
1287
+ createRegExpParser(/-?0x([0-9a-fA-F]+)([Lts])?/),
1288
+ match => {
1289
+ const hexDigits = match[1]!;
1290
+ const optionalSuffix = match[2];
1505
1291
 
1506
- if (
1507
- (character >= '0' && character <= '9')
1508
- || (character >= 'a' && character <= 'f')
1509
- || (character >= 'A' && character <= 'F')
1510
- ) {
1511
- characters.push(character);
1512
-
1513
- parserContext.skip(1);
1514
-
1515
- continue;
1516
- }
1517
-
1518
- break;
1519
- }
1520
-
1521
- return characters.join('');
1522
- },
1523
- createOptionalParser(createUnionParser([
1524
- createExactSequenceParser('L'),
1525
- createExactSequenceParser('t'),
1526
- createExactSequenceParser('s'),
1527
- ])),
1528
- ]),
1529
- ([
1530
- optionalMinus,
1531
- _0x,
1532
- value,
1533
- optionalSuffix,
1534
- ]) => {
1535
1292
  if (optionalSuffix === 'L') {
1536
- const sign = optionalMinus ? -1n : 1n;
1293
+ const sign = match[0].startsWith('-') ? -1n : 1n;
1537
1294
 
1538
- return sign * BigInt('0x' + value);
1295
+ return sign * BigInt('0x' + hexDigits);
1539
1296
  }
1540
1297
 
1541
- const sign = optionalMinus ? -1 : 1;
1298
+ const sign = match[0].startsWith('-') ? -1 : 1;
1542
1299
 
1543
- return sign * Number.parseInt(value, 16);
1300
+ return sign * Number.parseInt(hexDigits, 16);
1544
1301
  },
1545
1302
  );
1546
1303
 
@@ -1563,26 +1320,13 @@ const smaliParametersTypeParser: Parser<string, string> = cloneParser(smaliTypeD
1563
1320
 
1564
1321
  setParserName(smaliParametersTypeParser, 'smaliParametersTypeParser');
1565
1322
 
1566
- const smaliParametersFieldParser: Parser<DalvikExecutableField, string> = promiseCompose(
1567
- createTupleParser([
1568
- smaliTypeDescriptorParser,
1569
- createExactSequenceParser('->'),
1570
- smaliMemberNameParser,
1571
- createExactSequenceParser(':'),
1572
- smaliTypeDescriptorParser,
1573
- ]),
1574
- ([
1575
- classPath,
1576
- _separator,
1577
- fieldName,
1578
- _colon,
1579
- type,
1580
- ]) => ({
1581
- class: classPath,
1582
- name: fieldName,
1583
- type,
1584
- }),
1585
- );
1323
+ const smaliParametersFieldParser: Parser<DalvikExecutableField, string> = createObjectParser({
1324
+ class: smaliTypeDescriptorParser,
1325
+ _separator: createExactSequenceParser('->'),
1326
+ name: smaliMemberNameParser,
1327
+ _colon: createExactSequenceParser(':'),
1328
+ type: smaliTypeDescriptorParser,
1329
+ });
1586
1330
 
1587
1331
  setParserName(smaliParametersFieldParser, 'smaliParametersFieldParser');
1588
1332
 
@@ -1590,12 +1334,15 @@ type SmaliCodeOperationParameter =
1590
1334
  | SmaliRegister
1591
1335
  | SmaliRegister[]
1592
1336
  | string
1337
+ | number
1338
+ | bigint
1593
1339
  | DalvikExecutableMethod
1340
+ | DalvikExecutableField
1594
1341
  ;
1595
1342
 
1596
1343
  const smaliCodeOperationParametersParser: Parser<SmaliCodeOperationParameter[], string> = createArrayParser(promiseCompose(
1597
1344
  createTupleParser([
1598
- createUnionParser<SmaliCodeOperationParameter, string>([
1345
+ createUnionParser([
1599
1346
  smaliParametersRegisterParser,
1600
1347
  smaliParametersRegistersParser,
1601
1348
  smaliParametersStringParser,
@@ -1663,29 +1410,18 @@ type SmaliOneLineCodeOperation = {
1663
1410
  parameters: SmaliCodeOperationParameter[];
1664
1411
  };
1665
1412
 
1666
- const smaliOneLineCodeOperationParser: Parser<SmaliOneLineCodeOperation, string> = promiseCompose(
1667
- createTupleParser([
1668
- smaliSingleIndentationParser,
1669
- smaliCodeOperationNameParser,
1670
- promiseCompose(
1671
- createOptionalParser(createTupleParser([
1672
- smaliSingleWhitespaceParser,
1673
- smaliCodeOperationParametersParser,
1674
- ])),
1675
- undefinedOrParameters => undefinedOrParameters === undefined ? [] : undefinedOrParameters[1],
1676
- ),
1677
- smaliLineEndPraser,
1678
- ]),
1679
- ([
1680
- _indent,
1681
- operation,
1682
- parameters,
1683
- _newline,
1684
- ]) => ({
1685
- operation,
1686
- parameters,
1687
- }),
1688
- );
1413
+ const smaliOneLineCodeOperationParser: Parser<SmaliOneLineCodeOperation, string> = createObjectParser({
1414
+ _indent: smaliSingleIndentationParser,
1415
+ operation: smaliCodeOperationNameParser,
1416
+ parameters: promiseCompose(
1417
+ createOptionalParser(createTupleParser([
1418
+ smaliSingleWhitespaceParser,
1419
+ smaliCodeOperationParametersParser,
1420
+ ])),
1421
+ undefinedOrParameters => undefinedOrParameters === undefined ? [] : undefinedOrParameters[1],
1422
+ ),
1423
+ _newline: smaliLineEndPraser,
1424
+ });
1689
1425
 
1690
1426
  setParserName(smaliOneLineCodeOperationParser, 'smaliOneLineCodeOperationParser');
1691
1427
 
@@ -1841,17 +1577,21 @@ const smaliLooseCodeOperationParser: Parser<SmaliLooseCodeOperation, string> = c
1841
1577
 
1842
1578
  setParserName(smaliLooseCodeOperationParser, 'smaliLooseCodeOperationParser');
1843
1579
 
1844
- type SmaliCodeOperationFromDalvikBytecodeOperation<T extends DalvikBytecodeOperation> =
1845
- T extends { branchOffsets: number[] }
1846
- ? Simplify<Omit<T, 'branchOffsets'> & { branchOffsetIndices: number[] }>
1847
- : T extends { branchOffset: number }
1848
- ? Simplify<Omit<T, 'branchOffset'> & { branchOffsetIndex: number }>
1580
+ // SmaliCodeOperation transforms DalvikBytecodeOperation:
1581
+ // - targetInstructionIndex -> branchOffsetIndex (intermediate form during parsing, relative)
1582
+ // - targetInstructionIndices -> branchOffsetIndices (intermediate form during parsing, relative)
1583
+ // - methodIndex -> method (resolved)
1584
+ type SmaliCodeOperationFromDalvikOperation<T extends DalvikBytecodeOperation> =
1585
+ T extends { targetInstructionIndices: number[] }
1586
+ ? Simplify<Omit<T, 'targetInstructionIndices'> & { branchOffsetIndices: number[] }>
1587
+ : T extends { targetInstructionIndex: number }
1588
+ ? Simplify<Omit<T, 'targetInstructionIndex'> & { branchOffsetIndex: number }>
1849
1589
  : T extends { methodIndex: IndexIntoMethodIds }
1850
1590
  ? Simplify<Omit<T, 'methodIndex'> & { method: DalvikExecutableMethod }>
1851
1591
  : T
1852
1592
  ;
1853
1593
 
1854
- type SmaliCodeOperation = SmaliCodeOperationFromDalvikBytecodeOperation<DalvikBytecodeOperation>;
1594
+ type SmaliCodeOperation = SmaliCodeOperationFromDalvikOperation<DalvikBytecodeOperation>;
1855
1595
 
1856
1596
  export const smaliCodeOperationParser: Parser<SmaliCodeOperation, string> = promiseCompose(
1857
1597
  smaliLooseCodeOperationParser,
@@ -2240,41 +1980,15 @@ const smaliExecutableCodeParser: Parser<SmaliExecutableCode<DalvikBytecode>, str
2240
1980
  }
2241
1981
  }
2242
1982
 
2243
- const branchOffsetByBranchOffsetIndex = new Map<number, number>();
2244
-
2245
- let operationOffset = 0;
2246
-
2247
- for (const [ operationIndex, operation ] of instructions.entries()) {
2248
- const operationSize = getOperationFormatSize(operation);
2249
-
2250
- branchOffsetByBranchOffsetIndex.set(
2251
- operationIndex,
2252
- operationOffset,
2253
- );
2254
-
2255
- operationOffset += operationSize;
2256
- }
2257
-
1983
+ // Convert branchOffsetIndex (relative) to targetInstructionIndex (absolute)
2258
1984
  for (const [ operationIndex, operation ] of instructions.entries()) {
2259
1985
  if (
2260
1986
  'branchOffsetIndex' in operation
2261
1987
  && typeof operation.branchOffsetIndex === 'number'
2262
1988
  ) {
2263
- const operationOffset = branchOffsetByBranchOffsetIndex.get(operationIndex + operation.branchOffsetIndex);
2264
- invariant(
2265
- operationOffset !== undefined,
2266
- 'Expected branch offset for operation index %s, but got undefined',
2267
- operation.branchOffsetIndex,
2268
- );
2269
-
2270
- const branchOffset = branchOffsetByBranchOffsetIndex.get(operationIndex);
2271
- invariant(
2272
- branchOffset !== undefined,
2273
- 'Expected branch offset for operation index %s, but got undefined',
2274
- operationIndex,
2275
- );
2276
-
2277
- (operation as any).branchOffset = operationOffset - branchOffset;
1989
+ // branchOffsetIndex is the relative instruction index from the label
1990
+ // targetInstructionIndex is the absolute instruction index
1991
+ (operation as any).targetInstructionIndex = operationIndex + operation.branchOffsetIndex;
2278
1992
  }
2279
1993
 
2280
1994
  if (
@@ -2297,22 +2011,11 @@ const smaliExecutableCodeParser: Parser<SmaliExecutableCode<DalvikBytecode>, str
2297
2011
  const [ sourceOperation ] = sourceOperations;
2298
2012
  const sourceOperationIndex = instructions.indexOf(sourceOperation);
2299
2013
 
2300
- (operation as any).branchOffsets = operation.branchOffsetIndices.map((branchOffsetIndex: number) => {
2301
- const operationOffset = branchOffsetByBranchOffsetIndex.get(sourceOperationIndex + branchOffsetIndex);
2302
- invariant(
2303
- operationOffset !== undefined,
2304
- 'Expected branch offset for operation index %s, but got undefined',
2305
- sourceOperationIndex + branchOffsetIndex,
2306
- );
2307
-
2308
- const branchOffset = branchOffsetByBranchOffsetIndex.get(sourceOperationIndex);
2309
- invariant(
2310
- branchOffset !== undefined,
2311
- 'Expected branch offset for operation index %s, but got undefined',
2312
- sourceOperationIndex,
2313
- );
2314
-
2315
- return operationOffset - branchOffset;
2014
+ // For payload instructions, branchOffsetIndices contains instruction-relative indices
2015
+ // from the source switch instruction. Convert to absolute instruction indices.
2016
+ (operation as any).targetInstructionIndices = operation.branchOffsetIndices.map((branchOffsetIndex: number) => {
2017
+ // branchOffsetIndex is relative to the source operation
2018
+ return sourceOperationIndex + branchOffsetIndex;
2316
2019
  });
2317
2020
  }
2318
2021
  }
@@ -2356,11 +2059,12 @@ const smaliExecutableCodeParser: Parser<SmaliExecutableCode<DalvikBytecode>, str
2356
2059
  }
2357
2060
 
2358
2061
  // Build tries array from catch directives
2062
+ // Now using instruction indices directly instead of code unit offsets
2359
2063
  const triesByRange = new Map<string, {
2360
- startAddress: number;
2064
+ startInstructionIndex: number;
2361
2065
  instructionCount: number;
2362
- handlers: Array<{ type: string; address: number }>;
2363
- catchAllAddress: number | undefined;
2066
+ handlers: Array<{ type: string; handlerInstructionIndex: number }>;
2067
+ catchAllInstructionIndex: number | undefined;
2364
2068
  }>();
2365
2069
 
2366
2070
  for (const catchDirective of catchDirectives) {
@@ -2373,56 +2077,64 @@ const smaliExecutableCodeParser: Parser<SmaliExecutableCode<DalvikBytecode>, str
2373
2077
  invariant(endIndex !== undefined, 'Expected to find end label %s', catchDirective.endLabel);
2374
2078
  invariant(handlerIndex !== undefined, 'Expected to find handler label %s', catchDirective.handlerLabel);
2375
2079
 
2376
- const startAddress = branchOffsetByBranchOffsetIndex.get(startIndex);
2377
- const endAddress = branchOffsetByBranchOffsetIndex.get(endIndex);
2378
- const handlerAddress = branchOffsetByBranchOffsetIndex.get(handlerIndex);
2379
-
2380
- invariant(startAddress !== undefined, 'Expected start address for index %s', startIndex);
2381
- invariant(endAddress !== undefined, 'Expected end address for index %s', endIndex);
2382
- invariant(handlerAddress !== undefined, 'Expected handler address for index %s', handlerIndex);
2080
+ // Use instruction indices directly
2081
+ const startInstructionIndex = startIndex;
2082
+ const instructionCount = endIndex - startIndex;
2083
+ const handlerInstructionIndex = handlerIndex;
2383
2084
 
2384
- const instructionCount = endAddress - startAddress;
2385
- const rangeKey = `${startAddress}-${instructionCount}`;
2085
+ const rangeKey = `${startInstructionIndex}-${instructionCount}`;
2386
2086
 
2387
2087
  let tryEntry = triesByRange.get(rangeKey);
2388
2088
  if (!tryEntry) {
2389
2089
  tryEntry = {
2390
- startAddress,
2090
+ startInstructionIndex,
2391
2091
  instructionCount,
2392
2092
  handlers: [],
2393
- catchAllAddress: undefined,
2093
+ catchAllInstructionIndex: undefined as number | undefined,
2394
2094
  };
2395
2095
  triesByRange.set(rangeKey, tryEntry);
2396
2096
  }
2397
2097
 
2398
2098
  if (catchDirective.type === undefined) {
2399
2099
  // .catchall
2400
- tryEntry.catchAllAddress = handlerAddress;
2100
+ tryEntry.catchAllInstructionIndex = handlerInstructionIndex;
2401
2101
  } else {
2402
2102
  // .catch Type
2403
2103
  tryEntry.handlers.push({
2404
2104
  type: catchDirective.type,
2405
- address: handlerAddress,
2105
+ handlerInstructionIndex,
2406
2106
  });
2407
2107
  }
2408
2108
  }
2409
2109
 
2410
2110
  const tries = Array.from(triesByRange.values()).map(tryEntry => ({
2411
- startAddress: tryEntry.startAddress,
2111
+ startInstructionIndex: tryEntry.startInstructionIndex,
2412
2112
  instructionCount: tryEntry.instructionCount,
2413
2113
  handler: {
2414
2114
  handlers: tryEntry.handlers,
2415
- catchAllAddress: tryEntry.catchAllAddress,
2115
+ catchAllInstructionIndex: tryEntry.catchAllInstructionIndex,
2416
2116
  },
2417
2117
  }));
2418
2118
 
2119
+ // Build debug info from debug directives
2120
+ // Debug info still uses code unit offsets (addressDiff), so we need to build the mapping
2121
+ // IMPORTANT: Must be done BEFORE deleting branchOffsetIndices, as getOperationSizeInCodeUnits uses it
2122
+ const codeUnitOffsetByInstructionIndex = new Map<number, number>();
2123
+ let codeUnitOffset = 0;
2124
+ for (let i = 0; i < instructions.length; i++) {
2125
+ codeUnitOffsetByInstructionIndex.set(i, codeUnitOffset);
2126
+ codeUnitOffset += getOperationSizeInCodeUnits(instructions[i]);
2127
+ }
2128
+ codeUnitOffsetByInstructionIndex.set(instructions.length, codeUnitOffset);
2129
+ // Alias for backward compatibility with debug info code
2130
+ const branchOffsetByBranchOffsetIndex = codeUnitOffsetByInstructionIndex;
2131
+
2419
2132
  for (const operation of instructions) {
2420
2133
  delete (operation as any).labels;
2421
2134
  delete (operation as any).branchOffsetIndex;
2422
2135
  delete (operation as any).branchOffsetIndices;
2423
2136
  }
2424
2137
 
2425
- // Build debug info from debug directives
2426
2138
  type DebugByteCodeValue = DalvikExecutableDebugInfo['bytecode'][number];
2427
2139
  let debugInfo: DalvikExecutableDebugInfo | undefined;
2428
2140
  const debugBytecode: DebugByteCodeValue[] = [];
@@ -2741,7 +2453,7 @@ export const smaliMethodParser: Parser<SmaliMethod<DalvikBytecode>, string> = pr
2741
2453
  code.insSize = insSize;
2742
2454
 
2743
2455
  for (const operation of code.instructions) {
2744
- const smaliRegisters = dalvikBytecodeOperationCompanion.getRegisters(operation) as unknown[] as SmaliRegister[]; // TODO
2456
+ const smaliRegisters = rawDalvikBytecodeOperationCompanion.getRegisters(operation as RawDalvikBytecodeOperation) as unknown[] as SmaliRegister[]; // TODO
2745
2457
 
2746
2458
  if (smaliRegisters.length === 0) {
2747
2459
  continue;
@@ -2769,7 +2481,7 @@ export const smaliMethodParser: Parser<SmaliMethod<DalvikBytecode>, string> = pr
2769
2481
  continue;
2770
2482
  }
2771
2483
 
2772
- const registers = dalvikBytecodeOperationCompanion.getRegisters(operation);
2484
+ const registers = rawDalvikBytecodeOperationCompanion.getRegisters(operation as RawDalvikBytecodeOperation);
2773
2485
 
2774
2486
  outsSize = Math.max(outsSize, registers.length); // TODO?: two words for wide types?
2775
2487
  }
@@ -2829,7 +2541,7 @@ type SmaliMethods = Pick<DalvikExecutableClassData<DalvikBytecode>, 'directMetho
2829
2541
  };
2830
2542
 
2831
2543
  const smaliMethodsParser: Parser<SmaliMethods, string> = promiseCompose(
2832
- createArrayParser<string[] | SmaliMethod<DalvikBytecode>, string>(createDisjunctionParser<string[] | SmaliMethod<DalvikBytecode>, string, string>([
2544
+ createArrayParser(createDisjunctionParser([
2833
2545
  smaliMethodParser,
2834
2546
  smaliCommentsOrNewlinesParser,
2835
2547
  ])),