semantifold 0.3.0 → 0.4.0

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 (297) hide show
  1. package/README.md +58 -15
  2. package/build/index.d.ts +48 -2
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +57 -8
  5. package/build/src/artifact-path.d.ts +23 -1
  6. package/build/src/artifact-path.d.ts.map +1 -1
  7. package/build/src/artifact-path.js +45 -3
  8. package/build/src/artifacts.d.ts.map +1 -1
  9. package/build/src/artifacts.js +66 -1
  10. package/build/src/backends/c-validation.d.ts.map +1 -1
  11. package/build/src/backends/c-validation.js +7 -3
  12. package/build/src/backends/cpp-validation.d.ts.map +1 -1
  13. package/build/src/backends/cpp-validation.js +7 -3
  14. package/build/src/backends/csharp.js +7 -1
  15. package/build/src/backends/dart-runtime.d.ts +2 -0
  16. package/build/src/backends/dart-runtime.d.ts.map +1 -0
  17. package/build/src/backends/dart-runtime.js +41 -0
  18. package/build/src/backends/dart.d.ts +20 -0
  19. package/build/src/backends/dart.d.ts.map +1 -0
  20. package/build/src/backends/dart.js +321 -0
  21. package/build/src/backends/effects.d.ts +60 -0
  22. package/build/src/backends/effects.d.ts.map +1 -0
  23. package/build/src/backends/effects.js +746 -0
  24. package/build/src/backends/go.js +18 -4
  25. package/build/src/backends/identifiers.d.ts +36 -4
  26. package/build/src/backends/identifiers.d.ts.map +1 -1
  27. package/build/src/backends/identifiers.js +154 -10
  28. package/build/src/backends/index.d.ts.map +1 -1
  29. package/build/src/backends/index.js +27 -4
  30. package/build/src/backends/ios.d.ts +68 -0
  31. package/build/src/backends/ios.d.ts.map +1 -0
  32. package/build/src/backends/ios.js +1503 -0
  33. package/build/src/backends/java.d.ts.map +1 -1
  34. package/build/src/backends/java.js +429 -36
  35. package/build/src/backends/javascript.d.ts +6 -0
  36. package/build/src/backends/javascript.d.ts.map +1 -1
  37. package/build/src/backends/javascript.js +380 -24
  38. package/build/src/backends/kotlin-runtime.d.ts +3 -0
  39. package/build/src/backends/kotlin-runtime.d.ts.map +1 -0
  40. package/build/src/backends/kotlin-runtime.js +29 -0
  41. package/build/src/backends/kotlin.d.ts +23 -0
  42. package/build/src/backends/kotlin.d.ts.map +1 -0
  43. package/build/src/backends/kotlin.js +136 -0
  44. package/build/src/backends/native-validation.d.ts +2 -2
  45. package/build/src/backends/native-validation.d.ts.map +1 -1
  46. package/build/src/backends/native-validation.js +2 -2
  47. package/build/src/backends/ordered-expressions.d.ts.map +1 -1
  48. package/build/src/backends/ordered-expressions.js +39 -7
  49. package/build/src/backends/php-stdlib-support.d.ts +19 -0
  50. package/build/src/backends/php-stdlib-support.d.ts.map +1 -0
  51. package/build/src/backends/php-stdlib-support.js +227 -0
  52. package/build/src/backends/php.d.ts.map +1 -1
  53. package/build/src/backends/php.js +448 -33
  54. package/build/src/backends/program.d.ts +81 -0
  55. package/build/src/backends/program.d.ts.map +1 -0
  56. package/build/src/backends/program.js +1308 -0
  57. package/build/src/backends/python.js +7 -1
  58. package/build/src/backends/ruby.d.ts.map +1 -1
  59. package/build/src/backends/ruby.js +310 -24
  60. package/build/src/backends/rust-runtime.d.ts +7 -0
  61. package/build/src/backends/rust-runtime.d.ts.map +1 -0
  62. package/build/src/backends/rust-runtime.js +32 -0
  63. package/build/src/backends/rust-validation.d.ts +9 -0
  64. package/build/src/backends/rust-validation.d.ts.map +1 -0
  65. package/build/src/backends/rust-validation.js +78 -0
  66. package/build/src/backends/rust.d.ts +24 -0
  67. package/build/src/backends/rust.d.ts.map +1 -0
  68. package/build/src/backends/rust.js +344 -0
  69. package/build/src/backends/scalars.d.ts +14 -6
  70. package/build/src/backends/scalars.d.ts.map +1 -1
  71. package/build/src/backends/scalars.js +167 -17
  72. package/build/src/backends/shared.d.ts +23 -4
  73. package/build/src/backends/shared.d.ts.map +1 -1
  74. package/build/src/backends/shared.js +2158 -62
  75. package/build/src/backends/stdlib-support.d.ts +14 -0
  76. package/build/src/backends/stdlib-support.d.ts.map +1 -0
  77. package/build/src/backends/stdlib-support.js +237 -0
  78. package/build/src/backends/swift-runtime.d.ts +3 -0
  79. package/build/src/backends/swift-runtime.d.ts.map +1 -0
  80. package/build/src/backends/swift-runtime.js +14 -0
  81. package/build/src/backends/swift.d.ts +8 -0
  82. package/build/src/backends/swift.d.ts.map +1 -0
  83. package/build/src/backends/swift.js +127 -0
  84. package/build/src/backends/typescript.d.ts.map +1 -1
  85. package/build/src/backends/typescript.js +344 -24
  86. package/build/src/backends/wasm.d.ts +43 -0
  87. package/build/src/backends/wasm.d.ts.map +1 -0
  88. package/build/src/backends/wasm.js +2164 -0
  89. package/build/src/backends/writer.d.ts +235 -4
  90. package/build/src/backends/writer.d.ts.map +1 -1
  91. package/build/src/backends/writer.js +468 -3
  92. package/build/src/diagnostic.d.ts +4 -3
  93. package/build/src/diagnostic.d.ts.map +1 -1
  94. package/build/src/diagnostic.js +5 -3
  95. package/build/src/frontends/c.d.ts.map +1 -1
  96. package/build/src/frontends/c.js +5 -3
  97. package/build/src/frontends/cpp.d.ts.map +1 -1
  98. package/build/src/frontends/cpp.js +5 -3
  99. package/build/src/frontends/csharp.d.ts.map +1 -1
  100. package/build/src/frontends/csharp.js +7 -3
  101. package/build/src/frontends/dart.d.ts +10 -0
  102. package/build/src/frontends/dart.d.ts.map +1 -0
  103. package/build/src/frontends/dart.js +913 -0
  104. package/build/src/frontends/index.d.ts +3 -1
  105. package/build/src/frontends/index.d.ts.map +1 -1
  106. package/build/src/frontends/index.js +15 -5
  107. package/build/src/frontends/java.d.ts +110 -1
  108. package/build/src/frontends/java.d.ts.map +1 -1
  109. package/build/src/frontends/java.js +1725 -70
  110. package/build/src/frontends/javascript-typescript.d.ts +69 -1
  111. package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
  112. package/build/src/frontends/javascript-typescript.js +1825 -93
  113. package/build/src/frontends/kotlin.d.ts +10 -0
  114. package/build/src/frontends/kotlin.d.ts.map +1 -0
  115. package/build/src/frontends/kotlin.js +685 -0
  116. package/build/src/frontends/php.d.ts +118 -1
  117. package/build/src/frontends/php.d.ts.map +1 -1
  118. package/build/src/frontends/php.js +1583 -76
  119. package/build/src/frontends/program.d.ts +74 -0
  120. package/build/src/frontends/program.d.ts.map +1 -0
  121. package/build/src/frontends/program.js +989 -0
  122. package/build/src/frontends/ruby.d.ts +68 -1
  123. package/build/src/frontends/ruby.d.ts.map +1 -1
  124. package/build/src/frontends/ruby.js +1446 -101
  125. package/build/src/frontends/rust-parser.d.ts +11 -0
  126. package/build/src/frontends/rust-parser.d.ts.map +1 -0
  127. package/build/src/frontends/rust-parser.js +15 -0
  128. package/build/src/frontends/rust.d.ts +14 -0
  129. package/build/src/frontends/rust.d.ts.map +1 -0
  130. package/build/src/frontends/rust.js +715 -0
  131. package/build/src/frontends/scalars.d.ts +10 -0
  132. package/build/src/frontends/scalars.d.ts.map +1 -1
  133. package/build/src/frontends/scalars.js +28 -2
  134. package/build/src/frontends/swift.d.ts +10 -0
  135. package/build/src/frontends/swift.d.ts.map +1 -0
  136. package/build/src/frontends/swift.js +860 -0
  137. package/build/src/frontends/types.d.ts +186 -0
  138. package/build/src/frontends/types.d.ts.map +1 -0
  139. package/build/src/frontends/types.js +634 -0
  140. package/build/src/language-registry.d.ts +46 -4
  141. package/build/src/language-registry.d.ts.map +1 -1
  142. package/build/src/language-registry.js +167 -13
  143. package/build/src/mapping.d.ts +2 -2
  144. package/build/src/mapping.d.ts.map +1 -1
  145. package/build/src/mapping.js +31 -10
  146. package/build/src/semantic/capabilities.d.ts +66 -0
  147. package/build/src/semantic/capabilities.d.ts.map +1 -0
  148. package/build/src/semantic/capabilities.js +649 -0
  149. package/build/src/semantic/effects.d.ts +26 -0
  150. package/build/src/semantic/effects.d.ts.map +1 -0
  151. package/build/src/semantic/effects.js +764 -0
  152. package/build/src/semantic/generics.d.ts +23 -0
  153. package/build/src/semantic/generics.d.ts.map +1 -0
  154. package/build/src/semantic/generics.js +61 -0
  155. package/build/src/semantic/lifetime.d.ts +37 -0
  156. package/build/src/semantic/lifetime.d.ts.map +1 -0
  157. package/build/src/semantic/lifetime.js +527 -0
  158. package/build/src/semantic/provenance.d.ts +9 -2
  159. package/build/src/semantic/provenance.d.ts.map +1 -1
  160. package/build/src/semantic/provenance.js +462 -20
  161. package/build/src/semantic/scalars.d.ts +11 -0
  162. package/build/src/semantic/scalars.d.ts.map +1 -1
  163. package/build/src/semantic/scalars.js +16 -1
  164. package/build/src/semantic/stdlib.d.ts +254 -0
  165. package/build/src/semantic/stdlib.d.ts.map +1 -0
  166. package/build/src/semantic/stdlib.js +880 -0
  167. package/build/src/semantic/types.d.ts +2952 -202
  168. package/build/src/semantic/types.d.ts.map +1 -1
  169. package/build/src/semantic/types.js +688 -15
  170. package/build/src/semantic/validate.d.ts +85 -5
  171. package/build/src/semantic/validate.d.ts.map +1 -1
  172. package/build/src/semantic/validate.js +2576 -98
  173. package/build/src/stdlib-facades.d.ts +304 -0
  174. package/build/src/stdlib-facades.d.ts.map +1 -0
  175. package/build/src/stdlib-facades.js +1167 -0
  176. package/build/src/stdlib-negotiation.d.ts +69 -0
  177. package/build/src/stdlib-negotiation.d.ts.map +1 -0
  178. package/build/src/stdlib-negotiation.js +403 -0
  179. package/build/src/stdlib-providers.d.ts +72 -0
  180. package/build/src/stdlib-providers.d.ts.map +1 -0
  181. package/build/src/stdlib-providers.js +339 -0
  182. package/build/src/toolchains.d.ts +55 -1
  183. package/build/src/toolchains.d.ts.map +1 -1
  184. package/build/src/toolchains.js +15 -4
  185. package/docs/architecture.md +45 -13
  186. package/docs/dart.md +60 -0
  187. package/docs/goals.md +3 -3
  188. package/docs/ios.md +121 -0
  189. package/docs/kotlin.md +42 -0
  190. package/docs/language-support.md +231 -26
  191. package/docs/multi-file-modules.md +52 -0
  192. package/docs/parser-qualification.md +121 -8
  193. package/docs/plans/2026-09-05-standard-library-portability.md +10 -10
  194. package/docs/rust.md +88 -0
  195. package/docs/source-maps.md +15 -7
  196. package/docs/standard-library-portability.md +39 -8
  197. package/docs/swift.md +44 -0
  198. package/docs/testing.md +366 -4
  199. package/docs/webassembly.md +52 -0
  200. package/index.js +63 -8
  201. package/node_modules/semantifold-tree-sitter-legacy-internal/README.md +2 -2
  202. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/LICENSE +21 -0
  203. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/README.md +45 -0
  204. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/binding.gyp +30 -0
  205. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding.cc +20 -0
  206. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding_test.js +9 -0
  207. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.d.ts +28 -0
  208. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.js +11 -0
  209. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/grammar.js +1630 -0
  210. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/package.json +64 -0
  211. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-arm64/tree-sitter-rust.node +0 -0
  212. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-x64/tree-sitter-rust.node +0 -0
  213. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-arm64/tree-sitter-rust.node +0 -0
  214. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-x64/tree-sitter-rust.node +0 -0
  215. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-arm64/tree-sitter-rust.node +0 -0
  216. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-x64/tree-sitter-rust.node +0 -0
  217. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/highlights.scm +159 -0
  218. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/injections.scm +9 -0
  219. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/tags.scm +60 -0
  220. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/grammar.json +9405 -0
  221. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/node-types.json +5399 -0
  222. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/parser.c +192569 -0
  223. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/scanner.c +393 -0
  224. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/alloc.h +54 -0
  225. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/array.h +290 -0
  226. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/parser.h +266 -0
  227. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter-rust.wasm +0 -0
  228. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter.json +53 -0
  229. package/node_modules/semantifold-tree-sitter-legacy-internal/package.json +3 -2
  230. package/node_modules/semantifold-tree-sitter-legacy-internal/src/c.js +5 -4
  231. package/package.json +5 -2
  232. package/src/artifact-path.js +47 -2
  233. package/src/artifacts.js +67 -0
  234. package/src/backends/c-validation.js +6 -1
  235. package/src/backends/cpp-validation.js +6 -1
  236. package/src/backends/csharp.js +3 -0
  237. package/src/backends/dart-runtime.js +41 -0
  238. package/src/backends/dart.js +326 -0
  239. package/src/backends/effects.js +705 -0
  240. package/src/backends/go.js +14 -2
  241. package/src/backends/identifiers.js +160 -9
  242. package/src/backends/index.js +27 -2
  243. package/src/backends/ios.js +1612 -0
  244. package/src/backends/java.js +454 -36
  245. package/src/backends/javascript.js +389 -23
  246. package/src/backends/kotlin-runtime.js +29 -0
  247. package/src/backends/kotlin.js +141 -0
  248. package/src/backends/native-validation.js +1 -1
  249. package/src/backends/ordered-expressions.js +40 -6
  250. package/src/backends/php-stdlib-support.js +239 -0
  251. package/src/backends/php.js +469 -32
  252. package/src/backends/program.js +1407 -0
  253. package/src/backends/python.js +3 -0
  254. package/src/backends/ruby.js +326 -23
  255. package/src/backends/rust-runtime.js +34 -0
  256. package/src/backends/rust-validation.js +75 -0
  257. package/src/backends/rust.js +335 -0
  258. package/src/backends/scalars.js +141 -16
  259. package/src/backends/shared.js +2304 -124
  260. package/src/backends/stdlib-support.js +234 -0
  261. package/src/backends/swift-runtime.js +14 -0
  262. package/src/backends/swift.js +132 -0
  263. package/src/backends/typescript.js +349 -23
  264. package/src/backends/wasm.js +2208 -0
  265. package/src/backends/writer.js +520 -2
  266. package/src/diagnostic.js +4 -2
  267. package/src/frontends/c.js +4 -2
  268. package/src/frontends/cpp.js +4 -2
  269. package/src/frontends/csharp.js +4 -2
  270. package/src/frontends/dart.js +963 -0
  271. package/src/frontends/index.js +14 -4
  272. package/src/frontends/java.js +1977 -69
  273. package/src/frontends/javascript-typescript.js +2046 -102
  274. package/src/frontends/kotlin.js +713 -0
  275. package/src/frontends/php.js +1725 -79
  276. package/src/frontends/program.js +1062 -0
  277. package/src/frontends/ruby.js +1624 -98
  278. package/src/frontends/rust-parser.js +18 -0
  279. package/src/frontends/rust.js +714 -0
  280. package/src/frontends/scalars.js +31 -1
  281. package/src/frontends/swift.js +893 -0
  282. package/src/frontends/types.js +750 -0
  283. package/src/language-registry.js +172 -12
  284. package/src/mapping.js +33 -9
  285. package/src/semantic/capabilities.js +671 -0
  286. package/src/semantic/effects.js +737 -0
  287. package/src/semantic/generics.js +58 -0
  288. package/src/semantic/lifetime.js +517 -0
  289. package/src/semantic/provenance.js +412 -19
  290. package/src/semantic/scalars.js +17 -0
  291. package/src/semantic/stdlib.js +921 -0
  292. package/src/semantic/types.js +765 -14
  293. package/src/semantic/validate.js +2934 -209
  294. package/src/stdlib-facades.js +1211 -0
  295. package/src/stdlib-negotiation.js +446 -0
  296. package/src/stdlib-providers.js +377 -0
  297. package/src/toolchains.js +16 -3
@@ -0,0 +1,713 @@
1
+ // @ts-check
2
+
3
+ import Parser from "tree-sitter"
4
+ import KotlinLanguage from "tree-sitter-kotlin"
5
+ import {isKotlinIdentifier} from "../backends/identifiers.js"
6
+ import {kotlinRuntime} from "../backends/kotlin-runtime.js"
7
+ import {missingType, SemantifoldDiagnostic, unsupportedSyntax} from "../diagnostic.js"
8
+ import {locationFromOffsets, moduleLocation, utf8ByteOffsetToUtf16Offset} from "../semantic/location.js"
9
+ import {withAdaptedOperation} from "../semantic/operators.js"
10
+ import {withParserRanges} from "../semantic/provenance.js"
11
+ import {hasOnlyUnicodeScalars} from "../semantic/scalars.js"
12
+ import {validateParsedModule} from "../semantic/validate.js"
13
+ import {sourceScalarType} from "./scalars.js"
14
+
15
+ const parser = new Parser()
16
+
17
+ parser.setLanguage(/** @type {import("tree-sitter").Language} */ (/** @type {unknown} */ (KotlinLanguage)))
18
+
19
+ const binaryOperations = new Map([
20
+ ["+", "Add"], ["-", "Subtract"], ["*", "Multiply"], ["==", "Equal"], ["!=", "NotEqual"],
21
+ ["<", "LessThan"], ["<=", "LessThanOrEqual"], [">", "GreaterThan"], [">=", "GreaterThanOrEqual"],
22
+ ["&&", "And"], ["||", "Or"]
23
+ ])
24
+ const binaryNodeOperators = new Map([
25
+ ["additive_expression", new Set(["+", "-"])],
26
+ ["multiplicative_expression", new Set(["*"])],
27
+ ["equality_expression", new Set(["==", "!="])],
28
+ ["comparison_expression", new Set(["<", "<=", ">", ">="])],
29
+ ["conjunction_expression", new Set(["&&"])],
30
+ ["disjunction_expression", new Set(["||"])]
31
+ ])
32
+ /** @type {Map<string, import("../semantic/operators.js").AdaptedOperation>} */
33
+ const helperOperations = new Map([
34
+ ["semantifold_integer_add", "Add"], ["semantifold_integer_subtract", "Subtract"],
35
+ ["semantifold_integer_multiply", "Multiply"], ["semantifold_integer_negate", "Negate"]
36
+ ])
37
+ const commentTypes = new Set(["line_comment", "multiline_comment"])
38
+
39
+ /**
40
+ * Verifies a Tree-sitter binding index through the shared byte converter.
41
+ * @param {string} source - Complete source.
42
+ * @param {number} index - Binding-reported UTF-16 index.
43
+ * @returns {number} Verified UTF-16 offset.
44
+ */
45
+ function bindingIndexToUtf16Offset(source, index) {
46
+ if (!Number.isInteger(index) || index < 0 || index > source.length ||
47
+ index > 0 && index < source.length && /[\uD800-\uDBFF]/u.test(source[index - 1]) && /[\uDC00-\uDFFF]/u.test(source[index])) {
48
+ throw new RangeError("Invalid Tree-sitter source index: " + index)
49
+ }
50
+ return utf8ByteOffsetToUtf16Offset(source, new TextEncoder().encode(source.slice(0, index)).length)
51
+ }
52
+
53
+ /**
54
+ * Finds an unpaired UTF-16 surrogate.
55
+ * @param {string} source - Complete source.
56
+ * @returns {number} Invalid offset or -1.
57
+ */
58
+ function firstLoneSurrogateOffset(source) {
59
+ for (let index = 0; index < source.length; index += 1) {
60
+ const unit = source.charCodeAt(index)
61
+
62
+ if (unit >= 0xD800 && unit <= 0xDBFF) {
63
+ const next = source.charCodeAt(index + 1)
64
+
65
+ if (next >= 0xDC00 && next <= 0xDFFF) index += 1
66
+ else return index
67
+ } else if (unit >= 0xDC00 && unit <= 0xDFFF) return index
68
+ }
69
+ return -1
70
+ }
71
+
72
+ /** Consumes exact qualified Kotlin CST shapes without retaining parser handles. */
73
+ class KotlinReader {
74
+ /**
75
+ * Creates a reader over one parser-owned Kotlin source.
76
+ * @param {string} filename - Original filename.
77
+ * @param {string} source - Complete source.
78
+ */
79
+ constructor(filename, source) {
80
+ this.filename = filename
81
+ this.source = source
82
+ this.runtime = false
83
+ }
84
+
85
+ /**
86
+ * Converts one parser range to Semantifold UTF-16 coordinates.
87
+ * @param {import("tree-sitter").SyntaxNode} node - Parser node.
88
+ * @returns {import("../semantic/types.js").SourceLocation} Exact location.
89
+ */
90
+ location(node) {
91
+ return locationFromOffsets(this.filename, this.source, bindingIndexToUtf16Offset(this.source, node.startIndex),
92
+ bindingIndexToUtf16Offset(this.source, node.endIndex))
93
+ }
94
+
95
+ /**
96
+ * Rejects one located source-profile violation.
97
+ * @param {import("tree-sitter").SyntaxNode} node - Violating node.
98
+ * @param {string} [detail] - Profile detail.
99
+ * @returns {never} Always throws.
100
+ */
101
+ fail(node, detail = node.type) {
102
+ unsupportedSyntax("kotlin", detail, this.location(node))
103
+ }
104
+
105
+ /**
106
+ * Traverses every named, anonymous, extra, directive, and recovery node.
107
+ * @param {import("tree-sitter").SyntaxNode} root - Complete parser root.
108
+ * @returns {void}
109
+ */
110
+ validateTree(root) {
111
+ const pending = [{depth: 0, node: root, visited: false}]
112
+
113
+ while (pending.length) {
114
+ const current = pending.pop()
115
+
116
+ if (!current) throw new Error("Kotlin traversal lost a pending parser node.")
117
+ const {depth, node, visited} = current
118
+
119
+ if (depth > 512) this.fail(node, "CST exceeds the 512-level traversal limit")
120
+ if (!visited) {
121
+ pending.push({depth, node, visited: true})
122
+ for (let index = node.childCount - 1; index >= 0; index -= 1) {
123
+ const child = node.child(index)
124
+
125
+ if (!child) throw new Error(`Tree-sitter omitted child ${index} of ${node.type}.`)
126
+ pending.push({depth: depth + 1, node: child, visited: false})
127
+ }
128
+ continue
129
+ }
130
+ if (node.hasError || node.isError || node.isMissing) {
131
+ throw new SemantifoldDiagnostic({
132
+ code: "PARSE_ERROR",
133
+ language: "kotlin",
134
+ location: this.location(node),
135
+ message: `Tree-sitter exposed recovery at '${node.type}'.`
136
+ })
137
+ }
138
+ if (["annotation", "file_annotation", "shebang_line"].includes(node.type)) this.fail(node, node.type)
139
+ if (commentTypes.has(node.type) && /(?:language|api|jvm)[-_ ]version/iu.test(node.text)) {
140
+ this.fail(node, "directive-bearing comment")
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Omits only inert comments already accounted for by exhaustive traversal.
147
+ * @param {import("tree-sitter").SyntaxNode} node - Parent node.
148
+ * @returns {import("tree-sitter").SyntaxNode[]} Structural children.
149
+ */
150
+ parts(node) {
151
+ return node.children.filter((child) => !commentTypes.has(child.type))
152
+ }
153
+
154
+ /**
155
+ * Requires all ordered children, including anonymous punctuation.
156
+ * @param {import("tree-sitter").SyntaxNode} node - Shape owner.
157
+ * @param {(import("tree-sitter").SyntaxNode | string)[]} expected - Exact child sequence.
158
+ * @returns {void}
159
+ */
160
+ shape(node, expected) {
161
+ const actual = this.parts(node)
162
+
163
+ if (actual.length != expected.length) this.fail(actual[Math.min(actual.length, expected.length)] ?? node, `${node.type} child shape`)
164
+ for (let index = 0; index < expected.length; index += 1) {
165
+ const wanted = expected[index]
166
+ const child = actual[index]
167
+ const matches = typeof wanted == "string" ? child.text == wanted : child.id == wanted.id
168
+
169
+ if (!matches) this.fail(child, `${node.type} child shape`)
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Requires one exact parser field edge.
175
+ * @param {import("tree-sitter").SyntaxNode} node - Field owner.
176
+ * @param {string} name - Field name.
177
+ * @returns {import("tree-sitter").SyntaxNode} Sole field node.
178
+ */
179
+ field(node, name) {
180
+ const matches = []
181
+
182
+ for (let index = 0; index < node.childCount; index += 1) {
183
+ const child = node.child(index)
184
+
185
+ if (!child) throw new Error(`Tree-sitter omitted child ${index} of ${node.type}.`)
186
+ if (node.fieldNameForChild(index) == name) matches.push(child)
187
+ }
188
+ if (matches.length != 1) this.fail(node, `expected one '${name}' field`)
189
+ return matches[0]
190
+ }
191
+
192
+ /**
193
+ * Validates one Kotlin identifier in the portable source profile.
194
+ * @param {import("tree-sitter").SyntaxNode} node - Identifier token.
195
+ * @param {boolean} [allowMain] - Whether the fixed main scaffold is expected.
196
+ * @param {boolean} [allowPrint] - Whether the fixed print scaffold is expected.
197
+ * @returns {string} Accepted spelling.
198
+ */
199
+ identifier(node, allowMain = false, allowPrint = false) {
200
+ const name = node.text
201
+
202
+ if (node.type != "simple_identifier" || !(allowMain && name == "main") && !(allowPrint && name == "println") &&
203
+ (!isKotlinIdentifier(name) || name.normalize("NFC") != name)) this.fail(node, "reserved or unsupported identifier")
204
+ return name
205
+ }
206
+
207
+ /**
208
+ * Converts exactly Long, Boolean, or String.
209
+ * @param {import("tree-sitter").SyntaxNode} node - Type node.
210
+ * @returns {import("../semantic/types.js").TypeReference} Semantic scalar.
211
+ */
212
+ type(node) {
213
+ const parts = this.parts(node)
214
+
215
+ if (node.type != "user_type" || parts.length != 1 || parts[0].type != "type_identifier") this.fail(node, "scalar type shape")
216
+ this.shape(node, [parts[0]])
217
+ const type = sourceScalarType("kotlin", parts[0].text, this.location(parts[0]))
218
+
219
+ if (!type) this.fail(parts[0], `unsupported scalar type '${parts[0].text}'`)
220
+ return type
221
+ }
222
+
223
+ /**
224
+ * Decodes an ordinary noninterpolated Kotlin string.
225
+ * @param {import("tree-sitter").SyntaxNode} node - String literal node.
226
+ * @returns {string} Decoded Unicode scalar string.
227
+ */
228
+ string(node) {
229
+ const parts = this.parts(node)
230
+
231
+ if (node.type != "string_literal" || parts.some((part) => part.type != "string_content") ||
232
+ !node.text.startsWith('"') || !node.text.endsWith('"')) this.fail(node, "ordinary noninterpolated string literal required")
233
+ this.shape(node, parts)
234
+ let value = ""
235
+ const simpleEscapes = new Map([
236
+ ["t", "\t"], ["b", "\b"], ["n", "\n"], ["r", "\r"], ["'", "'"], ['"', '"'], ["\\", "\\"], ["$", "$"]
237
+ ])
238
+
239
+ for (let index = 1; index < node.text.length - 1; index += 1) {
240
+ const character = node.text[index]
241
+
242
+ if (character != "\\") {
243
+ if (character == "\n" || character == "\r" || character == '"') this.fail(node, "invalid string content")
244
+ value += character
245
+ continue
246
+ }
247
+ const escaped = node.text[++index]
248
+
249
+ if (simpleEscapes.has(escaped)) value += simpleEscapes.get(escaped)
250
+ else if (escaped == "u") {
251
+ const hexadecimal = node.text.slice(index + 1, index + 5)
252
+
253
+ if (!/^[0-9A-Fa-f]{4}$/u.test(hexadecimal)) this.fail(node, "unsupported string escape")
254
+ value += String.fromCharCode(Number.parseInt(hexadecimal, 16))
255
+ index += 4
256
+ } else this.fail(node, "unsupported string escape")
257
+ }
258
+ if (!hasOnlyUnicodeScalars(value)) this.fail(node, "invalid Unicode string literal")
259
+ return value
260
+ }
261
+
262
+ /**
263
+ * Extracts exact unnamed call arguments.
264
+ * @param {import("tree-sitter").SyntaxNode} suffix - Call suffix node.
265
+ * @returns {import("tree-sitter").SyntaxNode[]} Argument expression nodes.
266
+ */
267
+ arguments(suffix) {
268
+ const suffixParts = this.parts(suffix)
269
+
270
+ if (suffix.type != "call_suffix" || suffixParts.length != 1 || suffixParts[0].type != "value_arguments") {
271
+ return this.fail(suffix, "call suffix shape")
272
+ }
273
+ this.shape(suffix, [suffixParts[0]])
274
+ const list = suffixParts[0]
275
+ const parts = this.parts(list)
276
+
277
+ if (parts.length < 2 || parts[0].text != "(" || parts.at(-1)?.text != ")") this.fail(list, "call argument list shape")
278
+ const arguments_ = parts.slice(1, -1).filter((_part, index) => index % 2 == 0)
279
+
280
+ this.shape(list, ["(", ...arguments_.flatMap((argument, index) => index ? [",", argument] : [argument]), ")"])
281
+ return arguments_.map((argument) => {
282
+ const argumentParts = this.parts(argument)
283
+
284
+ if (argument.type != "value_argument" || argumentParts.length != 1) this.fail(argument, "unnamed argument required")
285
+ this.shape(argument, [argumentParts[0]])
286
+ return argumentParts[0]
287
+ })
288
+ }
289
+
290
+ /**
291
+ * Converts a direct semantic or generated-helper call.
292
+ * @param {import("tree-sitter").SyntaxNode} node - Call expression node.
293
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
294
+ */
295
+ call(node) {
296
+ const parts = this.parts(node)
297
+
298
+ if (node.type != "call_expression" || parts.length != 2 || parts[0].type != "simple_identifier") this.fail(node, "direct call shape")
299
+ this.shape(node, [parts[0], parts[1]])
300
+ const argumentNodes = this.arguments(parts[1])
301
+ const name = parts[0].text
302
+ const helper = this.runtime ? helperOperations.get(name) : undefined
303
+ const location = this.location(node)
304
+
305
+ if (helper) {
306
+ const count = helper == "Negate" ? 1 : 2
307
+
308
+ if (argumentNodes.length != count) this.fail(node, "Kotlin checked-integer helper shape")
309
+ if (helper == "Negate") {
310
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
311
+ kind: /** @type {const} */ ("UnaryExpression"), location, operand: this.expression(argumentNodes[0])
312
+ }, {operator: this.location(parts[0])}), helper)))
313
+ }
314
+ return /** @type {import("../semantic/types.js").Expression} */ (withAdaptedOperation(withParserRanges({
315
+ kind: /** @type {const} */ ("BinaryExpression"), left: this.expression(argumentNodes[0]), location, right: this.expression(argumentNodes[1])
316
+ }, {operator: this.location(parts[0])}), helper))
317
+ }
318
+ const semanticName = this.identifier(parts[0])
319
+
320
+ if (argumentNodes.length != 2) this.fail(parts[1], "semantic call argument count")
321
+ return withParserRanges({
322
+ arguments: argumentNodes.map((argument) => this.expression(argument)), callee: semanticName,
323
+ kind: /** @type {const} */ ("CallExpression"), location
324
+ }, {callee: this.location(parts[0])})
325
+ }
326
+
327
+ /**
328
+ * Converts one supported scalar expression.
329
+ * @param {import("tree-sitter").SyntaxNode} node - Expression node.
330
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
331
+ */
332
+ expression(node) {
333
+ const location = this.location(node)
334
+
335
+ if (node.type == "simple_identifier") {
336
+ return withParserRanges({kind: /** @type {const} */ ("IdentifierExpression"), location, name: this.identifier(node)}, {name: location})
337
+ }
338
+ if (node.type == "integer_literal" || node.type == "long_literal") {
339
+ const literal = node.type == "long_literal" ? this.parts(node)[0] : node
340
+
341
+ if (node.type == "long_literal") this.shape(node, [literal, "L"])
342
+ if (!literal || literal.type != "integer_literal" || !/^(?:0|[1-9][0-9]*)$/u.test(literal.text) ||
343
+ node.type == "long_literal" && !/L$/u.test(node.text)) this.fail(node, "noncanonical integer literal")
344
+ const value = Number(BigInt(literal.text))
345
+
346
+ if (!Number.isSafeInteger(value)) this.fail(node, "non-safe integer literal")
347
+ return withParserRanges({kind: /** @type {const} */ ("IntegerLiteral"), location, value}, {literal: location})
348
+ }
349
+ if (node.type == "boolean_literal") {
350
+ const parts = this.parts(node)
351
+
352
+ if (parts.length != 1 || !["true", "false"].includes(parts[0].text)) this.fail(node, "Boolean literal shape")
353
+ this.shape(node, [parts[0].text])
354
+ return withParserRanges({kind: /** @type {const} */ ("BooleanLiteral"), location, value: parts[0].text == "true"}, {literal: location})
355
+ }
356
+ if (node.type == "string_literal") {
357
+ return withParserRanges({kind: /** @type {const} */ ("StringLiteral"), location, value: this.string(node)}, {literal: location})
358
+ }
359
+ if (node.type == "parenthesized_expression") {
360
+ const parts = this.parts(node)
361
+
362
+ if (parts.length != 3) this.fail(node, "parenthesized expression shape")
363
+ this.shape(node, ["(", parts[1], ")"])
364
+ return this.expression(parts[1])
365
+ }
366
+ if (node.type == "prefix_expression") {
367
+ const parts = this.parts(node)
368
+
369
+ if (parts.length != 2 || !["-", "!"].includes(parts[0].text)) this.fail(node, "unary operator")
370
+ this.shape(node, [parts[0].text, parts[1]])
371
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
372
+ kind: /** @type {const} */ ("UnaryExpression"), location, operand: this.expression(parts[1])
373
+ }, {operator: this.location(parts[0])}), parts[0].text == "-" ? "Negate" : "Not")))
374
+ }
375
+ if (binaryNodeOperators.has(node.type)) return this.binary(node)
376
+ if (node.type == "call_expression") return this.call(node)
377
+ return this.fail(node)
378
+ }
379
+
380
+ /**
381
+ * Converts one binary expression.
382
+ * @param {import("tree-sitter").SyntaxNode} node - Binary expression node.
383
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
384
+ */
385
+ binary(node) {
386
+ const parts = this.parts(node)
387
+ const accepted = binaryNodeOperators.get(node.type)
388
+
389
+ if (parts.length != 3) this.fail(node, `${node.type} child shape`)
390
+ this.shape(node, [parts[0], parts[1], parts[2]])
391
+ const operation = binaryOperations.get(parts[1].text)
392
+
393
+ if (!accepted?.has(parts[1].text) || !operation) this.fail(parts[1], "unsupported binary operator")
394
+ return /** @type {import("../semantic/types.js").Expression} */ (withAdaptedOperation(withParserRanges({
395
+ kind: /** @type {const} */ ("BinaryExpression"), left: this.expression(parts[0]), location: this.location(node), right: this.expression(parts[2])
396
+ }, {operator: this.location(parts[1])}), /** @type {import("../semantic/operators.js").AdaptedOperation} */ (operation)))
397
+ }
398
+
399
+ /**
400
+ * Converts one explicitly typed local declaration.
401
+ * @param {import("tree-sitter").SyntaxNode} node - Property declaration node.
402
+ * @returns {import("../semantic/types.js").LocalDeclaration} Semantic declaration.
403
+ */
404
+ local(node) {
405
+ const parts = this.parts(node)
406
+ const location = this.location(node)
407
+
408
+ if (node.type != "property_declaration" || parts.length != 4 || parts[0].type != "binding_pattern_kind" ||
409
+ parts[1].type != "variable_declaration" || parts[2].text != "=") this.fail(node, "local declaration shape")
410
+ const bindingParts = this.parts(parts[0])
411
+ const variableParts = this.parts(parts[1])
412
+
413
+ if (bindingParts.length != 1 || !["val", "var"].includes(bindingParts[0].text)) this.fail(parts[0], "local binding kind")
414
+ if (variableParts.length == 1) return missingType("kotlin", "Local", location)
415
+ if (variableParts.length != 3 || variableParts[0].type != "simple_identifier" || variableParts[1].text != ":") {
416
+ this.fail(parts[1], "local declaration shape")
417
+ }
418
+ this.shape(parts[0], [bindingParts[0].text])
419
+ this.shape(parts[1], [variableParts[0], ":", variableParts[2]])
420
+ this.shape(node, [parts[0], parts[1], "=", parts[3]])
421
+ const name = this.identifier(variableParts[0])
422
+
423
+ return withParserRanges({
424
+ initializer: this.expression(parts[3]), kind: /** @type {const} */ ("LocalDeclaration"), location,
425
+ mutable: bindingParts[0].text == "var", name, type: this.type(variableParts[2])
426
+ }, {name: this.location(variableParts[0]), operator: this.location(parts[2])})
427
+ }
428
+
429
+ /**
430
+ * Converts one plain local assignment.
431
+ * @param {import("tree-sitter").SyntaxNode} node - Assignment node.
432
+ * @returns {import("../semantic/types.js").AssignmentStatement} Semantic assignment.
433
+ */
434
+ assignment(node) {
435
+ const parts = this.parts(node)
436
+
437
+ if (node.type != "assignment" || parts.length != 3 || parts[0].type != "directly_assignable_expression" || parts[1].text != "=") {
438
+ this.fail(node, "assignment shape")
439
+ }
440
+ const targetParts = this.parts(parts[0])
441
+
442
+ if (targetParts.length != 1 || targetParts[0].type != "simple_identifier") this.fail(parts[0], "assignment target shape")
443
+ this.shape(parts[0], [targetParts[0]])
444
+ this.shape(node, [parts[0], "=", parts[2]])
445
+ const name = this.identifier(targetParts[0])
446
+ const targetLocation = this.location(targetParts[0])
447
+
448
+ return withParserRanges({
449
+ expression: this.expression(parts[2]), kind: /** @type {const} */ ("AssignmentStatement"), location: this.location(node),
450
+ target: withParserRanges({kind: /** @type {const} */ ("IdentifierExpression"), location: targetLocation, name}, {name: targetLocation})
451
+ }, {operator: this.location(parts[1])})
452
+ }
453
+
454
+ /**
455
+ * Converts the exact println entry scaffold.
456
+ * @param {import("tree-sitter").SyntaxNode} node - Call node.
457
+ * @returns {import("../semantic/types.js").PrintStatement} Semantic print.
458
+ */
459
+ print(node) {
460
+ const parts = this.parts(node)
461
+
462
+ if (node.type != "call_expression" || parts.length != 2 || parts[0].type != "simple_identifier" ||
463
+ this.identifier(parts[0], false, true) != "println") this.fail(node, "exact println call required")
464
+ const arguments_ = this.arguments(parts[1])
465
+
466
+ if (arguments_.length != 1) this.fail(parts[1], "println argument count")
467
+ return {expression: this.expression(arguments_[0]), kind: /** @type {const} */ ("PrintStatement"), location: this.location(node)}
468
+ }
469
+
470
+ /**
471
+ * Converts one supported statement.
472
+ * @param {import("tree-sitter").SyntaxNode} node - Statement node.
473
+ * @returns {import("../semantic/types.js").Statement} Semantic statement.
474
+ */
475
+ statement(node) {
476
+ if (node.type == "property_declaration") return this.local(node)
477
+ if (node.type == "assignment") return this.assignment(node)
478
+ if (node.type == "if_expression") return this.conditional(node)
479
+ if (node.type == "call_expression") return this.print(node)
480
+ if (node.type == "jump_expression") {
481
+ const parts = this.parts(node)
482
+
483
+ if (parts.length != 2 || parts[0].text != "return") this.fail(node, "return expression shape")
484
+ this.shape(node, ["return", parts[1]])
485
+ return {expression: this.expression(parts[1]), kind: /** @type {const} */ ("ReturnStatement"), location: this.location(node)}
486
+ }
487
+ return this.fail(node)
488
+ }
489
+
490
+ /**
491
+ * Converts an optional parser statement list.
492
+ * @param {import("tree-sitter").SyntaxNode | undefined} node - Statement-list node.
493
+ * @returns {import("../semantic/types.js").Statement[]} Semantic statements.
494
+ */
495
+ statements(node) {
496
+ if (!node) return []
497
+ if (node.type != "statements") this.fail(node, "statement list shape")
498
+ return this.parts(node).map((statement) => this.statement(statement))
499
+ }
500
+
501
+ /**
502
+ * Converts one braced conditional body.
503
+ * @param {import("tree-sitter").SyntaxNode} node - Control body node.
504
+ * @returns {import("../semantic/types.js").Block} Semantic block.
505
+ */
506
+ controlBody(node) {
507
+ const parts = this.parts(node)
508
+ const statements = parts[1]?.type == "statements" ? parts[1] : undefined
509
+
510
+ if (node.type != "control_structure_body") this.fail(node, "conditional block shape")
511
+ this.shape(node, ["{", ...(statements ? [statements] : []), "}"])
512
+ return {kind: /** @type {const} */ ("Block"), location: this.location(node), statements: this.statements(statements)}
513
+ }
514
+
515
+ /**
516
+ * Converts one strict Boolean conditional.
517
+ * @param {import("tree-sitter").SyntaxNode} node - If expression node.
518
+ * @returns {import("../semantic/types.js").IfStatement} Semantic conditional.
519
+ */
520
+ conditional(node) {
521
+ const parts = this.parts(node)
522
+ const condition = this.field(node, "condition")
523
+ const consequence = this.field(node, "consequence")
524
+ const base = ["if", "(", condition, ")", consequence]
525
+
526
+ if (node.type != "if_expression" || consequence.type != "control_structure_body") this.fail(node, "if expression shape")
527
+ const statement = /** @type {import("../semantic/types.js").IfStatement} */ ({
528
+ condition: this.expression(condition), consequent: this.controlBody(consequence), kind: /** @type {const} */ ("IfStatement"),
529
+ location: this.location(node)
530
+ })
531
+
532
+ if (parts.length == base.length) {
533
+ this.shape(node, base)
534
+ return statement
535
+ }
536
+ const alternative = this.field(node, "alternative")
537
+
538
+ this.shape(node, [...base, "else", alternative])
539
+ if (alternative.type != "control_structure_body") this.fail(alternative, "if alternate shape")
540
+ const alternativeParts = this.parts(alternative)
541
+
542
+ if (alternativeParts.length == 1 && alternativeParts[0].type == "if_expression") {
543
+ this.shape(alternative, [alternativeParts[0]])
544
+ return {...statement, alternate: {kind: /** @type {const} */ ("Block"), location: this.location(alternative),
545
+ statements: [this.conditional(alternativeParts[0])]}}
546
+ }
547
+ return {...statement, alternate: this.controlBody(alternative)}
548
+ }
549
+
550
+ /**
551
+ * Converts one exact braced block.
552
+ * @param {import("tree-sitter").SyntaxNode} node - Block node.
553
+ * @param {"function_body" | "control_structure_body"} type - Required parser node type.
554
+ * @returns {import("../semantic/types.js").Block} Semantic block.
555
+ */
556
+ block(node, type = "function_body") {
557
+ const parts = this.parts(node)
558
+ const statements = parts[1]?.type == "statements" ? parts[1] : undefined
559
+
560
+ if (node.type != type) this.fail(node, `${type} shape`)
561
+ this.shape(node, ["{", ...(statements ? [statements] : []), "}"])
562
+ return {kind: /** @type {const} */ ("Block"), location: this.location(node), statements: this.statements(statements)}
563
+ }
564
+
565
+ /**
566
+ * Converts one explicitly typed parameter.
567
+ * @param {import("tree-sitter").SyntaxNode} node - Parameter node.
568
+ * @returns {import("../semantic/types.js").Parameter} Semantic parameter.
569
+ */
570
+ parameter(node) {
571
+ const parts = this.parts(node)
572
+
573
+ if (node.type != "parameter" || parts.length != 3 || parts[0].type != "simple_identifier" || parts[1].text != ":") {
574
+ this.fail(node, "parameter shape")
575
+ }
576
+ this.shape(node, [parts[0], ":", parts[2]])
577
+ const name = this.identifier(parts[0])
578
+
579
+ return withParserRanges({kind: /** @type {const} */ ("Parameter"), location: this.location(node), name, type: this.type(parts[2])}, {
580
+ name: this.location(parts[0])
581
+ })
582
+ }
583
+
584
+ /**
585
+ * Converts one supported top-level function.
586
+ * @param {import("tree-sitter").SyntaxNode} node - Function declaration node.
587
+ * @returns {import("../semantic/types.js").FunctionDeclaration} Semantic function.
588
+ */
589
+ function(node) {
590
+ const parts = this.parts(node)
591
+
592
+ if (node.type != "function_declaration" || parts.length < 4 || parts[0].text != "fun" || parts[1].type != "simple_identifier" ||
593
+ parts[2].type != "function_value_parameters" || parts.at(-1)?.type != "function_body") this.fail(node, "function declaration shape")
594
+ if (!parts.some((part) => part.text == ":")) return missingType("kotlin", "Function return", this.location(node))
595
+ if (parts.length != 6 || parts[3].text != ":") this.fail(node, "function declaration shape")
596
+ this.shape(node, ["fun", parts[1], parts[2], ":", parts[4], parts[5]])
597
+ const parameterParts = this.parts(parts[2])
598
+ const parameters = parameterParts.filter((part) => part.type == "parameter")
599
+
600
+ if (parameters.length != 2) this.fail(parts[2], "function parameter count other than two")
601
+ this.shape(parts[2], ["(", parameters[0], ",", parameters[1], ")"])
602
+ const name = this.identifier(parts[1])
603
+
604
+ return withParserRanges({
605
+ body: this.block(parts[5]), kind: /** @type {const} */ ("FunctionDeclaration"), location: this.location(node), name,
606
+ parameters: parameters.map((parameter) => this.parameter(parameter)), returnType: this.type(parts[4])
607
+ }, {name: this.location(parts[1])})
608
+ }
609
+
610
+ /**
611
+ * Converts the exact final main function.
612
+ * @param {import("tree-sitter").SyntaxNode} node - Main declaration node.
613
+ * @returns {import("../semantic/types.js").EntryPoint} Semantic entry point.
614
+ */
615
+ main(node) {
616
+ const parts = this.parts(node)
617
+
618
+ if (node.type != "function_declaration" || parts.length != 4 || parts[0].text != "fun" ||
619
+ this.identifier(parts[1], true) != "main" || parts[2].type != "function_value_parameters" || parts[3].type != "function_body") {
620
+ this.fail(node, "exact main declaration required")
621
+ }
622
+ this.shape(parts[2], ["(", ")"])
623
+ this.shape(node, ["fun", parts[1], parts[2], parts[3]])
624
+ return {body: this.block(parts[3]), kind: /** @type {const} */ ("EntryPoint"), location: this.location(node)}
625
+ }
626
+
627
+ /**
628
+ * Compares source support with the canonical generated helper CST.
629
+ * @param {import("tree-sitter").SyntaxNode} actual - Source node.
630
+ * @param {import("tree-sitter").SyntaxNode} expected - Canonical support node.
631
+ * @returns {void}
632
+ */
633
+ compareTree(actual, expected) {
634
+ if (actual.type != expected.type || actual.isNamed != expected.isNamed || actual.isExtra != expected.isExtra ||
635
+ actual.childCount != expected.childCount) this.fail(actual, "modified Kotlin support node")
636
+ if (!actual.childCount && actual.text != expected.text) this.fail(actual, "modified Kotlin support token")
637
+ for (let index = 0; index < actual.childCount; index += 1) {
638
+ const left = actual.child(index)
639
+ const right = expected.child(index)
640
+
641
+ if (!left || !right || actual.fieldNameForChild(index) != expected.fieldNameForChild(index)) {
642
+ this.fail(left ?? actual, "modified Kotlin support field")
643
+ }
644
+ this.compareTree(left, right)
645
+ }
646
+ }
647
+
648
+ /**
649
+ * Converts and validates one complete Kotlin source file.
650
+ * @param {import("tree-sitter").SyntaxNode} root - Source file root.
651
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
652
+ */
653
+ module(root) {
654
+ this.validateTree(root)
655
+ if (root.type != "source_file") this.fail(root, "source file root")
656
+ const parts = this.parts(root)
657
+ const supportTree = parser.parse(kotlinRuntime)
658
+ const support = this.parts(supportTree.rootNode)
659
+ let supportIndex = 0
660
+
661
+ while (supportIndex < parts.length && supportIndex < support.length && parts[supportIndex].type == support[supportIndex].type) {
662
+ this.compareTree(parts[supportIndex], support[supportIndex])
663
+ supportIndex += 1
664
+ }
665
+ if (supportIndex > 0 && supportIndex != support.length) this.fail(parts[supportIndex - 1], "complete Kotlin support required")
666
+ this.runtime = supportIndex == support.length
667
+ const semanticParts = parts.slice(supportIndex)
668
+ const mainIndex = semanticParts.findIndex((node) => node.type == "function_declaration" && this.parts(node)[1]?.text == "main")
669
+
670
+ if (mainIndex < 0) this.fail(root, "source file without main")
671
+ if (mainIndex == 0) this.fail(semanticParts[0], "top-level semantic function required")
672
+ if (mainIndex != semanticParts.length - 1) this.fail(semanticParts[mainIndex + 1], "declaration after main")
673
+ const declarations = semanticParts.slice(0, mainIndex)
674
+
675
+ for (const declaration of declarations) {
676
+ if (declaration.type != "function_declaration") this.fail(declaration)
677
+ }
678
+ const module = {
679
+ entryPoint: this.main(semanticParts[mainIndex]), functions: declarations.map((declaration) => this.function(declaration)),
680
+ kind: /** @type {const} */ ("Module"), location: this.location(root)
681
+ }
682
+
683
+ validateParsedModule(module, "kotlin")
684
+ return module
685
+ }
686
+ }
687
+
688
+ /**
689
+ * Parses the strict Task 023 Kotlin/JVM profile through the qualified grammar.
690
+ * @param {{filename: string, source: string}} input - Exact source request.
691
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
692
+ */
693
+ export function parseKotlin({filename, source}) {
694
+ if (!hasOnlyUnicodeScalars(source)) {
695
+ const offset = firstLoneSurrogateOffset(source)
696
+
697
+ throw new SemantifoldDiagnostic({
698
+ code: "PARSE_ERROR", language: "kotlin", location: locationFromOffsets(filename, source, offset, offset + 1),
699
+ message: "Kotlin source contains an invalid lone UTF-16 surrogate."
700
+ })
701
+ }
702
+ let tree
703
+
704
+ try {
705
+ tree = parser.parse(source)
706
+ } catch (error) {
707
+ throw new SemantifoldDiagnostic({
708
+ cause: error instanceof Error ? error : undefined, code: "PARSE_ERROR", language: "kotlin",
709
+ location: moduleLocation(filename, source), message: "The qualified Kotlin parser could not produce a complete CST."
710
+ })
711
+ }
712
+ return new KotlinReader(filename, source).module(tree.rootNode)
713
+ }