@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,2640 @@
1
+ import { type Parser, setParserName } from './parser.js';
2
+ import { unescapeJavaString } from './stringEscapes.js';
3
+ import { createUnionParser } from './unionParser.js';
4
+ import { createExactSequenceParser } from './exactSequenceParser.js';
5
+ import { promiseCompose } from './promiseCompose.js';
6
+ import { createTupleParser } from './tupleParser.js';
7
+ import { createDisjunctionParser } from './disjunctionParser.js';
8
+ import { createArrayParser } from './arrayParser.js';
9
+ import { createOptionalParser } from './optionalParser.js';
10
+ import { createRegExpParser } from './regexpParser.js';
11
+ import { createSeparatedNonEmptyArrayParser } from './separatedNonEmptyArrayParser.js';
12
+ import { createObjectParser } from './objectParser.js';
13
+ import {
14
+ type JavaModifier,
15
+ type JavaModifierKeyword,
16
+ type JavaName,
17
+ type JavaSimpleName,
18
+ type JavaImportDeclaration,
19
+ } from './java.js';
20
+
21
+ // Temporary local types while migrating to javaparser format
22
+ type JavaIdentifier = string;
23
+ type JavaQualifiedName = { parts: JavaIdentifier[] };
24
+ type JavaAnnotation = { type: 'MarkerAnnotationExpr'; name: JavaName };
25
+ type JavaPackageDeclaration = { annotations: JavaAnnotation[]; name: JavaQualifiedName };
26
+ type JavaEnumDeclarationOutput = {
27
+ type: 'EnumDeclaration';
28
+ modifiers: JavaModifier[];
29
+ annotations: JavaAnnotation[];
30
+ name: JavaSimpleName;
31
+ implementedTypes: unknown[];
32
+ entries: unknown[];
33
+ members: unknown[];
34
+ };
35
+ type JavaRecordDeclaration = { type: 'record'; annotations: JavaAnnotation[]; modifiers: JavaModifier[]; name: JavaIdentifier };
36
+ type JavaAnnotationTypeDeclaration = { type: 'annotation'; annotations: JavaAnnotation[]; modifiers: JavaModifier[]; name: JavaIdentifier };
37
+ // Note: JavaTypeDeclaration is now more permissive to allow the new declaration formats
38
+ type JavaTypeDeclaration = JavaEnumDeclarationOutput | JavaRecordDeclaration | JavaAnnotationTypeDeclaration | {
39
+ type: 'ClassOrInterfaceDeclaration';
40
+ modifiers: JavaModifier[];
41
+ annotations: unknown[];
42
+ name: JavaSimpleName;
43
+ isInterface: boolean;
44
+ typeParameters: unknown[];
45
+ extendedTypes: unknown[];
46
+ implementedTypes: unknown[];
47
+ permittedTypes: unknown[];
48
+ members: unknown[];
49
+ };
50
+ type JavaCompilationUnit = { package?: JavaPackageDeclaration; imports: JavaImportDeclaration[]; types: JavaTypeDeclaration[] };
51
+
52
+ // Whitespace (spaces, tabs, newlines)
53
+ const javaWhitespaceParser: Parser<string, string> = promiseCompose(
54
+ createRegExpParser(/\s+/),
55
+ match => match[0],
56
+ );
57
+
58
+ const javaOptionalWhitespaceParser: Parser<string, string> = promiseCompose(
59
+ createRegExpParser(/\s*/),
60
+ match => match[0],
61
+ );
62
+
63
+ // Line comment: // ...
64
+ const javaLineCommentParser: Parser<string, string> = promiseCompose(
65
+ createRegExpParser(/\/\/[^\n]*/),
66
+ match => match[0],
67
+ );
68
+
69
+ // Block comment: /* ... */
70
+ // TODO: proper nested comment handling if needed
71
+ const javaBlockCommentParser: Parser<string, string> = promiseCompose(
72
+ createRegExpParser(/\/\*[\s\S]*?\*\//),
73
+ match => match[0],
74
+ );
75
+
76
+ // Comment (line or block)
77
+ const javaCommentParser: Parser<string, string> = createUnionParser([
78
+ javaLineCommentParser,
79
+ javaBlockCommentParser,
80
+ ]);
81
+
82
+ // Whitespace or comment
83
+ const javaWhitespaceOrCommentParser: Parser<string, string> = createUnionParser([
84
+ javaWhitespaceParser,
85
+ javaCommentParser,
86
+ ]);
87
+
88
+ // Optional whitespace/comments (skippable)
89
+ const javaSkippableParser: Parser<unknown, string> = createArrayParser(javaWhitespaceOrCommentParser);
90
+
91
+ // Identifier: valid Java identifier
92
+ const javaIdentifierParser: Parser<JavaIdentifier, string> = promiseCompose(
93
+ createRegExpParser(/[a-zA-Z_$][a-zA-Z0-9_$]*/),
94
+ match => match[0],
95
+ );
96
+
97
+ setParserName(javaIdentifierParser, 'javaIdentifierParser');
98
+
99
+ // SimpleName: single identifier wrapped in SimpleName node
100
+ const javaSimpleNameParser: Parser<JavaSimpleName, string> = createObjectParser({
101
+ type: 'SimpleName' as const,
102
+ identifier: javaIdentifierParser,
103
+ });
104
+
105
+ setParserName(javaSimpleNameParser, 'javaSimpleNameParser');
106
+
107
+ // Name: qualified name as nested structure (e.g., com.example.Foo)
108
+ // Result is { type: 'Name', identifier: 'Foo', qualifier: { type: 'Name', identifier: 'example', qualifier: { type: 'Name', identifier: 'com' } } }
109
+ const javaNameParser: Parser<JavaName, string> = promiseCompose(
110
+ createSeparatedNonEmptyArrayParser(
111
+ javaIdentifierParser,
112
+ promiseCompose(
113
+ createTupleParser([
114
+ javaOptionalWhitespaceParser,
115
+ createExactSequenceParser('.'),
116
+ javaOptionalWhitespaceParser,
117
+ ]),
118
+ () => '.',
119
+ ),
120
+ ),
121
+ parts => {
122
+ // Build nested Name structure from left to right
123
+ // parts = ['com', 'example', 'Foo'] -> nested with 'Foo' at top
124
+ let result: JavaName = { type: 'Name', identifier: parts[0]! };
125
+ for (let i = 1; i < parts.length; i++) {
126
+ result = { type: 'Name', identifier: parts[i]!, qualifier: result };
127
+ }
128
+ return result;
129
+ },
130
+ );
131
+
132
+ setParserName(javaNameParser, 'javaNameParser');
133
+
134
+ // Qualified name: com.example.Foo (legacy format with flat parts array)
135
+ const javaQualifiedNameParser: Parser<JavaQualifiedName, string> = promiseCompose(
136
+ createSeparatedNonEmptyArrayParser(
137
+ javaIdentifierParser,
138
+ promiseCompose(
139
+ createTupleParser([
140
+ javaOptionalWhitespaceParser,
141
+ createExactSequenceParser('.'),
142
+ javaOptionalWhitespaceParser,
143
+ ]),
144
+ () => '.',
145
+ ),
146
+ ),
147
+ parts => ({ parts }),
148
+ );
149
+
150
+ setParserName(javaQualifiedNameParser, 'javaQualifiedNameParser');
151
+
152
+ // Annotation: @Name
153
+ // TODO: annotation arguments like @Name(value = "foo") -> SingleMemberAnnotationExpr or NormalAnnotationExpr
154
+ type JavaMarkerAnnotationExprOutput = {
155
+ type: 'MarkerAnnotationExpr';
156
+ name: JavaName;
157
+ };
158
+
159
+ const javaAnnotationParser: Parser<JavaMarkerAnnotationExprOutput, string> = createObjectParser({
160
+ _at: createExactSequenceParser('@'),
161
+ type: 'MarkerAnnotationExpr' as const,
162
+ name: javaNameParser,
163
+ });
164
+
165
+ setParserName(javaAnnotationParser, 'javaAnnotationParser');
166
+
167
+ // Annotations with trailing whitespace
168
+ const javaAnnotationsParser: Parser<JavaAnnotation[], string> = createArrayParser(
169
+ promiseCompose(
170
+ createTupleParser([
171
+ javaAnnotationParser,
172
+ javaSkippableParser,
173
+ ]),
174
+ ([annotation]) => annotation,
175
+ ),
176
+ );
177
+
178
+ // Package declaration: package com.example;
179
+ type JavaPackageDeclarationNew = { type: 'PackageDeclaration'; annotations: JavaAnnotation[]; name: JavaName };
180
+ const javaPackageDeclarationParserNew: Parser<JavaPackageDeclarationNew, string> = createObjectParser({
181
+ annotations: javaAnnotationsParser,
182
+ _package: createExactSequenceParser('package'),
183
+ _ws1: javaWhitespaceParser,
184
+ type: 'PackageDeclaration' as const,
185
+ name: javaNameParser,
186
+ _ws2: javaOptionalWhitespaceParser,
187
+ _semi: createExactSequenceParser(';'),
188
+ });
189
+
190
+ // Legacy package declaration parser (still using old annotation format)
191
+ const javaPackageDeclarationParser: Parser<JavaPackageDeclaration, string> = promiseCompose(
192
+ createTupleParser([
193
+ javaAnnotationsParser,
194
+ createExactSequenceParser('package'),
195
+ javaWhitespaceParser,
196
+ javaQualifiedNameParser,
197
+ javaOptionalWhitespaceParser,
198
+ createExactSequenceParser(';'),
199
+ ]),
200
+ ([annotations, , , name]) => ({ annotations, name }),
201
+ );
202
+
203
+ setParserName(javaPackageDeclarationParser, 'javaPackageDeclarationParser');
204
+
205
+ // Import declaration: import [static] com.example.Foo[.*];
206
+ const javaImportDeclarationParser: Parser<JavaImportDeclaration, string> = promiseCompose(
207
+ createTupleParser([
208
+ createExactSequenceParser('import'),
209
+ javaWhitespaceParser,
210
+ createOptionalParser(
211
+ promiseCompose(
212
+ createTupleParser([
213
+ createExactSequenceParser('static'),
214
+ javaWhitespaceParser,
215
+ ]),
216
+ () => true as const,
217
+ ),
218
+ ),
219
+ javaNameParser,
220
+ createOptionalParser(
221
+ promiseCompose(
222
+ createTupleParser([
223
+ javaOptionalWhitespaceParser,
224
+ createExactSequenceParser('.'),
225
+ javaOptionalWhitespaceParser,
226
+ createExactSequenceParser('*'),
227
+ ]),
228
+ () => true as const,
229
+ ),
230
+ ),
231
+ javaOptionalWhitespaceParser,
232
+ createExactSequenceParser(';'),
233
+ ]),
234
+ ([, , isStatic, name, isAsterisk]) => ({
235
+ type: 'ImportDeclaration' as const,
236
+ isStatic: isStatic ?? false,
237
+ isAsterisk: isAsterisk ?? false,
238
+ name,
239
+ }),
240
+ );
241
+
242
+ setParserName(javaImportDeclarationParser, 'javaImportDeclarationParser');
243
+
244
+ // Modifier keywords
245
+ const javaModifierKeywordParser: Parser<JavaModifierKeyword, string> = createDisjunctionParser([
246
+ promiseCompose(createExactSequenceParser('public'), () => 'PUBLIC' as const),
247
+ promiseCompose(createExactSequenceParser('protected'), () => 'PROTECTED' as const),
248
+ promiseCompose(createExactSequenceParser('private'), () => 'PRIVATE' as const),
249
+ promiseCompose(createExactSequenceParser('static'), () => 'STATIC' as const),
250
+ promiseCompose(createExactSequenceParser('final'), () => 'FINAL' as const),
251
+ promiseCompose(createExactSequenceParser('abstract'), () => 'ABSTRACT' as const),
252
+ promiseCompose(createExactSequenceParser('synchronized'), () => 'SYNCHRONIZED' as const),
253
+ promiseCompose(createExactSequenceParser('native'), () => 'NATIVE' as const),
254
+ promiseCompose(createExactSequenceParser('transient'), () => 'TRANSIENT' as const),
255
+ promiseCompose(createExactSequenceParser('volatile'), () => 'VOLATILE' as const),
256
+ promiseCompose(createExactSequenceParser('strictfp'), () => 'STRICTFP' as const),
257
+ promiseCompose(createExactSequenceParser('default'), () => 'DEFAULT' as const),
258
+ promiseCompose(createExactSequenceParser('sealed'), () => 'SEALED' as const),
259
+ promiseCompose(createExactSequenceParser('non-sealed'), () => 'NON_SEALED' as const),
260
+ ]);
261
+
262
+ const javaModifierParser: Parser<JavaModifier, string> = createObjectParser({
263
+ type: 'Modifier' as const,
264
+ keyword: javaModifierKeywordParser,
265
+ });
266
+
267
+ setParserName(javaModifierParser, 'javaModifierParser');
268
+
269
+ // Type parsers
270
+ type JavaPrimitiveTypeOutput = {
271
+ type: 'PrimitiveType';
272
+ type_: 'BOOLEAN' | 'BYTE' | 'CHAR' | 'DOUBLE' | 'FLOAT' | 'INT' | 'LONG' | 'SHORT';
273
+ annotations: unknown[];
274
+ };
275
+
276
+ const javaPrimitiveTypeParser: Parser<JavaPrimitiveTypeOutput, string> = createDisjunctionParser([
277
+ promiseCompose(createExactSequenceParser('boolean'), () => ({ type: 'PrimitiveType' as const, type_: 'BOOLEAN' as const, annotations: [] })),
278
+ promiseCompose(createExactSequenceParser('byte'), () => ({ type: 'PrimitiveType' as const, type_: 'BYTE' as const, annotations: [] })),
279
+ promiseCompose(createExactSequenceParser('char'), () => ({ type: 'PrimitiveType' as const, type_: 'CHAR' as const, annotations: [] })),
280
+ promiseCompose(createExactSequenceParser('double'), () => ({ type: 'PrimitiveType' as const, type_: 'DOUBLE' as const, annotations: [] })),
281
+ promiseCompose(createExactSequenceParser('float'), () => ({ type: 'PrimitiveType' as const, type_: 'FLOAT' as const, annotations: [] })),
282
+ promiseCompose(createExactSequenceParser('int'), () => ({ type: 'PrimitiveType' as const, type_: 'INT' as const, annotations: [] })),
283
+ promiseCompose(createExactSequenceParser('long'), () => ({ type: 'PrimitiveType' as const, type_: 'LONG' as const, annotations: [] })),
284
+ promiseCompose(createExactSequenceParser('short'), () => ({ type: 'PrimitiveType' as const, type_: 'SHORT' as const, annotations: [] })),
285
+ ]);
286
+
287
+ setParserName(javaPrimitiveTypeParser, 'javaPrimitiveTypeParser');
288
+
289
+ type JavaVoidTypeOutput = {
290
+ type: 'VoidType';
291
+ annotations: unknown[];
292
+ };
293
+
294
+ const javaVoidTypeParser: Parser<JavaVoidTypeOutput, string> = createObjectParser({
295
+ _void: createExactSequenceParser('void'),
296
+ type: 'VoidType' as const,
297
+ annotations: [] as unknown[],
298
+ });
299
+
300
+ setParserName(javaVoidTypeParser, 'javaVoidTypeParser');
301
+
302
+ type JavaClassOrInterfaceTypeOutput = {
303
+ type: 'ClassOrInterfaceType';
304
+ name: JavaSimpleName;
305
+ scope?: JavaClassOrInterfaceTypeOutput;
306
+ typeArguments?: unknown[];
307
+ annotations: unknown[];
308
+ };
309
+
310
+ // Forward declaration for recursive type parsing
311
+ let javaTypeParser: Parser<unknown, string>;
312
+
313
+ // Wildcard type: ?, ? extends Foo, ? super Foo
314
+ type JavaWildcardTypeOutput = {
315
+ type: 'WildcardType';
316
+ annotations: unknown[];
317
+ extendedType?: unknown;
318
+ superType?: unknown;
319
+ };
320
+
321
+ const javaWildcardTypeParser: Parser<JavaWildcardTypeOutput, string> = promiseCompose(
322
+ createTupleParser([
323
+ createExactSequenceParser('?'),
324
+ javaSkippableParser,
325
+ createOptionalParser(
326
+ createUnionParser([
327
+ promiseCompose(
328
+ createTupleParser([
329
+ createExactSequenceParser('extends'),
330
+ javaSkippableParser,
331
+ (ctx) => javaTypeParser(ctx),
332
+ ]),
333
+ ([, , type]) => ({ extendedType: type }),
334
+ ),
335
+ promiseCompose(
336
+ createTupleParser([
337
+ createExactSequenceParser('super'),
338
+ javaSkippableParser,
339
+ (ctx) => javaTypeParser(ctx),
340
+ ]),
341
+ ([, , type]) => ({ superType: type }),
342
+ ),
343
+ ]),
344
+ ),
345
+ ]),
346
+ ([, , bounds]) => ({
347
+ type: 'WildcardType' as const,
348
+ annotations: [],
349
+ ...(bounds ?? {}),
350
+ }),
351
+ );
352
+
353
+ setParserName(javaWildcardTypeParser, 'javaWildcardTypeParser');
354
+
355
+ // Type argument: either a type or a wildcard
356
+ const javaTypeArgumentParser: Parser<unknown, string> = createUnionParser([
357
+ javaWildcardTypeParser,
358
+ (ctx) => javaTypeParser(ctx),
359
+ ]);
360
+
361
+ setParserName(javaTypeArgumentParser, 'javaTypeArgumentParser');
362
+
363
+ // Type arguments: <T, U, V> or <?, ? extends Foo>
364
+ const javaTypeArgumentsParser: Parser<unknown[], string> = promiseCompose(
365
+ createTupleParser([
366
+ createExactSequenceParser('<'),
367
+ javaSkippableParser,
368
+ createSeparatedNonEmptyArrayParser(
369
+ promiseCompose(
370
+ createTupleParser([
371
+ javaTypeArgumentParser,
372
+ javaSkippableParser,
373
+ ]),
374
+ ([type]) => type,
375
+ ),
376
+ promiseCompose(
377
+ createTupleParser([
378
+ createExactSequenceParser(','),
379
+ javaSkippableParser,
380
+ ]),
381
+ () => ',',
382
+ ),
383
+ ),
384
+ javaSkippableParser,
385
+ createExactSequenceParser('>'),
386
+ ]),
387
+ ([, , types]) => types,
388
+ );
389
+
390
+ setParserName(javaTypeArgumentsParser, 'javaTypeArgumentsParser');
391
+
392
+ // Type parameter: T, T extends Foo, T extends Foo & Bar
393
+ type JavaTypeParameterOutput = {
394
+ type: 'TypeParameter';
395
+ annotations: unknown[];
396
+ name: JavaSimpleName;
397
+ typeBound: unknown[];
398
+ };
399
+
400
+ const javaTypeParameterParser: Parser<JavaTypeParameterOutput, string> = promiseCompose(
401
+ createTupleParser([
402
+ javaSimpleNameParser,
403
+ javaSkippableParser,
404
+ createOptionalParser(
405
+ promiseCompose(
406
+ createTupleParser([
407
+ createExactSequenceParser('extends'),
408
+ javaSkippableParser,
409
+ createSeparatedNonEmptyArrayParser(
410
+ promiseCompose(
411
+ createTupleParser([
412
+ (ctx) => javaTypeParser(ctx),
413
+ javaSkippableParser,
414
+ ]),
415
+ ([type]) => type,
416
+ ),
417
+ promiseCompose(
418
+ createTupleParser([
419
+ createExactSequenceParser('&'),
420
+ javaSkippableParser,
421
+ ]),
422
+ () => '&',
423
+ ),
424
+ ),
425
+ ]),
426
+ ([, , bounds]) => bounds,
427
+ ),
428
+ ),
429
+ ]),
430
+ ([name, , typeBound]) => ({
431
+ type: 'TypeParameter' as const,
432
+ annotations: [], // TODO: parse type parameter annotations
433
+ name,
434
+ typeBound: typeBound ?? [],
435
+ }),
436
+ );
437
+
438
+ setParserName(javaTypeParameterParser, 'javaTypeParameterParser');
439
+
440
+ // Type parameters: <T>, <T, U>, <T extends Foo>
441
+ const javaTypeParametersParser: Parser<JavaTypeParameterOutput[], string> = promiseCompose(
442
+ createTupleParser([
443
+ createExactSequenceParser('<'),
444
+ javaSkippableParser,
445
+ createSeparatedNonEmptyArrayParser(
446
+ promiseCompose(
447
+ createTupleParser([
448
+ javaTypeParameterParser,
449
+ javaSkippableParser,
450
+ ]),
451
+ ([param]) => param,
452
+ ),
453
+ promiseCompose(
454
+ createTupleParser([
455
+ createExactSequenceParser(','),
456
+ javaSkippableParser,
457
+ ]),
458
+ () => ',',
459
+ ),
460
+ ),
461
+ javaSkippableParser,
462
+ createExactSequenceParser('>'),
463
+ ]),
464
+ ([, , params]) => params,
465
+ );
466
+
467
+ setParserName(javaTypeParametersParser, 'javaTypeParametersParser');
468
+
469
+ // ClassOrInterfaceType: Foo, List<T>, Outer.Inner, Map<K, V>
470
+ // Forward declaration for recursive scope
471
+ let javaClassOrInterfaceTypeParser: Parser<JavaClassOrInterfaceTypeOutput, string>;
472
+
473
+ // Parser for a single type segment (name with optional type arguments)
474
+ const javaTypeSegmentParser: Parser<{ name: JavaSimpleName; typeArguments?: unknown[] }, string> = promiseCompose(
475
+ createTupleParser([
476
+ javaSimpleNameParser,
477
+ javaSkippableParser,
478
+ createOptionalParser(javaTypeArgumentsParser),
479
+ ]),
480
+ ([name, , typeArguments]) => ({
481
+ name,
482
+ ...(typeArguments ? { typeArguments } : {}),
483
+ }),
484
+ );
485
+
486
+ setParserName(javaTypeSegmentParser, 'javaTypeSegmentParser');
487
+
488
+ // Full ClassOrInterfaceType with optional scope: Outer.Inner or just Foo
489
+ javaClassOrInterfaceTypeParser = promiseCompose(
490
+ createSeparatedNonEmptyArrayParser(
491
+ promiseCompose(
492
+ createTupleParser([
493
+ javaTypeSegmentParser,
494
+ javaSkippableParser,
495
+ ]),
496
+ ([segment]) => segment,
497
+ ),
498
+ promiseCompose(
499
+ createTupleParser([
500
+ createExactSequenceParser('.'),
501
+ javaSkippableParser,
502
+ ]),
503
+ () => '.',
504
+ ),
505
+ ),
506
+ (segments) => {
507
+ // Build the type from segments: [Outer, Inner] -> { scope: Outer, name: Inner }
508
+ let result: JavaClassOrInterfaceTypeOutput | undefined;
509
+ for (const segment of segments) {
510
+ if (result === undefined) {
511
+ result = {
512
+ type: 'ClassOrInterfaceType' as const,
513
+ name: segment.name,
514
+ ...(segment.typeArguments ? { typeArguments: segment.typeArguments } : {}),
515
+ annotations: [],
516
+ };
517
+ } else {
518
+ result = {
519
+ type: 'ClassOrInterfaceType' as const,
520
+ scope: result,
521
+ name: segment.name,
522
+ ...(segment.typeArguments ? { typeArguments: segment.typeArguments } : {}),
523
+ annotations: [],
524
+ };
525
+ }
526
+ }
527
+ return result!;
528
+ },
529
+ );
530
+
531
+ setParserName(javaClassOrInterfaceTypeParser, 'javaClassOrInterfaceTypeParser');
532
+
533
+ // Reference type (class/interface or array)
534
+ type JavaTypeOutput = JavaPrimitiveTypeOutput | JavaVoidTypeOutput | JavaClassOrInterfaceTypeOutput | {
535
+ type: 'ArrayType';
536
+ componentType: JavaTypeOutput;
537
+ origin: 'TYPE';
538
+ annotations: unknown[];
539
+ };
540
+
541
+ // Base type (without array brackets)
542
+ const javaBaseTypeParser: Parser<JavaPrimitiveTypeOutput | JavaVoidTypeOutput | JavaClassOrInterfaceTypeOutput, string> = createDisjunctionParser([
543
+ javaPrimitiveTypeParser,
544
+ javaVoidTypeParser,
545
+ javaClassOrInterfaceTypeParser,
546
+ ]);
547
+
548
+ // Array brackets
549
+ const javaArrayBracketsParser: Parser<unknown[], string> = createArrayParser(
550
+ promiseCompose(
551
+ createTupleParser([
552
+ javaSkippableParser,
553
+ createExactSequenceParser('['),
554
+ javaSkippableParser,
555
+ createExactSequenceParser(']'),
556
+ ]),
557
+ () => [],
558
+ ),
559
+ );
560
+
561
+ // Full type with optional array brackets
562
+ javaTypeParser = promiseCompose(
563
+ createTupleParser([
564
+ javaBaseTypeParser,
565
+ javaArrayBracketsParser,
566
+ ]),
567
+ ([baseType, brackets]) => {
568
+ let result: JavaTypeOutput = baseType;
569
+ for (const _ of brackets) {
570
+ result = {
571
+ type: 'ArrayType' as const,
572
+ componentType: result,
573
+ origin: 'TYPE' as const,
574
+ annotations: [],
575
+ };
576
+ }
577
+ return result;
578
+ },
579
+ );
580
+
581
+ setParserName(javaTypeParser, 'javaTypeParser');
582
+
583
+ // Modifiers with trailing whitespace
584
+ const javaModifiersParser: Parser<JavaModifier[], string> = createArrayParser(
585
+ promiseCompose(
586
+ createTupleParser([
587
+ javaModifierParser,
588
+ javaSkippableParser,
589
+ ]),
590
+ ([modifier]) => modifier,
591
+ ),
592
+ );
593
+
594
+ // Skip balanced braces (for skipping method/block bodies)
595
+ const javaSkipBalancedBracesParser: Parser<string, string> = promiseCompose(
596
+ createRegExpParser(/\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/),
597
+ match => match[0],
598
+ );
599
+
600
+ // Parameter: @Annotation final Type name
601
+ type JavaParameterOutput = {
602
+ type: 'Parameter';
603
+ modifiers: JavaModifier[];
604
+ annotations: unknown[];
605
+ type_: unknown; // The type of the parameter
606
+ isVarArgs: boolean;
607
+ varArgsAnnotations: unknown[];
608
+ name: JavaSimpleName;
609
+ };
610
+
611
+ const javaParameterParser: Parser<JavaParameterOutput, string> = promiseCompose(
612
+ createTupleParser([
613
+ javaAnnotationsParser,
614
+ javaModifiersParser,
615
+ javaTypeParser,
616
+ javaSkippableParser,
617
+ createOptionalParser(createExactSequenceParser('...')), // varargs
618
+ javaSkippableParser,
619
+ javaSimpleNameParser,
620
+ ]),
621
+ ([annotations, modifiers, type_, , varArgs, , name]) => ({
622
+ type: 'Parameter' as const,
623
+ modifiers,
624
+ annotations,
625
+ type_,
626
+ isVarArgs: varArgs !== undefined,
627
+ varArgsAnnotations: [],
628
+ name,
629
+ }),
630
+ );
631
+
632
+ setParserName(javaParameterParser, 'javaParameterParser');
633
+
634
+ // Parameter list: (param1, param2, ...)
635
+ const javaParameterListParser: Parser<JavaParameterOutput[], string> = promiseCompose(
636
+ createTupleParser([
637
+ createExactSequenceParser('('),
638
+ javaSkippableParser,
639
+ createOptionalParser(
640
+ createSeparatedNonEmptyArrayParser(
641
+ promiseCompose(
642
+ createTupleParser([
643
+ javaParameterParser,
644
+ javaSkippableParser,
645
+ ]),
646
+ ([param]) => param,
647
+ ),
648
+ promiseCompose(
649
+ createTupleParser([
650
+ createExactSequenceParser(','),
651
+ javaSkippableParser,
652
+ ]),
653
+ () => ',',
654
+ ),
655
+ ),
656
+ ),
657
+ javaSkippableParser,
658
+ createExactSequenceParser(')'),
659
+ ]),
660
+ ([, , params]) => params ?? [],
661
+ );
662
+
663
+ setParserName(javaParameterListParser, 'javaParameterListParser');
664
+
665
+ // Throws clause: throws Exception1, Exception2
666
+ const javaThrowsClauseParser: Parser<JavaClassOrInterfaceTypeOutput[], string> = promiseCompose(
667
+ createTupleParser([
668
+ createExactSequenceParser('throws'),
669
+ javaWhitespaceParser,
670
+ createSeparatedNonEmptyArrayParser(
671
+ promiseCompose(
672
+ createTupleParser([
673
+ javaClassOrInterfaceTypeParser,
674
+ javaSkippableParser,
675
+ ]),
676
+ ([type]) => type,
677
+ ),
678
+ promiseCompose(
679
+ createTupleParser([
680
+ createExactSequenceParser(','),
681
+ javaSkippableParser,
682
+ ]),
683
+ () => ',',
684
+ ),
685
+ ),
686
+ ]),
687
+ ([, , types]) => types,
688
+ );
689
+
690
+ setParserName(javaThrowsClauseParser, 'javaThrowsClauseParser');
691
+
692
+ // Implements clause: implements Interface1, Interface2
693
+ const javaImplementsClauseParser: Parser<JavaClassOrInterfaceTypeOutput[], string> = promiseCompose(
694
+ createTupleParser([
695
+ createExactSequenceParser('implements'),
696
+ javaWhitespaceParser,
697
+ createSeparatedNonEmptyArrayParser(
698
+ promiseCompose(
699
+ createTupleParser([
700
+ javaClassOrInterfaceTypeParser,
701
+ javaSkippableParser,
702
+ ]),
703
+ ([type]) => type,
704
+ ),
705
+ promiseCompose(
706
+ createTupleParser([
707
+ createExactSequenceParser(','),
708
+ javaSkippableParser,
709
+ ]),
710
+ () => ',',
711
+ ),
712
+ ),
713
+ ]),
714
+ ([, , types]) => types,
715
+ );
716
+
717
+ setParserName(javaImplementsClauseParser, 'javaImplementsClauseParser');
718
+
719
+ // Extends clause: extends Parent
720
+ const javaExtendsClauseParser: Parser<JavaClassOrInterfaceTypeOutput[], string> = promiseCompose(
721
+ createTupleParser([
722
+ createExactSequenceParser('extends'),
723
+ javaWhitespaceParser,
724
+ createSeparatedNonEmptyArrayParser(
725
+ promiseCompose(
726
+ createTupleParser([
727
+ javaClassOrInterfaceTypeParser,
728
+ javaSkippableParser,
729
+ ]),
730
+ ([type]) => type,
731
+ ),
732
+ promiseCompose(
733
+ createTupleParser([
734
+ createExactSequenceParser(','),
735
+ javaSkippableParser,
736
+ ]),
737
+ () => ',',
738
+ ),
739
+ ),
740
+ ]),
741
+ ([, , types]) => types,
742
+ );
743
+
744
+ setParserName(javaExtendsClauseParser, 'javaExtendsClauseParser');
745
+
746
+ // Block statement: { ... }
747
+ type JavaBlockStmtOutput = {
748
+ type: 'BlockStmt';
749
+ statements: unknown[];
750
+ };
751
+
752
+ // Forward declaration - will be defined after expression parsers
753
+ let javaStatementParser: Parser<unknown, string>;
754
+ let javaBlockStmtParserWithStatements: Parser<JavaBlockStmtOutput, string>;
755
+
756
+ // Simple block parser that skips content (used during initial parsing)
757
+ const javaBlockStmtParser: Parser<JavaBlockStmtOutput, string> = createObjectParser({
758
+ _content: javaSkipBalancedBracesParser,
759
+ type: 'BlockStmt' as const,
760
+ statements: [] as unknown[], // Will be replaced by javaBlockStmtParserWithStatements
761
+ });
762
+
763
+ setParserName(javaBlockStmtParser, 'javaBlockStmtParser');
764
+
765
+ // Method declaration
766
+ type JavaMethodDeclarationOutput = {
767
+ type: 'MethodDeclaration';
768
+ modifiers: JavaModifier[];
769
+ annotations: unknown[];
770
+ typeParameters: unknown[];
771
+ type_: unknown; // Return type
772
+ name: JavaSimpleName;
773
+ parameters: JavaParameterOutput[];
774
+ thrownExceptions: JavaClassOrInterfaceTypeOutput[];
775
+ body?: JavaBlockStmtOutput;
776
+ };
777
+
778
+ const javaMethodDeclarationParser: Parser<JavaMethodDeclarationOutput, string> = promiseCompose(
779
+ createTupleParser([
780
+ javaAnnotationsParser,
781
+ javaModifiersParser,
782
+ createOptionalParser(
783
+ promiseCompose(
784
+ createTupleParser([
785
+ javaTypeParametersParser,
786
+ javaSkippableParser,
787
+ ]),
788
+ ([params]) => params,
789
+ ),
790
+ ),
791
+ javaTypeParser,
792
+ javaSkippableParser,
793
+ javaSimpleNameParser,
794
+ javaSkippableParser,
795
+ javaParameterListParser,
796
+ javaSkippableParser,
797
+ createOptionalParser(
798
+ promiseCompose(
799
+ createTupleParser([
800
+ javaThrowsClauseParser,
801
+ javaSkippableParser,
802
+ ]),
803
+ ([throws]) => throws,
804
+ ),
805
+ ),
806
+ createUnionParser([
807
+ (ctx) => javaBlockStmtParserWithStatements(ctx),
808
+ promiseCompose(createExactSequenceParser(';'), () => undefined),
809
+ ]),
810
+ ]),
811
+ ([annotations, modifiers, typeParameters, type_, , name, , parameters, , thrownExceptions, body]) => ({
812
+ type: 'MethodDeclaration' as const,
813
+ modifiers,
814
+ annotations,
815
+ typeParameters: typeParameters ?? [],
816
+ type_,
817
+ name,
818
+ parameters,
819
+ thrownExceptions: thrownExceptions ?? [],
820
+ ...(body ? { body } : {}),
821
+ }),
822
+ );
823
+
824
+ setParserName(javaMethodDeclarationParser, 'javaMethodDeclarationParser');
825
+
826
+ // Field declaration: modifiers type name [= init] [, name2 [= init2]] ;
827
+ type JavaVariableDeclaratorOutput = {
828
+ type: 'VariableDeclarator';
829
+ name: JavaSimpleName;
830
+ type_: unknown; // Variable type
831
+ initializer?: unknown;
832
+ };
833
+
834
+ type JavaFieldDeclarationOutput = {
835
+ type: 'FieldDeclaration';
836
+ modifiers: JavaModifier[];
837
+ annotations: unknown[];
838
+ variables: JavaVariableDeclaratorOutput[];
839
+ };
840
+
841
+ // Expression parsers
842
+ // Forward declaration for recursive expression parsing
843
+ let javaExpressionParser: Parser<unknown, string>;
844
+
845
+ // NameExpr: simple name reference like `foo`
846
+ type JavaNameExprOutput = {
847
+ type: 'NameExpr';
848
+ name: JavaSimpleName;
849
+ };
850
+
851
+ const javaNameExprParser: Parser<JavaNameExprOutput, string> = createObjectParser({
852
+ type: 'NameExpr' as const,
853
+ name: javaSimpleNameParser,
854
+ });
855
+
856
+ setParserName(javaNameExprParser, 'javaNameExprParser');
857
+
858
+ // StringLiteralExpr: "string"
859
+ type JavaStringLiteralExprOutput = {
860
+ type: 'StringLiteralExpr';
861
+ value: string;
862
+ };
863
+
864
+ const javaStringLiteralExprParser: Parser<JavaStringLiteralExprOutput, string> = promiseCompose(
865
+ createRegExpParser(/"(?:[^"\\]|\\.)*"/),
866
+ match => ({
867
+ type: 'StringLiteralExpr' as const,
868
+ value: unescapeJavaString(match[0].slice(1, -1)),
869
+ }),
870
+ );
871
+
872
+ setParserName(javaStringLiteralExprParser, 'javaStringLiteralExprParser');
873
+
874
+ // IntegerLiteralExpr: 123, 0x1F, etc.
875
+ type JavaIntegerLiteralExprOutput = {
876
+ type: 'IntegerLiteralExpr';
877
+ value: string;
878
+ };
879
+
880
+ const javaIntegerLiteralExprParser: Parser<JavaIntegerLiteralExprOutput, string> = promiseCompose(
881
+ createRegExpParser(/(?:0x[0-9a-fA-F]+|0b[01]+|0[0-7]*|[1-9][0-9]*)[lL]?/),
882
+ match => ({
883
+ type: 'IntegerLiteralExpr' as const,
884
+ value: match[0],
885
+ }),
886
+ );
887
+
888
+ setParserName(javaIntegerLiteralExprParser, 'javaIntegerLiteralExprParser');
889
+
890
+ // NullLiteralExpr: null
891
+ type JavaNullLiteralExprOutput = {
892
+ type: 'NullLiteralExpr';
893
+ };
894
+
895
+ const javaNullLiteralExprParser: Parser<JavaNullLiteralExprOutput, string> = createObjectParser({
896
+ _null: createExactSequenceParser('null'),
897
+ type: 'NullLiteralExpr' as const,
898
+ });
899
+
900
+ setParserName(javaNullLiteralExprParser, 'javaNullLiteralExprParser');
901
+
902
+ // BooleanLiteralExpr: true, false
903
+ type JavaBooleanLiteralExprOutput = {
904
+ type: 'BooleanLiteralExpr';
905
+ value: boolean;
906
+ };
907
+
908
+ const javaBooleanLiteralExprParser: Parser<JavaBooleanLiteralExprOutput, string> = createUnionParser([
909
+ promiseCompose(createExactSequenceParser('true'), () => ({ type: 'BooleanLiteralExpr' as const, value: true })),
910
+ promiseCompose(createExactSequenceParser('false'), () => ({ type: 'BooleanLiteralExpr' as const, value: false })),
911
+ ]);
912
+
913
+ setParserName(javaBooleanLiteralExprParser, 'javaBooleanLiteralExprParser');
914
+
915
+ // TypeExpr: used in method references like ParserConfiguration::new
916
+ type JavaTypeExprOutput = {
917
+ type: 'TypeExpr';
918
+ type_: unknown;
919
+ };
920
+
921
+ const javaTypeExprParser: Parser<JavaTypeExprOutput, string> = createObjectParser({
922
+ type: 'TypeExpr' as const,
923
+ type_: javaClassOrInterfaceTypeParser,
924
+ });
925
+
926
+ setParserName(javaTypeExprParser, 'javaTypeExprParser');
927
+
928
+ // MethodReferenceExpr: Foo::bar or Foo::new
929
+ type JavaMethodReferenceExprOutput = {
930
+ type: 'MethodReferenceExpr';
931
+ scope: unknown;
932
+ identifier: string;
933
+ };
934
+
935
+ const javaMethodReferenceExprParser: Parser<JavaMethodReferenceExprOutput, string> = createObjectParser({
936
+ type: 'MethodReferenceExpr' as const,
937
+ scope: javaTypeExprParser,
938
+ _ws1: javaSkippableParser,
939
+ _colons: createExactSequenceParser('::'),
940
+ _ws2: javaSkippableParser,
941
+ identifier: javaIdentifierParser,
942
+ });
943
+
944
+ setParserName(javaMethodReferenceExprParser, 'javaMethodReferenceExprParser');
945
+
946
+ // Argument list: (arg1, arg2, ...)
947
+ const javaArgumentListParser: Parser<unknown[], string> = promiseCompose(
948
+ createTupleParser([
949
+ createExactSequenceParser('('),
950
+ javaSkippableParser,
951
+ createOptionalParser(
952
+ createSeparatedNonEmptyArrayParser(
953
+ promiseCompose(
954
+ createTupleParser([
955
+ (ctx) => javaExpressionParser(ctx),
956
+ javaSkippableParser,
957
+ ]),
958
+ ([expr]) => expr,
959
+ ),
960
+ promiseCompose(
961
+ createTupleParser([
962
+ createExactSequenceParser(','),
963
+ javaSkippableParser,
964
+ ]),
965
+ () => ',',
966
+ ),
967
+ ),
968
+ ),
969
+ javaSkippableParser,
970
+ createExactSequenceParser(')'),
971
+ ]),
972
+ ([, , args]) => args ?? [],
973
+ );
974
+
975
+ setParserName(javaArgumentListParser, 'javaArgumentListParser');
976
+
977
+ // MethodCallExpr: foo.bar(args) or bar(args)
978
+ type JavaMethodCallExprOutput = {
979
+ type: 'MethodCallExpr';
980
+ scope?: unknown;
981
+ name: JavaSimpleName;
982
+ arguments: unknown[];
983
+ };
984
+
985
+ // Simple method call without scope: foo(args)
986
+ const javaSimpleMethodCallExprParser: Parser<JavaMethodCallExprOutput, string> = createObjectParser({
987
+ type: 'MethodCallExpr' as const,
988
+ name: javaSimpleNameParser,
989
+ _ws1: javaSkippableParser,
990
+ arguments: javaArgumentListParser,
991
+ });
992
+
993
+ setParserName(javaSimpleMethodCallExprParser, 'javaSimpleMethodCallExprParser');
994
+
995
+ // ObjectCreationExpr: new ClassName(args) or new ClassName<>(args) (diamond)
996
+ const javaObjectCreationExprParser: Parser<{
997
+ type: 'ObjectCreationExpr';
998
+ type_: JavaClassOrInterfaceTypeOutput;
999
+ arguments: unknown[];
1000
+ }, string> = promiseCompose(
1001
+ createTupleParser([
1002
+ createExactSequenceParser('new'),
1003
+ javaWhitespaceParser, // Must have whitespace after 'new' to avoid matching 'newFoo()' as method call
1004
+ javaClassOrInterfaceTypeParser,
1005
+ javaSkippableParser,
1006
+ // Optional diamond operator <>
1007
+ createOptionalParser(
1008
+ promiseCompose(
1009
+ createTupleParser([
1010
+ createExactSequenceParser('<'),
1011
+ javaSkippableParser,
1012
+ createExactSequenceParser('>'),
1013
+ javaSkippableParser,
1014
+ ]),
1015
+ () => true,
1016
+ ),
1017
+ ),
1018
+ javaArgumentListParser,
1019
+ ]),
1020
+ ([, , type_, , diamond, args]) => ({
1021
+ type: 'ObjectCreationExpr' as const,
1022
+ type_: diamond ? {
1023
+ ...type_,
1024
+ typeArguments: [], // Diamond means empty type arguments
1025
+ } : type_,
1026
+ arguments: args,
1027
+ }),
1028
+ );
1029
+
1030
+ setParserName(javaObjectCreationExprParser, 'javaObjectCreationExprParser');
1031
+
1032
+ // ThisExpr: this
1033
+ type JavaThisExprOutput = {
1034
+ type: 'ThisExpr';
1035
+ };
1036
+
1037
+ const javaThisExprParser: Parser<JavaThisExprOutput, string> = createObjectParser({
1038
+ _this: createExactSequenceParser('this'),
1039
+ type: 'ThisExpr' as const,
1040
+ });
1041
+
1042
+ setParserName(javaThisExprParser, 'javaThisExprParser');
1043
+
1044
+ // CastExpr: (Type) expr
1045
+ type JavaCastExprOutput = {
1046
+ type: 'CastExpr';
1047
+ type_: unknown;
1048
+ expression: unknown;
1049
+ };
1050
+
1051
+ // Forward declaration - will be defined later after primary expressions
1052
+ let javaCastExprParser: Parser<unknown, string>;
1053
+
1054
+ // Parenthesized expression: (expr)
1055
+ type JavaEnclosedExprOutput = {
1056
+ type: 'EnclosedExpr';
1057
+ inner: unknown;
1058
+ };
1059
+
1060
+ const javaEnclosedExprParser: Parser<JavaEnclosedExprOutput, string> = createObjectParser({
1061
+ _open: createExactSequenceParser('('),
1062
+ _ws1: javaSkippableParser,
1063
+ type: 'EnclosedExpr' as const,
1064
+ inner: (ctx: Parameters<typeof javaExpressionParser>[0]) => javaExpressionParser(ctx),
1065
+ _ws2: javaSkippableParser,
1066
+ _close: createExactSequenceParser(')'),
1067
+ });
1068
+
1069
+ setParserName(javaEnclosedExprParser, 'javaEnclosedExprParser');
1070
+
1071
+ // Lambda parameter (can be just identifier or Type identifier)
1072
+ const javaLambdaParameterParser: Parser<unknown, string> = promiseCompose(
1073
+ createTupleParser([
1074
+ createOptionalParser(
1075
+ promiseCompose(
1076
+ createTupleParser([
1077
+ javaTypeParser,
1078
+ javaWhitespaceParser,
1079
+ ]),
1080
+ ([type_]) => type_,
1081
+ ),
1082
+ ),
1083
+ javaSimpleNameParser,
1084
+ ]),
1085
+ ([type_, name]) => ({
1086
+ type: 'Parameter' as const,
1087
+ annotations: [],
1088
+ modifiers: [],
1089
+ isVarArgs: false,
1090
+ varArgsAnnotations: [],
1091
+ name,
1092
+ type_: type_ ?? { type: 'UnknownType', annotations: [] },
1093
+ }),
1094
+ );
1095
+
1096
+ setParserName(javaLambdaParameterParser, 'javaLambdaParameterParser');
1097
+
1098
+ // Lambda expression: (params) -> body or x -> body
1099
+ // LambdaExpr with parenthesized parameters
1100
+ const javaLambdaWithParensParser: Parser<unknown, string> = promiseCompose(
1101
+ createTupleParser([
1102
+ createExactSequenceParser('('),
1103
+ javaSkippableParser,
1104
+ createOptionalParser(
1105
+ createSeparatedNonEmptyArrayParser(
1106
+ promiseCompose(
1107
+ createTupleParser([
1108
+ javaLambdaParameterParser,
1109
+ javaSkippableParser,
1110
+ ]),
1111
+ ([param]) => param,
1112
+ ),
1113
+ promiseCompose(
1114
+ createTupleParser([
1115
+ createExactSequenceParser(','),
1116
+ javaSkippableParser,
1117
+ ]),
1118
+ () => ',',
1119
+ ),
1120
+ ),
1121
+ ),
1122
+ createExactSequenceParser(')'),
1123
+ javaSkippableParser,
1124
+ createExactSequenceParser('->'),
1125
+ javaSkippableParser,
1126
+ createDisjunctionParser([
1127
+ (ctx) => javaBlockStmtParserWithStatements(ctx), // Block body
1128
+ (ctx) => javaExpressionParser(ctx), // Expression body
1129
+ ]),
1130
+ ]),
1131
+ ([, , params, , , , , body]) => ({
1132
+ type: 'LambdaExpr' as const,
1133
+ parameters: params ?? [],
1134
+ // Wrap expression body in ExpressionStmt to match javaparser format
1135
+ body: body && typeof body === 'object' && 'type' in body && body.type === 'BlockStmt'
1136
+ ? body
1137
+ : { type: 'ExpressionStmt' as const, expression: body },
1138
+ isEnclosingParameters: true,
1139
+ }),
1140
+ );
1141
+
1142
+ setParserName(javaLambdaWithParensParser, 'javaLambdaWithParensParser');
1143
+
1144
+ // Lambda with single identifier parameter (no parens): x -> body
1145
+ const javaLambdaSingleParamParser: Parser<unknown, string> = promiseCompose(
1146
+ createTupleParser([
1147
+ javaSimpleNameParser,
1148
+ javaSkippableParser,
1149
+ createExactSequenceParser('->'),
1150
+ javaSkippableParser,
1151
+ createDisjunctionParser([
1152
+ (ctx) => javaBlockStmtParserWithStatements(ctx), // Block body
1153
+ (ctx) => javaExpressionParser(ctx), // Expression body
1154
+ ]),
1155
+ ]),
1156
+ ([param, , , , body]) => ({
1157
+ type: 'LambdaExpr' as const,
1158
+ parameters: [{
1159
+ type: 'Parameter' as const,
1160
+ annotations: [],
1161
+ modifiers: [],
1162
+ isVarArgs: false,
1163
+ varArgsAnnotations: [],
1164
+ name: param,
1165
+ type_: { type: 'UnknownType', annotations: [] },
1166
+ }],
1167
+ // Wrap expression body in ExpressionStmt to match javaparser format
1168
+ body: body && typeof body === 'object' && 'type' in body && body.type === 'BlockStmt'
1169
+ ? body
1170
+ : { type: 'ExpressionStmt' as const, expression: body },
1171
+ isEnclosingParameters: false,
1172
+ }),
1173
+ );
1174
+
1175
+ setParserName(javaLambdaSingleParamParser, 'javaLambdaSingleParamParser');
1176
+
1177
+ // Primary expression (without method calls chained)
1178
+ const javaPrimaryExprParser: Parser<unknown, string> = createDisjunctionParser([
1179
+ javaStringLiteralExprParser,
1180
+ javaIntegerLiteralExprParser,
1181
+ javaNullLiteralExprParser,
1182
+ javaBooleanLiteralExprParser,
1183
+ javaThisExprParser, // this - must come before NameExpr
1184
+ javaObjectCreationExprParser, // new Foo() - must come before NameExpr
1185
+ javaMethodReferenceExprParser,
1186
+ javaSimpleMethodCallExprParser, // foo() - must come before NameExpr
1187
+ (ctx) => javaCastExprParser(ctx), // Cast - must come before enclosed
1188
+ javaLambdaWithParensParser, // (x, y) -> expr - must come before enclosed
1189
+ javaEnclosedExprParser, // (expr) - parenthesized expressions
1190
+ javaLambdaSingleParamParser, // x -> expr - must come before NameExpr
1191
+ javaNameExprParser, // Must be last since it matches any identifier
1192
+ ]);
1193
+
1194
+ setParserName(javaPrimaryExprParser, 'javaPrimaryExprParser');
1195
+
1196
+ // FieldAccessExpr: scope.field
1197
+ type JavaFieldAccessExprOutput = {
1198
+ type: 'FieldAccessExpr';
1199
+ scope: unknown;
1200
+ name: JavaSimpleName;
1201
+ };
1202
+
1203
+ // Helper to convert a NameExpr to a ClassOrInterfaceType for ClassExpr
1204
+ function nameExprToType(expr: unknown): unknown {
1205
+ if (expr && typeof expr === 'object' && 'type' in expr) {
1206
+ if (expr.type === 'NameExpr') {
1207
+ const nameExpr = expr as { type: 'NameExpr'; name: JavaSimpleName };
1208
+ return {
1209
+ type: 'ClassOrInterfaceType' as const,
1210
+ name: nameExpr.name,
1211
+ annotations: [],
1212
+ };
1213
+ }
1214
+ if (expr.type === 'FieldAccessExpr') {
1215
+ const fieldAccess = expr as { type: 'FieldAccessExpr'; scope: unknown; name: JavaSimpleName };
1216
+ return {
1217
+ type: 'ClassOrInterfaceType' as const,
1218
+ scope: nameExprToType(fieldAccess.scope),
1219
+ name: fieldAccess.name,
1220
+ annotations: [],
1221
+ };
1222
+ }
1223
+ }
1224
+ return expr;
1225
+ }
1226
+
1227
+ // Expression with optional member access chain: expr.field, expr.method(args), expr::method, expr[index]
1228
+ const javaMemberAccessExprParser: Parser<unknown, string> = promiseCompose(
1229
+ createTupleParser([
1230
+ javaPrimaryExprParser,
1231
+ createArrayParser(
1232
+ createDisjunctionParser([
1233
+ // Method reference: ::identifier
1234
+ promiseCompose(
1235
+ createTupleParser([
1236
+ javaSkippableParser,
1237
+ createExactSequenceParser('::'),
1238
+ javaSkippableParser,
1239
+ javaIdentifierParser,
1240
+ ]),
1241
+ ([, , , identifier]) => ({ type: 'methodReference' as const, identifier }),
1242
+ ),
1243
+ // Array access: [index]
1244
+ promiseCompose(
1245
+ createTupleParser([
1246
+ javaSkippableParser,
1247
+ createExactSequenceParser('['),
1248
+ javaSkippableParser,
1249
+ (ctx) => javaExpressionParser(ctx),
1250
+ javaSkippableParser,
1251
+ createExactSequenceParser(']'),
1252
+ ]),
1253
+ ([, , , index]) => ({ type: 'arrayAccess' as const, index }),
1254
+ ),
1255
+ // Class literal: .class
1256
+ promiseCompose(
1257
+ createTupleParser([
1258
+ javaSkippableParser,
1259
+ createExactSequenceParser('.'),
1260
+ javaSkippableParser,
1261
+ createExactSequenceParser('class'),
1262
+ ]),
1263
+ () => ({ type: 'classLiteral' as const }),
1264
+ ),
1265
+ // Field access or method call: .name[(args)]
1266
+ promiseCompose(
1267
+ createTupleParser([
1268
+ javaSkippableParser,
1269
+ createExactSequenceParser('.'),
1270
+ javaSkippableParser,
1271
+ javaSimpleNameParser,
1272
+ javaSkippableParser,
1273
+ createOptionalParser(javaArgumentListParser),
1274
+ ]),
1275
+ ([, , , name, , args]) => ({ type: 'member' as const, name, arguments: args }),
1276
+ ),
1277
+ ]),
1278
+ ),
1279
+ ]),
1280
+ ([primary, members]) => {
1281
+ let result = primary;
1282
+ for (const member of members) {
1283
+ if (member.type === 'methodReference') {
1284
+ result = {
1285
+ type: 'MethodReferenceExpr' as const,
1286
+ scope: result,
1287
+ identifier: member.identifier,
1288
+ };
1289
+ } else if (member.type === 'arrayAccess') {
1290
+ result = {
1291
+ type: 'ArrayAccessExpr' as const,
1292
+ name: result,
1293
+ index: member.index,
1294
+ };
1295
+ } else if (member.type === 'classLiteral') {
1296
+ // Convert the scope to a type for ClassExpr
1297
+ result = {
1298
+ type: 'ClassExpr' as const,
1299
+ type_: nameExprToType(result),
1300
+ };
1301
+ } else if (member.arguments !== undefined) {
1302
+ result = {
1303
+ type: 'MethodCallExpr' as const,
1304
+ scope: result,
1305
+ name: member.name,
1306
+ arguments: member.arguments,
1307
+ };
1308
+ } else {
1309
+ result = {
1310
+ type: 'FieldAccessExpr' as const,
1311
+ scope: result,
1312
+ name: member.name,
1313
+ };
1314
+ }
1315
+ }
1316
+ return result;
1317
+ },
1318
+ );
1319
+
1320
+ setParserName(javaMemberAccessExprParser, 'javaMemberAccessExprParser');
1321
+
1322
+ // Postfix expression: expr++ or expr--
1323
+ const javaPostfixExprParser: Parser<unknown, string> = promiseCompose(
1324
+ createTupleParser([
1325
+ javaMemberAccessExprParser,
1326
+ createOptionalParser(
1327
+ createDisjunctionParser([
1328
+ promiseCompose(createExactSequenceParser('++'), () => 'POSTFIX_INCREMENT' as const),
1329
+ promiseCompose(createExactSequenceParser('--'), () => 'POSTFIX_DECREMENT' as const),
1330
+ ]),
1331
+ ),
1332
+ ]),
1333
+ ([expr, operator]) => {
1334
+ if (operator) {
1335
+ return {
1336
+ type: 'UnaryExpr' as const,
1337
+ operator,
1338
+ expression: expr,
1339
+ };
1340
+ }
1341
+ return expr;
1342
+ },
1343
+ );
1344
+
1345
+ setParserName(javaPostfixExprParser, 'javaPostfixExprParser');
1346
+
1347
+ // Define cast expression: (Type) expr
1348
+ javaCastExprParser = createObjectParser({
1349
+ _open: createExactSequenceParser('('),
1350
+ _ws1: javaSkippableParser,
1351
+ type: 'CastExpr' as const,
1352
+ type_: javaTypeParser,
1353
+ _ws2: javaSkippableParser,
1354
+ _close: createExactSequenceParser(')'),
1355
+ _ws3: javaSkippableParser,
1356
+ expression: javaMemberAccessExprParser,
1357
+ });
1358
+
1359
+ setParserName(javaCastExprParser, 'javaCastExprParser');
1360
+
1361
+ // Unary expression: -expr, !expr, +expr, ++expr, --expr
1362
+ type JavaUnaryExprOutput = {
1363
+ type: 'UnaryExpr';
1364
+ operator: string;
1365
+ expression: unknown;
1366
+ };
1367
+
1368
+ const javaUnaryExprParser: Parser<unknown, string> = createDisjunctionParser([
1369
+ // Pre-increment/decrement: ++x, --x
1370
+ promiseCompose(
1371
+ createTupleParser([
1372
+ createDisjunctionParser([
1373
+ promiseCompose(createExactSequenceParser('++'), () => 'PREFIX_INCREMENT'),
1374
+ promiseCompose(createExactSequenceParser('--'), () => 'PREFIX_DECREMENT'),
1375
+ ]),
1376
+ javaSkippableParser,
1377
+ (ctx) => javaUnaryExprParser(ctx),
1378
+ ]),
1379
+ ([operator, , expression]) => ({
1380
+ type: 'UnaryExpr' as const,
1381
+ operator,
1382
+ expression,
1383
+ }),
1384
+ ),
1385
+ // Unary minus, plus, not
1386
+ promiseCompose(
1387
+ createTupleParser([
1388
+ createDisjunctionParser([
1389
+ promiseCompose(createExactSequenceParser('-'), () => 'MINUS'),
1390
+ promiseCompose(createExactSequenceParser('+'), () => 'PLUS'),
1391
+ promiseCompose(createExactSequenceParser('!'), () => 'LOGICAL_COMPLEMENT'),
1392
+ ]),
1393
+ javaSkippableParser,
1394
+ (ctx) => javaUnaryExprParser(ctx), // Recursive for --x, !!x, etc.
1395
+ ]),
1396
+ ([operator, , expression]) => ({
1397
+ type: 'UnaryExpr' as const,
1398
+ operator,
1399
+ expression,
1400
+ }),
1401
+ ),
1402
+ // Non-unary (postfix/primary/member access)
1403
+ javaPostfixExprParser,
1404
+ ]);
1405
+
1406
+ setParserName(javaUnaryExprParser, 'javaUnaryExprParser');
1407
+
1408
+ // Multiplicative operator (*, /, %)
1409
+ const javaMultiplicativeOperatorParser: Parser<string, string> = createDisjunctionParser([
1410
+ promiseCompose(createExactSequenceParser('*'), () => 'MULTIPLY'),
1411
+ promiseCompose(createExactSequenceParser('/'), () => 'DIVIDE'),
1412
+ promiseCompose(createExactSequenceParser('%'), () => 'REMAINDER'),
1413
+ ]);
1414
+
1415
+ // Multiplicative expression
1416
+ const javaMultiplicativeExprParser: Parser<unknown, string> = promiseCompose(
1417
+ createTupleParser([
1418
+ javaUnaryExprParser,
1419
+ createArrayParser(
1420
+ promiseCompose(
1421
+ createTupleParser([
1422
+ javaSkippableParser,
1423
+ javaMultiplicativeOperatorParser,
1424
+ javaSkippableParser,
1425
+ javaUnaryExprParser,
1426
+ ]),
1427
+ ([, operator, , right]) => ({ operator, right }),
1428
+ ),
1429
+ ),
1430
+ ]),
1431
+ ([left, operations]) => {
1432
+ let result = left;
1433
+ for (const op of operations) {
1434
+ result = {
1435
+ type: 'BinaryExpr' as const,
1436
+ left: result,
1437
+ right: op.right,
1438
+ operator: op.operator,
1439
+ };
1440
+ }
1441
+ return result;
1442
+ },
1443
+ );
1444
+
1445
+ setParserName(javaMultiplicativeExprParser, 'javaMultiplicativeExprParser');
1446
+
1447
+ // Additive operator (+, -)
1448
+ const javaAdditiveOperatorParser: Parser<string, string> = createDisjunctionParser([
1449
+ promiseCompose(createExactSequenceParser('+'), () => 'PLUS'),
1450
+ promiseCompose(createExactSequenceParser('-'), () => 'MINUS'),
1451
+ ]);
1452
+
1453
+ // Additive expression (handles string concatenation and arithmetic)
1454
+ const javaAdditiveExprParser: Parser<unknown, string> = promiseCompose(
1455
+ createTupleParser([
1456
+ javaMultiplicativeExprParser,
1457
+ createArrayParser(
1458
+ promiseCompose(
1459
+ createTupleParser([
1460
+ javaSkippableParser,
1461
+ javaAdditiveOperatorParser,
1462
+ javaSkippableParser,
1463
+ javaUnaryExprParser,
1464
+ ]),
1465
+ ([, operator, , right]) => ({ operator, right }),
1466
+ ),
1467
+ ),
1468
+ ]),
1469
+ ([left, operations]) => {
1470
+ let result = left;
1471
+ for (const op of operations) {
1472
+ result = {
1473
+ type: 'BinaryExpr' as const,
1474
+ left: result,
1475
+ right: op.right,
1476
+ operator: op.operator,
1477
+ };
1478
+ }
1479
+ return result;
1480
+ },
1481
+ );
1482
+
1483
+ setParserName(javaAdditiveExprParser, 'javaAdditiveExprParser');
1484
+
1485
+ // InstanceOfExpr: expr instanceof Type
1486
+ type JavaInstanceOfExprOutput = {
1487
+ type: 'InstanceOfExpr';
1488
+ expression: unknown;
1489
+ type_: unknown;
1490
+ };
1491
+
1492
+ // Relational expression with instanceof
1493
+ const javaRelationalExprParser: Parser<unknown, string> = promiseCompose(
1494
+ createTupleParser([
1495
+ javaAdditiveExprParser,
1496
+ createOptionalParser(
1497
+ promiseCompose(
1498
+ createTupleParser([
1499
+ javaSkippableParser,
1500
+ createExactSequenceParser('instanceof'),
1501
+ javaWhitespaceParser,
1502
+ javaTypeParser,
1503
+ ]),
1504
+ ([, , , type_]) => ({ type: 'instanceof' as const, type_ }),
1505
+ ),
1506
+ ),
1507
+ ]),
1508
+ ([expr, instanceOf]) => {
1509
+ if (instanceOf) {
1510
+ return {
1511
+ type: 'InstanceOfExpr' as const,
1512
+ expression: expr,
1513
+ type_: instanceOf.type_,
1514
+ };
1515
+ }
1516
+ return expr;
1517
+ },
1518
+ );
1519
+
1520
+ setParserName(javaRelationalExprParser, 'javaRelationalExprParser');
1521
+
1522
+ // Comparison operator
1523
+ const javaComparisonOperatorParser: Parser<string, string> = createDisjunctionParser([
1524
+ promiseCompose(createExactSequenceParser('<='), () => 'LESS_EQUALS'),
1525
+ promiseCompose(createExactSequenceParser('>='), () => 'GREATER_EQUALS'),
1526
+ promiseCompose(createExactSequenceParser('=='), () => 'EQUALS'),
1527
+ promiseCompose(createExactSequenceParser('!='), () => 'NOT_EQUALS'),
1528
+ promiseCompose(createExactSequenceParser('<'), () => 'LESS'),
1529
+ promiseCompose(createExactSequenceParser('>'), () => 'GREATER'),
1530
+ ]);
1531
+
1532
+ // Comparison expression (relational and equality)
1533
+ const javaComparisonExprParser: Parser<unknown, string> = promiseCompose(
1534
+ createTupleParser([
1535
+ javaRelationalExprParser,
1536
+ createOptionalParser(
1537
+ promiseCompose(
1538
+ createTupleParser([
1539
+ javaSkippableParser,
1540
+ javaComparisonOperatorParser,
1541
+ javaSkippableParser,
1542
+ javaRelationalExprParser,
1543
+ ]),
1544
+ ([, operator, , right]) => ({ operator, right }),
1545
+ ),
1546
+ ),
1547
+ ]),
1548
+ ([left, comparison]) => {
1549
+ if (comparison) {
1550
+ return {
1551
+ type: 'BinaryExpr' as const,
1552
+ left,
1553
+ right: comparison.right,
1554
+ operator: comparison.operator,
1555
+ };
1556
+ }
1557
+ return left;
1558
+ },
1559
+ );
1560
+
1561
+ setParserName(javaComparisonExprParser, 'javaComparisonExprParser');
1562
+
1563
+ // Logical AND expression
1564
+ const javaLogicalAndExprParser: Parser<unknown, string> = promiseCompose(
1565
+ createTupleParser([
1566
+ javaComparisonExprParser,
1567
+ createArrayParser(
1568
+ promiseCompose(
1569
+ createTupleParser([
1570
+ javaSkippableParser,
1571
+ createExactSequenceParser('&&'),
1572
+ javaSkippableParser,
1573
+ javaComparisonExprParser,
1574
+ ]),
1575
+ ([, , , right]) => right,
1576
+ ),
1577
+ ),
1578
+ ]),
1579
+ ([left, rights]) => {
1580
+ let result = left;
1581
+ for (const right of rights) {
1582
+ result = {
1583
+ type: 'BinaryExpr' as const,
1584
+ left: result,
1585
+ right,
1586
+ operator: 'AND',
1587
+ };
1588
+ }
1589
+ return result;
1590
+ },
1591
+ );
1592
+
1593
+ setParserName(javaLogicalAndExprParser, 'javaLogicalAndExprParser');
1594
+
1595
+ // Logical OR expression
1596
+ const javaLogicalOrExprParser: Parser<unknown, string> = promiseCompose(
1597
+ createTupleParser([
1598
+ javaLogicalAndExprParser,
1599
+ createArrayParser(
1600
+ promiseCompose(
1601
+ createTupleParser([
1602
+ javaSkippableParser,
1603
+ createExactSequenceParser('||'),
1604
+ javaSkippableParser,
1605
+ javaLogicalAndExprParser,
1606
+ ]),
1607
+ ([, , , right]) => right,
1608
+ ),
1609
+ ),
1610
+ ]),
1611
+ ([left, rights]) => {
1612
+ let result = left;
1613
+ for (const right of rights) {
1614
+ result = {
1615
+ type: 'BinaryExpr' as const,
1616
+ left: result,
1617
+ right,
1618
+ operator: 'OR',
1619
+ };
1620
+ }
1621
+ return result;
1622
+ },
1623
+ );
1624
+
1625
+ setParserName(javaLogicalOrExprParser, 'javaLogicalOrExprParser');
1626
+
1627
+ // Ternary (conditional) expression: condition ? thenExpr : elseExpr
1628
+ type JavaConditionalExprOutput = {
1629
+ type: 'ConditionalExpr';
1630
+ condition: unknown;
1631
+ thenExpr: unknown;
1632
+ elseExpr: unknown;
1633
+ };
1634
+
1635
+ const javaTernaryExprParser: Parser<unknown, string> = promiseCompose(
1636
+ createTupleParser([
1637
+ javaLogicalOrExprParser,
1638
+ createOptionalParser(
1639
+ promiseCompose(
1640
+ createTupleParser([
1641
+ javaSkippableParser,
1642
+ createExactSequenceParser('?'),
1643
+ javaSkippableParser,
1644
+ (ctx) => javaTernaryExprParser(ctx), // thenExpr can be another ternary
1645
+ javaSkippableParser,
1646
+ createExactSequenceParser(':'),
1647
+ javaSkippableParser,
1648
+ (ctx) => javaTernaryExprParser(ctx), // elseExpr can be another ternary
1649
+ ]),
1650
+ ([, , , thenExpr, , , , elseExpr]) => ({ thenExpr, elseExpr }),
1651
+ ),
1652
+ ),
1653
+ ]),
1654
+ ([condition, ternary]) => {
1655
+ if (ternary) {
1656
+ return {
1657
+ type: 'ConditionalExpr' as const,
1658
+ condition,
1659
+ thenExpr: ternary.thenExpr,
1660
+ elseExpr: ternary.elseExpr,
1661
+ };
1662
+ }
1663
+ return condition;
1664
+ },
1665
+ );
1666
+
1667
+ setParserName(javaTernaryExprParser, 'javaTernaryExprParser');
1668
+
1669
+ // Assignment operator
1670
+ const javaAssignOperatorParser: Parser<string, string> = createDisjunctionParser([
1671
+ promiseCompose(createExactSequenceParser('='), () => 'ASSIGN'),
1672
+ promiseCompose(createExactSequenceParser('+='), () => 'PLUS'),
1673
+ promiseCompose(createExactSequenceParser('-='), () => 'MINUS'),
1674
+ promiseCompose(createExactSequenceParser('*='), () => 'MULTIPLY'),
1675
+ promiseCompose(createExactSequenceParser('/='), () => 'DIVIDE'),
1676
+ ]);
1677
+
1678
+ // Expression with optional assignment
1679
+ javaExpressionParser = promiseCompose(
1680
+ createTupleParser([
1681
+ javaTernaryExprParser,
1682
+ createOptionalParser(
1683
+ promiseCompose(
1684
+ createTupleParser([
1685
+ javaSkippableParser,
1686
+ javaAssignOperatorParser,
1687
+ javaSkippableParser,
1688
+ (ctx) => javaExpressionParser(ctx), // Recursive for chained assignment
1689
+ ]),
1690
+ ([, operator, , value]) => ({ operator, value }),
1691
+ ),
1692
+ ),
1693
+ ]),
1694
+ ([target, assignment]) => {
1695
+ if (assignment) {
1696
+ return {
1697
+ type: 'AssignExpr' as const,
1698
+ target,
1699
+ value: assignment.value,
1700
+ operator: assignment.operator,
1701
+ };
1702
+ }
1703
+ return target;
1704
+ },
1705
+ );
1706
+
1707
+ setParserName(javaExpressionParser, 'javaExpressionParser');
1708
+
1709
+ // Skip balanced expression (fallback for complex initializers we can't parse yet)
1710
+ const javaSkipInitializerParser: Parser<unknown, string> = createObjectParser({
1711
+ _content: createRegExpParser(/[^,;{}]+/),
1712
+ type: 'UnparsedExpr' as const,
1713
+ });
1714
+
1715
+ // Expression parser with fallback
1716
+ const javaInitializerExprParser: Parser<unknown, string> = createDisjunctionParser([
1717
+ javaExpressionParser,
1718
+ javaSkipInitializerParser,
1719
+ ]);
1720
+
1721
+ // Statement parsers
1722
+ // ReturnStmt: return expr;
1723
+ type JavaReturnStmtOutput = {
1724
+ type: 'ReturnStmt';
1725
+ expression?: unknown;
1726
+ };
1727
+
1728
+ const javaReturnStmtParser: Parser<JavaReturnStmtOutput, string> = promiseCompose(
1729
+ createTupleParser([
1730
+ createExactSequenceParser('return'),
1731
+ javaSkippableParser,
1732
+ createOptionalParser(
1733
+ promiseCompose(
1734
+ createTupleParser([
1735
+ javaExpressionParser,
1736
+ javaSkippableParser,
1737
+ ]),
1738
+ ([expr]) => expr,
1739
+ ),
1740
+ ),
1741
+ createExactSequenceParser(';'),
1742
+ ]),
1743
+ ([, , expression]) => ({
1744
+ type: 'ReturnStmt' as const,
1745
+ ...(expression ? { expression } : {}),
1746
+ }),
1747
+ );
1748
+
1749
+ setParserName(javaReturnStmtParser, 'javaReturnStmtParser');
1750
+
1751
+ // ThrowStmt: throw expr;
1752
+ type JavaThrowStmtOutput = {
1753
+ type: 'ThrowStmt';
1754
+ expression: unknown;
1755
+ };
1756
+
1757
+ const javaThrowStmtParser: Parser<JavaThrowStmtOutput, string> = createObjectParser({
1758
+ _throw: createExactSequenceParser('throw'),
1759
+ _ws1: javaSkippableParser,
1760
+ type: 'ThrowStmt' as const,
1761
+ expression: javaExpressionParser,
1762
+ _ws2: javaSkippableParser,
1763
+ _semi: createExactSequenceParser(';'),
1764
+ });
1765
+
1766
+ setParserName(javaThrowStmtParser, 'javaThrowStmtParser');
1767
+
1768
+ // ExpressionStmt: expr;
1769
+ type JavaExpressionStmtOutput = {
1770
+ type: 'ExpressionStmt';
1771
+ expression: unknown;
1772
+ };
1773
+
1774
+ const javaExpressionStmtParser: Parser<JavaExpressionStmtOutput, string> = createObjectParser({
1775
+ type: 'ExpressionStmt' as const,
1776
+ expression: javaExpressionParser,
1777
+ _ws1: javaSkippableParser,
1778
+ _semi: createExactSequenceParser(';'),
1779
+ });
1780
+
1781
+ setParserName(javaExpressionStmtParser, 'javaExpressionStmtParser');
1782
+
1783
+ // IfStmt: if (cond) then [else elseStmt]
1784
+ type JavaIfStmtOutput = {
1785
+ type: 'IfStmt';
1786
+ condition: unknown;
1787
+ thenStmt: unknown;
1788
+ elseStmt?: unknown;
1789
+ };
1790
+
1791
+ const javaIfStmtParser: Parser<JavaIfStmtOutput, string> = promiseCompose(
1792
+ createTupleParser([
1793
+ createExactSequenceParser('if'),
1794
+ javaSkippableParser,
1795
+ createExactSequenceParser('('),
1796
+ javaSkippableParser,
1797
+ javaExpressionParser,
1798
+ javaSkippableParser,
1799
+ createExactSequenceParser(')'),
1800
+ javaSkippableParser,
1801
+ (ctx) => javaStatementParser(ctx),
1802
+ createOptionalParser(
1803
+ promiseCompose(
1804
+ createTupleParser([
1805
+ javaSkippableParser,
1806
+ createExactSequenceParser('else'),
1807
+ javaSkippableParser,
1808
+ (ctx) => javaStatementParser(ctx),
1809
+ ]),
1810
+ ([, , , elseStmt]) => elseStmt,
1811
+ ),
1812
+ ),
1813
+ ]),
1814
+ ([, , , , condition, , , , thenStmt, elseStmt]) => ({
1815
+ type: 'IfStmt' as const,
1816
+ condition,
1817
+ thenStmt,
1818
+ ...(elseStmt ? { elseStmt } : {}),
1819
+ }),
1820
+ );
1821
+
1822
+ setParserName(javaIfStmtParser, 'javaIfStmtParser');
1823
+
1824
+ // Define the block statement parser with actual statements
1825
+ javaBlockStmtParserWithStatements = createObjectParser({
1826
+ _open: createExactSequenceParser('{'),
1827
+ _ws1: javaSkippableParser,
1828
+ type: 'BlockStmt' as const,
1829
+ statements: createArrayParser(
1830
+ promiseCompose(
1831
+ createTupleParser([
1832
+ (ctx) => javaStatementParser(ctx),
1833
+ javaSkippableParser,
1834
+ ]),
1835
+ ([stmt]) => stmt,
1836
+ ),
1837
+ ),
1838
+ _close: createExactSequenceParser('}'),
1839
+ });
1840
+
1841
+ setParserName(javaBlockStmtParserWithStatements, 'javaBlockStmtParserWithStatements');
1842
+
1843
+ // VariableDeclarationExpr: Type name = expr
1844
+ type JavaVariableDeclarationExprOutput = {
1845
+ type: 'VariableDeclarationExpr';
1846
+ modifiers: JavaModifier[];
1847
+ annotations: unknown[];
1848
+ variables: JavaVariableDeclaratorOutput[];
1849
+ };
1850
+
1851
+ const javaVariableDeclarationExprParser: Parser<JavaVariableDeclarationExprOutput, string> = promiseCompose(
1852
+ createTupleParser([
1853
+ javaAnnotationsParser,
1854
+ javaModifiersParser,
1855
+ javaTypeParser,
1856
+ javaSkippableParser,
1857
+ createSeparatedNonEmptyArrayParser(
1858
+ promiseCompose(
1859
+ createTupleParser([
1860
+ javaSimpleNameParser,
1861
+ javaSkippableParser,
1862
+ createOptionalParser(
1863
+ promiseCompose(
1864
+ createTupleParser([
1865
+ createExactSequenceParser('='),
1866
+ javaSkippableParser,
1867
+ javaExpressionParser,
1868
+ ]),
1869
+ ([, , init]) => init,
1870
+ ),
1871
+ ),
1872
+ ]),
1873
+ ([name, , initializer]) => ({ name, initializer }),
1874
+ ),
1875
+ promiseCompose(
1876
+ createTupleParser([
1877
+ createExactSequenceParser(','),
1878
+ javaSkippableParser,
1879
+ ]),
1880
+ () => ',',
1881
+ ),
1882
+ ),
1883
+ ]),
1884
+ ([annotations, modifiers, type_, , variables]) => ({
1885
+ type: 'VariableDeclarationExpr' as const,
1886
+ modifiers,
1887
+ annotations,
1888
+ variables: variables.map(v => ({
1889
+ type: 'VariableDeclarator' as const,
1890
+ name: v.name,
1891
+ type_,
1892
+ ...(v.initializer ? { initializer: v.initializer } : {}),
1893
+ })),
1894
+ }),
1895
+ );
1896
+
1897
+ setParserName(javaVariableDeclarationExprParser, 'javaVariableDeclarationExprParser');
1898
+
1899
+ // Local variable declaration statement
1900
+ type JavaExpressionStmtOutputForVarDecl = {
1901
+ type: 'ExpressionStmt';
1902
+ expression: JavaVariableDeclarationExprOutput;
1903
+ };
1904
+
1905
+ const javaLocalVarDeclStmtParser: Parser<JavaExpressionStmtOutputForVarDecl, string> = createObjectParser({
1906
+ type: 'ExpressionStmt' as const,
1907
+ expression: javaVariableDeclarationExprParser,
1908
+ _ws1: javaSkippableParser,
1909
+ _semi: createExactSequenceParser(';'),
1910
+ });
1911
+
1912
+ setParserName(javaLocalVarDeclStmtParser, 'javaLocalVarDeclStmtParser');
1913
+
1914
+ // ForStmt: for (init; condition; update) body
1915
+ type JavaForStmtOutput = {
1916
+ type: 'ForStmt';
1917
+ initialization: unknown[];
1918
+ compare?: unknown;
1919
+ update: unknown[];
1920
+ body: unknown;
1921
+ };
1922
+
1923
+ const javaForStmtParser: Parser<JavaForStmtOutput, string> = promiseCompose(
1924
+ createTupleParser([
1925
+ createExactSequenceParser('for'),
1926
+ javaSkippableParser,
1927
+ createExactSequenceParser('('),
1928
+ javaSkippableParser,
1929
+ // Initialization: can be variable declaration or expression list
1930
+ createOptionalParser(
1931
+ createDisjunctionParser([
1932
+ javaVariableDeclarationExprParser,
1933
+ javaExpressionParser,
1934
+ ]),
1935
+ ),
1936
+ javaSkippableParser,
1937
+ createExactSequenceParser(';'),
1938
+ javaSkippableParser,
1939
+ // Condition
1940
+ createOptionalParser(javaExpressionParser),
1941
+ javaSkippableParser,
1942
+ createExactSequenceParser(';'),
1943
+ javaSkippableParser,
1944
+ // Update: expression list (comma-separated)
1945
+ createOptionalParser(
1946
+ createSeparatedNonEmptyArrayParser(
1947
+ promiseCompose(
1948
+ createTupleParser([
1949
+ javaExpressionParser,
1950
+ javaSkippableParser,
1951
+ ]),
1952
+ ([expr]) => expr,
1953
+ ),
1954
+ promiseCompose(
1955
+ createTupleParser([
1956
+ createExactSequenceParser(','),
1957
+ javaSkippableParser,
1958
+ ]),
1959
+ () => ',',
1960
+ ),
1961
+ ),
1962
+ ),
1963
+ javaSkippableParser,
1964
+ createExactSequenceParser(')'),
1965
+ javaSkippableParser,
1966
+ (ctx) => javaStatementParser(ctx),
1967
+ ]),
1968
+ ([, , , , init, , , , condition, , , , update, , , , body]) => ({
1969
+ type: 'ForStmt' as const,
1970
+ initialization: init ? [init] : [],
1971
+ ...(condition ? { compare: condition } : {}),
1972
+ update: update ?? [],
1973
+ body,
1974
+ }),
1975
+ );
1976
+
1977
+ setParserName(javaForStmtParser, 'javaForStmtParser');
1978
+
1979
+ // ForEachStmt: for (Type var : collection) body
1980
+ type JavaForEachStmtOutput = {
1981
+ type: 'ForEachStmt';
1982
+ variable: unknown;
1983
+ iterable: unknown;
1984
+ body: unknown;
1985
+ };
1986
+
1987
+ const javaForEachStmtParser: Parser<JavaForEachStmtOutput, string> = createObjectParser({
1988
+ _for: createExactSequenceParser('for'),
1989
+ _ws1: javaSkippableParser,
1990
+ _open: createExactSequenceParser('('),
1991
+ _ws2: javaSkippableParser,
1992
+ type: 'ForEachStmt' as const,
1993
+ variable: javaVariableDeclarationExprParser,
1994
+ _ws3: javaSkippableParser,
1995
+ _colon: createExactSequenceParser(':'),
1996
+ _ws4: javaSkippableParser,
1997
+ iterable: javaExpressionParser,
1998
+ _ws5: javaSkippableParser,
1999
+ _close: createExactSequenceParser(')'),
2000
+ _ws6: javaSkippableParser,
2001
+ body: (ctx: Parameters<typeof javaStatementParser>[0]) => javaStatementParser(ctx),
2002
+ });
2003
+
2004
+ setParserName(javaForEachStmtParser, 'javaForEachStmtParser');
2005
+
2006
+ // ExplicitConstructorInvocationStmt: this(...) or super(...)
2007
+ type JavaExplicitConstructorInvocationStmtOutput = {
2008
+ type: 'ExplicitConstructorInvocationStmt';
2009
+ isThis: boolean;
2010
+ arguments: unknown[];
2011
+ expression?: unknown;
2012
+ typeArguments?: unknown[];
2013
+ };
2014
+
2015
+ const javaExplicitConstructorInvocationStmtParser: Parser<JavaExplicitConstructorInvocationStmtOutput, string> = promiseCompose(
2016
+ createTupleParser([
2017
+ createDisjunctionParser([
2018
+ promiseCompose(createExactSequenceParser('this'), () => true as const),
2019
+ promiseCompose(createExactSequenceParser('super'), () => false as const),
2020
+ ]),
2021
+ javaSkippableParser,
2022
+ createExactSequenceParser('('),
2023
+ javaSkippableParser,
2024
+ createOptionalParser(
2025
+ createSeparatedNonEmptyArrayParser(
2026
+ promiseCompose(
2027
+ createTupleParser([
2028
+ javaExpressionParser,
2029
+ javaSkippableParser,
2030
+ ]),
2031
+ ([expr]) => expr,
2032
+ ),
2033
+ promiseCompose(
2034
+ createTupleParser([
2035
+ createExactSequenceParser(','),
2036
+ javaSkippableParser,
2037
+ ]),
2038
+ () => ',',
2039
+ ),
2040
+ ),
2041
+ ),
2042
+ createExactSequenceParser(')'),
2043
+ javaSkippableParser,
2044
+ createExactSequenceParser(';'),
2045
+ ]),
2046
+ ([isThis, , , , args]) => ({
2047
+ type: 'ExplicitConstructorInvocationStmt' as const,
2048
+ isThis,
2049
+ arguments: args ?? [],
2050
+ }),
2051
+ );
2052
+
2053
+ setParserName(javaExplicitConstructorInvocationStmtParser, 'javaExplicitConstructorInvocationStmtParser');
2054
+
2055
+ // CatchClause for try-catch
2056
+ type JavaCatchClauseOutput = {
2057
+ type: 'CatchClause';
2058
+ parameter: JavaParameterOutput;
2059
+ body: JavaBlockStmtOutput;
2060
+ };
2061
+
2062
+ const javaCatchClauseParser: Parser<JavaCatchClauseOutput, string> = createObjectParser({
2063
+ _catch: createExactSequenceParser('catch'),
2064
+ _ws1: javaSkippableParser,
2065
+ _open: createExactSequenceParser('('),
2066
+ _ws2: javaSkippableParser,
2067
+ type: 'CatchClause' as const,
2068
+ parameter: javaParameterParser,
2069
+ _ws3: javaSkippableParser,
2070
+ _close: createExactSequenceParser(')'),
2071
+ _ws4: javaSkippableParser,
2072
+ body: (ctx: Parameters<typeof javaBlockStmtParserWithStatements>[0]) => javaBlockStmtParserWithStatements(ctx),
2073
+ });
2074
+
2075
+ setParserName(javaCatchClauseParser, 'javaCatchClauseParser');
2076
+
2077
+ // TryStmt: try { } catch (...) { } finally { }
2078
+ // Also supports try-with-resources: try (Resource r = ...) { } catch (...) { }
2079
+ type JavaTryStmtOutput = {
2080
+ type: 'TryStmt';
2081
+ resources: unknown[];
2082
+ tryBlock: JavaBlockStmtOutput;
2083
+ catchClauses: JavaCatchClauseOutput[];
2084
+ finallyBlock?: JavaBlockStmtOutput;
2085
+ };
2086
+
2087
+ const javaTryStmtParser: Parser<JavaTryStmtOutput, string> = promiseCompose(
2088
+ createTupleParser([
2089
+ createExactSequenceParser('try'),
2090
+ javaSkippableParser,
2091
+ // Optional resources for try-with-resources: try (Resource r = ...)
2092
+ createOptionalParser(
2093
+ promiseCompose(
2094
+ createTupleParser([
2095
+ createExactSequenceParser('('),
2096
+ javaSkippableParser,
2097
+ createSeparatedNonEmptyArrayParser(
2098
+ promiseCompose(
2099
+ createTupleParser([
2100
+ javaVariableDeclarationExprParser,
2101
+ javaSkippableParser,
2102
+ ]),
2103
+ ([resource]) => resource,
2104
+ ),
2105
+ promiseCompose(
2106
+ createTupleParser([
2107
+ createExactSequenceParser(';'),
2108
+ javaSkippableParser,
2109
+ ]),
2110
+ () => ';',
2111
+ ),
2112
+ ),
2113
+ // Optional trailing semicolon
2114
+ createOptionalParser(createExactSequenceParser(';')),
2115
+ javaSkippableParser,
2116
+ createExactSequenceParser(')'),
2117
+ javaSkippableParser,
2118
+ ]),
2119
+ ([, , resources]) => resources,
2120
+ ),
2121
+ ),
2122
+ (ctx) => javaBlockStmtParserWithStatements(ctx),
2123
+ javaSkippableParser,
2124
+ createArrayParser(
2125
+ promiseCompose(
2126
+ createTupleParser([
2127
+ javaCatchClauseParser,
2128
+ javaSkippableParser,
2129
+ ]),
2130
+ ([clause]) => clause,
2131
+ ),
2132
+ ),
2133
+ createOptionalParser(
2134
+ promiseCompose(
2135
+ createTupleParser([
2136
+ createExactSequenceParser('finally'),
2137
+ javaSkippableParser,
2138
+ (ctx) => javaBlockStmtParserWithStatements(ctx),
2139
+ ]),
2140
+ ([, , block]) => block,
2141
+ ),
2142
+ ),
2143
+ ]),
2144
+ ([, , resources, tryBlock, , catchClauses, finallyBlock]) => ({
2145
+ type: 'TryStmt' as const,
2146
+ resources: resources ?? [],
2147
+ tryBlock,
2148
+ catchClauses,
2149
+ ...(finallyBlock ? { finallyBlock } : {}),
2150
+ }),
2151
+ );
2152
+
2153
+ setParserName(javaTryStmtParser, 'javaTryStmtParser');
2154
+
2155
+ // SwitchEntry: case CONST: statements or default: statements
2156
+ // In JavaParser, each case/default is its own entry
2157
+ type JavaSwitchEntryOutput = {
2158
+ type: 'SwitchEntry';
2159
+ isDefault: boolean;
2160
+ labels: unknown[];
2161
+ statements: unknown[];
2162
+ type_: 'STATEMENT_GROUP';
2163
+ };
2164
+
2165
+ const javaSwitchEntryParser: Parser<JavaSwitchEntryOutput, string> = createDisjunctionParser([
2166
+ // case expression:
2167
+ promiseCompose(
2168
+ createTupleParser([
2169
+ createExactSequenceParser('case'),
2170
+ javaSkippableParser,
2171
+ javaExpressionParser,
2172
+ javaSkippableParser,
2173
+ createExactSequenceParser(':'),
2174
+ javaSkippableParser,
2175
+ // Parse statements until we hit another case/default or closing brace
2176
+ createArrayParser(
2177
+ promiseCompose(
2178
+ createTupleParser([
2179
+ (ctx) => javaStatementParser(ctx),
2180
+ javaSkippableParser,
2181
+ ]),
2182
+ ([stmt]) => stmt,
2183
+ ),
2184
+ ),
2185
+ ]),
2186
+ ([, , expr, , , , statements]) => ({
2187
+ type: 'SwitchEntry' as const,
2188
+ isDefault: false,
2189
+ labels: [expr],
2190
+ statements,
2191
+ type_: 'STATEMENT_GROUP' as const,
2192
+ }),
2193
+ ),
2194
+ // default:
2195
+ promiseCompose(
2196
+ createTupleParser([
2197
+ createExactSequenceParser('default'),
2198
+ javaSkippableParser,
2199
+ createExactSequenceParser(':'),
2200
+ javaSkippableParser,
2201
+ // Parse statements until we hit another case/default or closing brace
2202
+ createArrayParser(
2203
+ promiseCompose(
2204
+ createTupleParser([
2205
+ (ctx) => javaStatementParser(ctx),
2206
+ javaSkippableParser,
2207
+ ]),
2208
+ ([stmt]) => stmt,
2209
+ ),
2210
+ ),
2211
+ ]),
2212
+ ([, , , , statements]) => ({
2213
+ type: 'SwitchEntry' as const,
2214
+ isDefault: true,
2215
+ labels: [],
2216
+ statements,
2217
+ type_: 'STATEMENT_GROUP' as const,
2218
+ }),
2219
+ ),
2220
+ ]);
2221
+
2222
+ setParserName(javaSwitchEntryParser, 'javaSwitchEntryParser');
2223
+
2224
+ // SwitchStmt: switch (selector) { entries }
2225
+ type JavaSwitchStmtOutput = {
2226
+ type: 'SwitchStmt';
2227
+ selector: unknown;
2228
+ entries: JavaSwitchEntryOutput[];
2229
+ };
2230
+
2231
+ const javaSwitchStmtParser: Parser<JavaSwitchStmtOutput, string> = promiseCompose(
2232
+ createTupleParser([
2233
+ createExactSequenceParser('switch'),
2234
+ javaSkippableParser,
2235
+ createExactSequenceParser('('),
2236
+ javaSkippableParser,
2237
+ javaExpressionParser,
2238
+ javaSkippableParser,
2239
+ createExactSequenceParser(')'),
2240
+ javaSkippableParser,
2241
+ createExactSequenceParser('{'),
2242
+ javaSkippableParser,
2243
+ createArrayParser(
2244
+ promiseCompose(
2245
+ createTupleParser([
2246
+ javaSwitchEntryParser,
2247
+ javaSkippableParser,
2248
+ ]),
2249
+ ([entry]) => entry,
2250
+ ),
2251
+ ),
2252
+ createExactSequenceParser('}'),
2253
+ ]),
2254
+ ([, , , , selector, , , , , , entries]) => ({
2255
+ type: 'SwitchStmt' as const,
2256
+ selector,
2257
+ entries,
2258
+ }),
2259
+ );
2260
+
2261
+ setParserName(javaSwitchStmtParser, 'javaSwitchStmtParser');
2262
+
2263
+ // Statement parser - combines all statement types
2264
+ javaStatementParser = createDisjunctionParser([
2265
+ javaReturnStmtParser,
2266
+ javaThrowStmtParser,
2267
+ javaIfStmtParser,
2268
+ javaForEachStmtParser, // Must come before ForStmt (both start with 'for')
2269
+ javaForStmtParser,
2270
+ javaTryStmtParser,
2271
+ javaSwitchStmtParser,
2272
+ javaExplicitConstructorInvocationStmtParser, // Must come before expression statement
2273
+ javaBlockStmtParserWithStatements,
2274
+ javaLocalVarDeclStmtParser, // Local variable declarations
2275
+ javaExpressionStmtParser, // Must be last since it's most general
2276
+ ]);
2277
+
2278
+ setParserName(javaStatementParser, 'javaStatementParser');
2279
+
2280
+ const javaFieldDeclarationParser: Parser<JavaFieldDeclarationOutput, string> = promiseCompose(
2281
+ createTupleParser([
2282
+ javaAnnotationsParser,
2283
+ javaModifiersParser,
2284
+ javaTypeParser,
2285
+ javaSkippableParser,
2286
+ createSeparatedNonEmptyArrayParser(
2287
+ promiseCompose(
2288
+ createTupleParser([
2289
+ javaSimpleNameParser,
2290
+ javaSkippableParser,
2291
+ createOptionalParser(
2292
+ promiseCompose(
2293
+ createTupleParser([
2294
+ createExactSequenceParser('='),
2295
+ javaSkippableParser,
2296
+ javaInitializerExprParser,
2297
+ ]),
2298
+ ([, , init]) => init,
2299
+ ),
2300
+ ),
2301
+ ]),
2302
+ ([name, , initializer]) => ({ name, initializer }),
2303
+ ),
2304
+ promiseCompose(
2305
+ createTupleParser([
2306
+ createExactSequenceParser(','),
2307
+ javaSkippableParser,
2308
+ ]),
2309
+ () => ',',
2310
+ ),
2311
+ ),
2312
+ javaSkippableParser,
2313
+ createExactSequenceParser(';'),
2314
+ ]),
2315
+ ([annotations, modifiers, type_, , variables]) => ({
2316
+ type: 'FieldDeclaration' as const,
2317
+ modifiers,
2318
+ annotations,
2319
+ variables: variables.map(v => ({
2320
+ type: 'VariableDeclarator' as const,
2321
+ name: v.name,
2322
+ type_,
2323
+ ...(v.initializer ? { initializer: v.initializer } : {}),
2324
+ })),
2325
+ }),
2326
+ );
2327
+
2328
+ setParserName(javaFieldDeclarationParser, 'javaFieldDeclarationParser');
2329
+
2330
+ // Constructor declaration
2331
+ type JavaConstructorDeclarationOutput = {
2332
+ type: 'ConstructorDeclaration';
2333
+ modifiers: JavaModifier[];
2334
+ annotations: unknown[];
2335
+ typeParameters: unknown[];
2336
+ name: JavaSimpleName;
2337
+ parameters: JavaParameterOutput[];
2338
+ thrownExceptions: JavaClassOrInterfaceTypeOutput[];
2339
+ body: JavaBlockStmtOutput;
2340
+ };
2341
+
2342
+ const javaConstructorDeclarationParser: Parser<JavaConstructorDeclarationOutput, string> = promiseCompose(
2343
+ createTupleParser([
2344
+ javaAnnotationsParser,
2345
+ javaModifiersParser,
2346
+ // Constructor name (same as class name)
2347
+ javaSimpleNameParser,
2348
+ javaSkippableParser,
2349
+ javaParameterListParser,
2350
+ javaSkippableParser,
2351
+ createOptionalParser(
2352
+ promiseCompose(
2353
+ createTupleParser([
2354
+ javaThrowsClauseParser,
2355
+ javaSkippableParser,
2356
+ ]),
2357
+ ([throws]) => throws,
2358
+ ),
2359
+ ),
2360
+ (ctx) => javaBlockStmtParserWithStatements(ctx),
2361
+ ]),
2362
+ ([annotations, modifiers, name, , parameters, , thrownExceptions, body]) => ({
2363
+ type: 'ConstructorDeclaration' as const,
2364
+ modifiers,
2365
+ annotations,
2366
+ typeParameters: [],
2367
+ name,
2368
+ parameters,
2369
+ thrownExceptions: thrownExceptions ?? [],
2370
+ body,
2371
+ }),
2372
+ );
2373
+
2374
+ setParserName(javaConstructorDeclarationParser, 'javaConstructorDeclarationParser');
2375
+
2376
+ // Body declaration (member) - forward declaration
2377
+ type JavaBodyDeclarationOutput = JavaMethodDeclarationOutput | JavaFieldDeclarationOutput | JavaConstructorDeclarationOutput | unknown;
2378
+
2379
+ // We need to try method first because field declaration also starts with modifiers + type + name
2380
+ // But constructors don't have a return type, so we try constructor after field fails
2381
+ // Note: javaBodyDeclarationParser is reassigned later to include nested type declarations
2382
+ let javaBodyDeclarationParser: Parser<JavaBodyDeclarationOutput, string> = createDisjunctionParser([
2383
+ javaMethodDeclarationParser,
2384
+ javaConstructorDeclarationParser,
2385
+ javaFieldDeclarationParser,
2386
+ ]);
2387
+
2388
+ setParserName(javaBodyDeclarationParser, 'javaBodyDeclarationParser');
2389
+
2390
+ // Class body: { member1 member2 ... }
2391
+ const javaClassBodyParser: Parser<JavaBodyDeclarationOutput[], string> = promiseCompose(
2392
+ createTupleParser([
2393
+ createExactSequenceParser('{'),
2394
+ javaSkippableParser,
2395
+ createArrayParser(
2396
+ promiseCompose(
2397
+ createTupleParser([
2398
+ (ctx) => javaBodyDeclarationParser(ctx), // Use function to pick up reassigned value
2399
+ javaSkippableParser,
2400
+ ]),
2401
+ ([member]) => member,
2402
+ ),
2403
+ ),
2404
+ createExactSequenceParser('}'),
2405
+ ]),
2406
+ ([, , members]) => members,
2407
+ );
2408
+
2409
+ // Class or Interface declaration (combined as javaparser does)
2410
+ type JavaClassOrInterfaceDeclarationOutput = {
2411
+ type: 'ClassOrInterfaceDeclaration';
2412
+ modifiers: JavaModifier[];
2413
+ annotations: JavaAnnotation[];
2414
+ name: JavaSimpleName;
2415
+ isInterface: boolean;
2416
+ typeParameters: unknown[];
2417
+ extendedTypes: unknown[];
2418
+ implementedTypes: unknown[];
2419
+ permittedTypes: unknown[];
2420
+ members: unknown[];
2421
+ };
2422
+
2423
+ const javaClassDeclarationParser: Parser<JavaClassOrInterfaceDeclarationOutput, string> = promiseCompose(
2424
+ createTupleParser([
2425
+ javaSkippableParser, // Skip leading comments (e.g., javadoc)
2426
+ javaAnnotationsParser,
2427
+ javaModifiersParser,
2428
+ createExactSequenceParser('class'),
2429
+ javaSkippableParser,
2430
+ javaSimpleNameParser,
2431
+ javaSkippableParser,
2432
+ createOptionalParser(
2433
+ promiseCompose(
2434
+ createTupleParser([javaTypeParametersParser, javaSkippableParser]),
2435
+ ([params]) => params,
2436
+ ),
2437
+ ),
2438
+ createOptionalParser(
2439
+ promiseCompose(
2440
+ createTupleParser([javaExtendsClauseParser, javaSkippableParser]),
2441
+ ([types]) => types,
2442
+ ),
2443
+ ),
2444
+ createOptionalParser(
2445
+ promiseCompose(
2446
+ createTupleParser([javaImplementsClauseParser, javaSkippableParser]),
2447
+ ([types]) => types,
2448
+ ),
2449
+ ),
2450
+ // TODO: permits clause
2451
+ javaClassBodyParser,
2452
+ ]),
2453
+ ([, annotations, modifiers, , , name, , typeParameters, extendedTypes, implementedTypes, members]) => ({
2454
+ type: 'ClassOrInterfaceDeclaration' as const,
2455
+ modifiers,
2456
+ annotations,
2457
+ name,
2458
+ isInterface: false,
2459
+ typeParameters: typeParameters ?? [],
2460
+ extendedTypes: extendedTypes ?? [],
2461
+ implementedTypes: implementedTypes ?? [],
2462
+ permittedTypes: [],
2463
+ members,
2464
+ }),
2465
+ );
2466
+
2467
+ setParserName(javaClassDeclarationParser, 'javaClassDeclarationParser');
2468
+
2469
+ const javaInterfaceDeclarationParser: Parser<JavaClassOrInterfaceDeclarationOutput, string> = promiseCompose(
2470
+ createTupleParser([
2471
+ javaSkippableParser, // Skip leading comments (e.g., javadoc)
2472
+ javaAnnotationsParser,
2473
+ javaModifiersParser,
2474
+ createExactSequenceParser('interface'),
2475
+ javaSkippableParser,
2476
+ javaSimpleNameParser,
2477
+ javaSkippableParser,
2478
+ createOptionalParser(
2479
+ promiseCompose(
2480
+ createTupleParser([javaTypeParametersParser, javaSkippableParser]),
2481
+ ([params]) => params,
2482
+ ),
2483
+ ),
2484
+ createOptionalParser(
2485
+ promiseCompose(
2486
+ createTupleParser([javaExtendsClauseParser, javaSkippableParser]),
2487
+ ([types]) => types,
2488
+ ),
2489
+ ),
2490
+ // TODO: permits clause
2491
+ javaClassBodyParser,
2492
+ ]),
2493
+ ([, annotations, modifiers, , , name, , typeParameters, extendedTypes, members]) => ({
2494
+ type: 'ClassOrInterfaceDeclaration' as const,
2495
+ modifiers,
2496
+ annotations,
2497
+ name,
2498
+ isInterface: true,
2499
+ typeParameters: typeParameters ?? [],
2500
+ extendedTypes: extendedTypes ?? [],
2501
+ implementedTypes: [],
2502
+ permittedTypes: [],
2503
+ members,
2504
+ }),
2505
+ );
2506
+
2507
+ setParserName(javaInterfaceDeclarationParser, 'javaInterfaceDeclarationParser');
2508
+
2509
+ // Enum declaration
2510
+ const javaEnumDeclarationParser: Parser<JavaEnumDeclarationOutput, string> = promiseCompose(
2511
+ createTupleParser([
2512
+ javaSkippableParser, // Skip leading comments
2513
+ javaAnnotationsParser,
2514
+ javaModifiersParser,
2515
+ createExactSequenceParser('enum'),
2516
+ javaSkippableParser,
2517
+ javaSimpleNameParser,
2518
+ javaSkippableParser,
2519
+ // TODO: implements clause
2520
+ // TODO: parse enum entries and members
2521
+ javaSkipBalancedBracesParser, // Skip body for now
2522
+ ]),
2523
+ ([, annotations, modifiers, , , name]) => ({
2524
+ type: 'EnumDeclaration' as const,
2525
+ modifiers,
2526
+ annotations,
2527
+ name,
2528
+ implementedTypes: [],
2529
+ entries: [],
2530
+ members: [],
2531
+ }),
2532
+ );
2533
+
2534
+ setParserName(javaEnumDeclarationParser, 'javaEnumDeclarationParser');
2535
+
2536
+ // Record declaration
2537
+ const javaRecordDeclarationParser: Parser<JavaRecordDeclaration, string> = promiseCompose(
2538
+ createTupleParser([
2539
+ javaAnnotationsParser,
2540
+ javaModifiersParser,
2541
+ createExactSequenceParser('record'),
2542
+ javaSkippableParser,
2543
+ javaIdentifierParser,
2544
+ javaSkippableParser,
2545
+ // TODO: type parameters
2546
+ // TODO: record components (required)
2547
+ // TODO: implements clause
2548
+ javaSkipBalancedBracesParser, // Skip body for now
2549
+ ]),
2550
+ ([annotations, modifiers, , , name]) => ({
2551
+ type: 'record' as const,
2552
+ annotations,
2553
+ modifiers,
2554
+ name,
2555
+ }),
2556
+ );
2557
+
2558
+ setParserName(javaRecordDeclarationParser, 'javaRecordDeclarationParser');
2559
+
2560
+ // Annotation type declaration
2561
+ const javaAnnotationDeclarationParser: Parser<JavaAnnotationTypeDeclaration, string> = promiseCompose(
2562
+ createTupleParser([
2563
+ javaAnnotationsParser,
2564
+ javaModifiersParser,
2565
+ createExactSequenceParser('@'),
2566
+ javaOptionalWhitespaceParser,
2567
+ createExactSequenceParser('interface'),
2568
+ javaSkippableParser,
2569
+ javaIdentifierParser,
2570
+ javaSkippableParser,
2571
+ javaSkipBalancedBracesParser, // Skip body for now
2572
+ ]),
2573
+ ([annotations, modifiers, , , , , name]) => ({
2574
+ type: 'annotation' as const,
2575
+ annotations,
2576
+ modifiers,
2577
+ name,
2578
+ }),
2579
+ );
2580
+
2581
+ setParserName(javaAnnotationDeclarationParser, 'javaAnnotationDeclarationParser');
2582
+
2583
+ // Type declaration (any kind)
2584
+ const javaTypeDeclarationParser: Parser<JavaTypeDeclaration, string> = createDisjunctionParser([
2585
+ javaAnnotationDeclarationParser, // Must come before class (both start with annotations/modifiers)
2586
+ javaClassDeclarationParser,
2587
+ javaInterfaceDeclarationParser,
2588
+ javaEnumDeclarationParser,
2589
+ javaRecordDeclarationParser,
2590
+ ]);
2591
+
2592
+ // Now reassign javaBodyDeclarationParser to include nested type declarations
2593
+ javaBodyDeclarationParser = createDisjunctionParser([
2594
+ javaMethodDeclarationParser,
2595
+ javaConstructorDeclarationParser,
2596
+ javaFieldDeclarationParser,
2597
+ javaClassDeclarationParser, // Nested class
2598
+ javaInterfaceDeclarationParser, // Nested interface
2599
+ javaEnumDeclarationParser, // Nested enum
2600
+ ]);
2601
+
2602
+ setParserName(javaBodyDeclarationParser, 'javaBodyDeclarationParser');
2603
+
2604
+ setParserName(javaTypeDeclarationParser, 'javaTypeDeclarationParser');
2605
+
2606
+ // Compilation unit (top-level)
2607
+ export const javaCompilationUnitParser = createObjectParser({
2608
+ type: 'CompilationUnit' as const,
2609
+ _ws1: javaSkippableParser,
2610
+ packageDeclaration: createOptionalParser(
2611
+ promiseCompose(
2612
+ createTupleParser([
2613
+ javaPackageDeclarationParserNew,
2614
+ javaSkippableParser,
2615
+ ]),
2616
+ ([pkg]) => pkg,
2617
+ ),
2618
+ ),
2619
+ imports: createArrayParser(
2620
+ promiseCompose(
2621
+ createTupleParser([
2622
+ javaImportDeclarationParser,
2623
+ javaSkippableParser,
2624
+ ]),
2625
+ ([imp]) => imp,
2626
+ ),
2627
+ ),
2628
+ types: createArrayParser(
2629
+ promiseCompose(
2630
+ createTupleParser([
2631
+ javaTypeDeclarationParser,
2632
+ javaSkippableParser,
2633
+ ]),
2634
+ ([type]) => type,
2635
+ ),
2636
+ ),
2637
+ _ws2: javaSkippableParser,
2638
+ });
2639
+
2640
+ setParserName(javaCompilationUnitParser, 'javaCompilationUnitParser');