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,893 @@
1
+ // @ts-check
2
+
3
+ import Parser from "tree-sitter"
4
+ import SwiftLanguage from "tree-sitter-swift/bindings/node/index.js"
5
+ import {isSwiftIdentifier} from "../backends/identifiers.js"
6
+ import {swiftRuntime} from "../backends/swift-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} */ (SwiftLanguage)))
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
+ ["infix_expression", new Set(["!=", "<=", ">="])]
32
+ ])
33
+ /** @type {Map<string, import("../semantic/operators.js").AdaptedOperation>} */
34
+ const helperOperations = new Map([
35
+ ["semantifold_string_equal", "StringEqual"], ["semantifold_string_not_equal", "StringNotEqual"]
36
+ ])
37
+ /**
38
+ * Verifies a Tree-sitter binding index through the shared byte converter.
39
+ * @param {string} source - Complete source.
40
+ * @param {number} index - Binding-reported UTF-16 index.
41
+ * @returns {number} Verified UTF-16 offset.
42
+ */
43
+ function bindingIndexToUtf16Offset(source, index) {
44
+ if (!Number.isInteger(index) || index < 0 || index > source.length ||
45
+ index > 0 && index < source.length && /[\uD800-\uDBFF]/u.test(source[index - 1]) && /[\uDC00-\uDFFF]/u.test(source[index])) {
46
+ throw new RangeError("Invalid Tree-sitter source index: " + index)
47
+ }
48
+ return utf8ByteOffsetToUtf16Offset(source, new TextEncoder().encode(source.slice(0, index)).length)
49
+ }
50
+
51
+ /**
52
+ * Finds an unpaired UTF-16 surrogate.
53
+ * @param {string} source - Complete source.
54
+ * @returns {number} Invalid offset or -1.
55
+ */
56
+ function firstLoneSurrogateOffset(source) {
57
+ for (let index = 0; index < source.length; index += 1) {
58
+ const unit = source.charCodeAt(index)
59
+
60
+ if (unit >= 0xD800 && unit <= 0xDBFF) {
61
+ const next = source.charCodeAt(index + 1)
62
+
63
+ if (next >= 0xDC00 && next <= 0xDFFF) index += 1
64
+ else return index
65
+ } else if (unit >= 0xDC00 && unit <= 0xDFFF) return index
66
+ }
67
+ return -1
68
+ }
69
+
70
+ /** Consumes exact qualified Swift CST shapes without retaining parser handles. */
71
+ class SwiftReader {
72
+ /**
73
+ * Creates a reader over one parser-owned Swift source.
74
+ * @param {string} filename - Original filename.
75
+ * @param {string} source - Complete source.
76
+ */
77
+ constructor(filename, source) {
78
+ this.filename = filename
79
+ this.source = source
80
+ /** @type {Set<string>} */
81
+ this.helpers = new Set()
82
+ this.mutableMarker = false
83
+ /** @type {WeakMap<object, import("tree-sitter").SyntaxNode>} */
84
+ this.nativeEqualityOperators = new WeakMap()
85
+ }
86
+
87
+ /**
88
+ * Converts one parser range to Semantifold UTF-16 coordinates.
89
+ * @param {import("tree-sitter").SyntaxNode} node - Parser node.
90
+ * @returns {import("../semantic/types.js").SourceLocation} Exact location.
91
+ */
92
+ location(node) {
93
+ return locationFromOffsets(this.filename, this.source, bindingIndexToUtf16Offset(this.source, node.startIndex),
94
+ bindingIndexToUtf16Offset(this.source, node.endIndex))
95
+ }
96
+
97
+ /**
98
+ * Rejects one located source-profile violation.
99
+ * @param {import("tree-sitter").SyntaxNode} node - Violating node.
100
+ * @param {string} [detail] - Profile detail.
101
+ * @returns {never} Always throws.
102
+ */
103
+ fail(node, detail = node.type) {
104
+ unsupportedSyntax("swift", detail, this.location(node))
105
+ }
106
+
107
+ /**
108
+ * Traverses every named, anonymous, extra, directive, and recovery node.
109
+ * @param {import("tree-sitter").SyntaxNode} root - Complete parser root.
110
+ * @returns {void}
111
+ */
112
+ validateTree(root) {
113
+ const pending = [{depth: 0, node: root, visited: false}]
114
+
115
+ while (pending.length) {
116
+ const current = pending.pop()
117
+
118
+ if (!current) throw new Error("Swift traversal lost a pending parser node.")
119
+ const {depth, node, visited} = current
120
+
121
+ if (depth > 512) this.fail(node, "CST exceeds the 512-level traversal limit")
122
+ if (!visited) {
123
+ pending.push({depth, node, visited: true})
124
+ for (let index = node.childCount - 1; index >= 0; index -= 1) {
125
+ const child = node.child(index)
126
+
127
+ if (!child) throw new Error(`Tree-sitter omitted child ${index} of ${node.type}.`)
128
+ pending.push({depth: depth + 1, node: child, visited: false})
129
+ }
130
+ continue
131
+ }
132
+ if (node.hasError || node.isError || node.isMissing) {
133
+ throw new SemantifoldDiagnostic({
134
+ code: "PARSE_ERROR",
135
+ language: "swift",
136
+ location: this.location(node),
137
+ message: `Tree-sitter exposed recovery at '${node.type}'.`
138
+ })
139
+ }
140
+ if (["attribute", "directive", "shebang_line"].includes(node.type)) this.fail(node, node.type)
141
+ if (node.type == "comment" && /swift-tools-version/u.test(node.text)) {
142
+ this.fail(node, "directive-bearing comment")
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Omits only inert comments already accounted for by exhaustive traversal.
149
+ * @param {import("tree-sitter").SyntaxNode} node - Parent node.
150
+ * @returns {import("tree-sitter").SyntaxNode[]} Structural children.
151
+ */
152
+ parts(node) {
153
+ return node.children.filter((child) => child.type != "comment")
154
+ }
155
+
156
+ /**
157
+ * Requires one exact parser field edge.
158
+ * @param {import("tree-sitter").SyntaxNode} node - Field owner.
159
+ * @param {string} name - Field name.
160
+ * @returns {import("tree-sitter").SyntaxNode} Sole field node.
161
+ */
162
+ field(node, name) {
163
+ const matches = []
164
+
165
+ for (let index = 0; index < node.childCount; index += 1) {
166
+ const child = node.child(index)
167
+
168
+ if (!child) throw new Error(`Tree-sitter omitted child ${index} of ${node.type}.`)
169
+ if (node.fieldNameForChild(index) == name) matches.push(child)
170
+ }
171
+ if (matches.length != 1) this.fail(node, `expected one '${name}' field`)
172
+ return matches[0]
173
+ }
174
+
175
+ /**
176
+ * Requires all ordered children, including anonymous punctuation.
177
+ * @param {import("tree-sitter").SyntaxNode} node - Shape owner.
178
+ * @param {(import("tree-sitter").SyntaxNode | string)[]} expected - Exact child sequence.
179
+ * @returns {void}
180
+ */
181
+ shape(node, expected) {
182
+ const actual = this.parts(node)
183
+
184
+ if (actual.length != expected.length) this.fail(actual[Math.min(actual.length, expected.length)] ?? node, `${node.type} child shape`)
185
+ for (let index = 0; index < expected.length; index += 1) {
186
+ const wanted = expected[index]
187
+ const child = actual[index]
188
+ const matches = typeof wanted == "string" ? child.text == wanted : child.id == wanted.id
189
+
190
+ if (!matches) this.fail(child, `${node.type} child shape`)
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Validates one Swift identifier in the portable source profile.
196
+ * @param {import("tree-sitter").SyntaxNode} node - Identifier token.
197
+ * @param {boolean} [allowPrint] - Whether the fixed print scaffold is expected.
198
+ * @returns {string} Accepted spelling.
199
+ */
200
+ identifier(node, allowPrint = false) {
201
+ const name = node.text
202
+
203
+ if (node.type != "simple_identifier" || !(allowPrint && name == "print") &&
204
+ (!isSwiftIdentifier(name) || name.normalize("NFC") != name)) this.fail(node, "reserved or unsupported identifier")
205
+ return name
206
+ }
207
+
208
+ /**
209
+ * Converts exactly Int64, Bool, or String.
210
+ * @param {import("tree-sitter").SyntaxNode} node - Type node.
211
+ * @returns {import("../semantic/types.js").TypeReference} Semantic scalar.
212
+ */
213
+ type(node) {
214
+ const parts = this.parts(node)
215
+
216
+ if (node.type != "user_type" || parts.length != 1 || parts[0].type != "type_identifier") this.fail(node, "scalar type shape")
217
+ this.shape(node, [parts[0]])
218
+ const type = sourceScalarType("swift", parts[0].text, this.location(parts[0]))
219
+
220
+ if (!type) this.fail(parts[0], `unsupported scalar type '${parts[0].text}'`)
221
+ return type
222
+ }
223
+
224
+ /**
225
+ * Converts one exact ordinary Swift string literal.
226
+ * @param {import("tree-sitter").SyntaxNode} node - String node.
227
+ * @returns {string} Unicode scalar value.
228
+ */
229
+ string(node) {
230
+ const parts = this.parts(node)
231
+
232
+ if (node.type != "line_string_literal" || parts.length < 2 || parts[0].text != '"' || parts.at(-1)?.text != '"') {
233
+ return this.fail(node, "ordinary noninterpolated string literal required")
234
+ }
235
+ this.shape(node, ['"', ...parts.slice(1, -1), '"'])
236
+ let value = ""
237
+ const simpleEscapes = new Map([
238
+ ["\\0", "\0"], ["\\n", "\n"], ["\\r", "\r"], ["\\t", "\t"], ["\\\\", "\\"], ['\\"', '"'], ["\\'", "'"]
239
+ ])
240
+
241
+ for (const part of parts.slice(1, -1)) {
242
+ if (part.type == "line_str_text") {
243
+ if (/[\r\n]/u.test(part.text)) this.fail(part, "string line terminator")
244
+ value += part.text
245
+ } else if (part.type == "str_escaped_char") {
246
+ const escape = part.text
247
+
248
+ if (simpleEscapes.has(escape)) value += simpleEscapes.get(escape)
249
+ else {
250
+ const match = /^\\u\{([0-9A-Fa-f]{1,8})\}$/u.exec(escape)
251
+
252
+ if (!match) this.fail(part, "unsupported string escape")
253
+ const scalar = Number.parseInt(match[1], 16)
254
+
255
+ if (scalar > 0x10FFFF || scalar >= 0xD800 && scalar <= 0xDFFF) this.fail(part, "non-scalar Unicode escape")
256
+ value += String.fromCodePoint(scalar)
257
+ }
258
+ } else this.fail(part, part.type == "interpolated_expression" ? "interpolated string" : "string child")
259
+ }
260
+ if (!hasOnlyUnicodeScalars(value)) this.fail(node, "invalid Unicode string literal")
261
+ return value
262
+ }
263
+
264
+ /**
265
+ * Reads exact unlabeled call arguments.
266
+ * @param {import("tree-sitter").SyntaxNode} suffix - Call suffix.
267
+ * @returns {import("tree-sitter").SyntaxNode[]} Argument value nodes.
268
+ */
269
+ arguments(suffix) {
270
+ const suffixParts = this.parts(suffix)
271
+
272
+ if (suffix.type != "call_suffix" || suffixParts.length != 1 || suffixParts[0].type != "value_arguments") {
273
+ return this.fail(suffix, "call suffix shape")
274
+ }
275
+ this.shape(suffix, [suffixParts[0]])
276
+ const list = suffixParts[0]
277
+ const parts = this.parts(list)
278
+
279
+ if (parts.length < 2 || parts[0].text != "(" || parts.at(-1)?.text != ")") this.fail(list, "call argument list shape")
280
+ const arguments_ = parts.slice(1, -1).filter((_part, index) => index % 2 == 0)
281
+ const expected = ["(", ...arguments_.flatMap((argument, index) => index == 0 ? [argument] : [",", argument]), ")"]
282
+
283
+ this.shape(list, expected)
284
+ return arguments_.map((argument) => {
285
+ const value = this.field(argument, "value")
286
+
287
+ if (argument.type != "value_argument") this.fail(argument, "unlabeled argument required")
288
+ this.shape(argument, [value])
289
+ return value
290
+ })
291
+ }
292
+
293
+ /**
294
+ * Converts a direct semantic call, including qualified negated-call and trailing-call binary shapes.
295
+ * @param {import("tree-sitter").SyntaxNode} node - Call node.
296
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
297
+ */
298
+ call(node) {
299
+ const location = this.location(node)
300
+ const parts = this.parts(node)
301
+
302
+ if (node.type != "call_expression" || parts.length != 2) this.fail(node, "direct call shape")
303
+ const target = parts[0]
304
+ const suffix = parts[1]
305
+
306
+ if (binaryNodeOperators.has(target.type)) {
307
+ const right = this.field(target, "rhs")
308
+ const callLocation = locationFromOffsets(this.filename, this.source,
309
+ bindingIndexToUtf16Offset(this.source, right.startIndex), bindingIndexToUtf16Offset(this.source, suffix.endIndex))
310
+
311
+ if (right.type != "simple_identifier") this.fail(node, "trailing direct call shape")
312
+ this.shape(node, [target, suffix])
313
+
314
+ return this.binary(target, undefined, location, this.callParts(right, suffix, callLocation))
315
+ }
316
+
317
+ return this.callParts(target, suffix, location)
318
+ }
319
+
320
+ /**
321
+ * Converts one direct call from its parser target and suffix.
322
+ * @param {import("tree-sitter").SyntaxNode} target - Direct call target.
323
+ * @param {import("tree-sitter").SyntaxNode} suffix - Argument suffix.
324
+ * @param {import("../semantic/types.js").SourceLocation} location - Complete call location.
325
+ * @returns {import("../semantic/types.js").Expression} Semantic call or prefixed call.
326
+ */
327
+ callParts(target, suffix, location) {
328
+ const argumentNodes = this.arguments(suffix)
329
+ let nameNode = target
330
+ /** @type {import("tree-sitter").SyntaxNode | undefined} */
331
+ let unaryOperator
332
+
333
+ if (["!", "-"].includes(nameNode.text)) {
334
+ if (argumentNodes.length != 1) this.fail(target, "parenthesized unary expression shape")
335
+ const expression = this.expression(argumentNodes[0])
336
+
337
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
338
+ kind: "UnaryExpression", location, operand: expression
339
+ }, {operator: this.location(nameNode)}), nameNode.text == "-" ? "Negate" : "Not")))
340
+ }
341
+ if (nameNode.type == "prefix_expression") {
342
+ const operation = this.field(nameNode, "operation")
343
+ const target = this.field(nameNode, "target")
344
+
345
+ this.shape(nameNode, [operation, target])
346
+ if (!["!", "-"].includes(operation.text) || target.type != "simple_identifier") this.fail(nameNode, "prefixed direct call shape")
347
+ unaryOperator = operation
348
+ nameNode = target
349
+ }
350
+ const name = nameNode.text
351
+
352
+ const helperOperation = this.helpers.has(name) ? helperOperations.get(name) : undefined
353
+
354
+ if (helperOperation) {
355
+ if (unaryOperator || argumentNodes.length != 2) this.fail(target, "Swift scalar equality helper shape")
356
+ return /** @type {import("../semantic/types.js").Expression} */ (withAdaptedOperation(withParserRanges({
357
+ kind: "BinaryExpression", left: this.expression(argumentNodes[0]), location, right: this.expression(argumentNodes[1])
358
+ }, {operator: this.location(nameNode)}), helperOperation))
359
+ }
360
+ const semanticName = this.identifier(nameNode)
361
+
362
+ if (argumentNodes.length != 2) this.fail(suffix, "semantic call argument count")
363
+ const call = withParserRanges({
364
+ arguments: argumentNodes.map((argument) => this.expression(argument)),
365
+ callee: semanticName,
366
+ kind: /** @type {const} */ ("CallExpression"),
367
+ location
368
+ }, {callee: this.location(nameNode)})
369
+
370
+ if (!unaryOperator) return call
371
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
372
+ kind: "UnaryExpression", location, operand: call
373
+ }, {operator: this.location(unaryOperator)}), unaryOperator.text == "-" ? "Negate" : "Not")))
374
+ }
375
+
376
+ /**
377
+ * Converts one supported scalar expression.
378
+ * @param {import("tree-sitter").SyntaxNode} node - Expression node.
379
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
380
+ */
381
+ expression(node) {
382
+ const location = this.location(node)
383
+
384
+ if (node.type == "simple_identifier") {
385
+ return withParserRanges({kind: /** @type {const} */ ("IdentifierExpression"), location, name: this.identifier(node)}, {name: location})
386
+ }
387
+ if (node.type == "integer_literal") {
388
+ if (!/^(?:0|[1-9][0-9]*)$/u.test(node.text)) this.fail(node, "noncanonical integer literal")
389
+ const value = Number(BigInt(node.text))
390
+
391
+ if (!Number.isSafeInteger(value)) this.fail(node, "non-safe integer literal")
392
+ return withParserRanges({kind: /** @type {const} */ ("IntegerLiteral"), location, value}, {literal: location})
393
+ }
394
+ if (node.type == "boolean_literal") {
395
+ const parts = this.parts(node)
396
+
397
+ if (parts.length != 1 || !["true", "false"].includes(parts[0].text)) this.fail(node, "Boolean literal shape")
398
+ this.shape(node, [parts[0].text])
399
+ return withParserRanges({kind: /** @type {const} */ ("BooleanLiteral"), location, value: parts[0].text == "true"}, {literal: location})
400
+ }
401
+ if (node.type == "line_string_literal") {
402
+ return withParserRanges({kind: /** @type {const} */ ("StringLiteral"), location, value: this.string(node)}, {literal: location})
403
+ }
404
+ if (node.type == "tuple_expression") {
405
+ const value = this.field(node, "value")
406
+
407
+ this.shape(node, ["(", value, ")"])
408
+ return this.expression(value)
409
+ }
410
+ if (node.type == "prefix_expression") {
411
+ const operation = this.field(node, "operation")
412
+ const target = this.field(node, "target")
413
+
414
+ this.shape(node, [operation, target])
415
+ if (!["-", "!"].includes(operation.text)) this.fail(operation, "unary operator")
416
+ return this.prefixed(operation, target)
417
+ }
418
+ const acceptedOperators = binaryNodeOperators.get(node.type)
419
+
420
+ if (acceptedOperators) {
421
+ return this.binary(node)
422
+ }
423
+ if (node.type == "call_expression") return this.call(node)
424
+ return this.fail(node)
425
+ }
426
+
427
+ /**
428
+ * Converts the grammar's broad prefix target with Swift's tighter prefix precedence.
429
+ * @param {import("tree-sitter").SyntaxNode} operator - Prefix operator.
430
+ * @param {import("tree-sitter").SyntaxNode} target - Grammar target.
431
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
432
+ */
433
+ prefixed(operator, target) {
434
+ const location = locationFromOffsets(this.filename, this.source,
435
+ bindingIndexToUtf16Offset(this.source, operator.startIndex), bindingIndexToUtf16Offset(this.source, target.endIndex))
436
+
437
+ if (binaryNodeOperators.has(target.type)) {
438
+ const left = this.field(target, "lhs")
439
+
440
+ return this.binary(target, this.prefixed(operator, left), location)
441
+ }
442
+
443
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
444
+ kind: "UnaryExpression", location, operand: this.expression(target)
445
+ }, {operator: this.location(operator)}), operator.text == "-" ? "Negate" : "Not")))
446
+ }
447
+
448
+ /**
449
+ * Converts one qualified binary node, optionally replacing its left edge for prefix precedence.
450
+ * @param {import("tree-sitter").SyntaxNode} node - Binary node.
451
+ * @param {import("../semantic/types.js").Expression} [leftExpression] - Adapted left operand.
452
+ * @param {import("../semantic/types.js").SourceLocation} [location] - Adapted expression range.
453
+ * @param {import("../semantic/types.js").Expression} [rightExpression] - Adapted trailing-call right operand.
454
+ * @returns {import("../semantic/types.js").Expression} Semantic expression.
455
+ */
456
+ binary(node, leftExpression, location = this.location(node), rightExpression) {
457
+ const acceptedOperators = binaryNodeOperators.get(node.type)
458
+ const left = this.field(node, "lhs")
459
+ const operator = this.field(node, "op")
460
+ const right = this.field(node, "rhs")
461
+ const operation = binaryOperations.get(operator.text)
462
+
463
+ this.shape(node, [left, operator, right])
464
+ if (!acceptedOperators?.has(operator.text) || !operation) this.fail(operator, "unsupported binary operator")
465
+ const expression = /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withAdaptedOperation(withParserRanges({
466
+ kind: "BinaryExpression", left: leftExpression ?? this.expression(left), location, right: rightExpression ?? this.expression(right)
467
+ }, {operator: this.location(operator)}), /** @type {import("../semantic/operators.js").AdaptedOperation} */ (operation))))
468
+
469
+ if (["==", "!="].includes(operator.text)) this.nativeEqualityOperators.set(expression, operator)
470
+ return expression
471
+ }
472
+
473
+ /**
474
+ * Converts one explicitly typed initialized local.
475
+ * @param {import("tree-sitter").SyntaxNode} node - Property declaration.
476
+ * @returns {import("../semantic/types.js").LocalDeclaration} Semantic local.
477
+ */
478
+ local(node) {
479
+ const location = this.location(node)
480
+ const parts = this.parts(node)
481
+ const binding = parts.find((child) => child.type == "value_binding_pattern")
482
+ const pattern = node.childForFieldName("name")
483
+ const annotation = parts.find((child) => child.type == "type_annotation")
484
+ const value = node.childForFieldName("value")
485
+
486
+ if (!annotation) return missingType("swift", "Local", location)
487
+ if (!binding || !pattern || !value || pattern.type != "pattern") this.fail(node, "local declaration shape")
488
+ const bindingParts = this.parts(binding)
489
+ const nameNode = pattern.childForFieldName("bound_identifier")
490
+ const annotationParts = this.parts(annotation)
491
+
492
+ if (bindingParts.length != 1 || !["let", "var"].includes(bindingParts[0].text) || !nameNode || annotationParts.length != 2) {
493
+ this.fail(node, "local declaration shape")
494
+ }
495
+ this.shape(binding, [bindingParts[0].text])
496
+ this.shape(pattern, [nameNode])
497
+ this.shape(annotation, [":", annotationParts[1]])
498
+ this.shape(node, [binding, pattern, annotation, "=", value])
499
+ const name = this.identifier(nameNode)
500
+
501
+ return withParserRanges({
502
+ initializer: this.expression(value),
503
+ kind: /** @type {const} */ ("LocalDeclaration"),
504
+ location,
505
+ mutable: bindingParts[0].text == "var",
506
+ name,
507
+ type: this.type(annotationParts[1])
508
+ }, {name: this.location(nameNode), operator: this.location(parts[3])})
509
+ }
510
+
511
+ /**
512
+ * Converts one plain identifier assignment.
513
+ * @param {import("tree-sitter").SyntaxNode} node - Assignment node.
514
+ * @returns {import("../semantic/types.js").AssignmentStatement} Semantic assignment.
515
+ */
516
+ assignment(node) {
517
+ const target = this.field(node, "target")
518
+ const operator = this.field(node, "operator")
519
+ const value = this.field(node, "result")
520
+ const targetParts = this.parts(target)
521
+
522
+ if (target.type != "directly_assignable_expression" || targetParts.length != 1 || operator.text != "=") {
523
+ this.fail(node, "assignment shape")
524
+ }
525
+ this.shape(target, [targetParts[0]])
526
+ this.shape(node, [target, operator, value])
527
+ const name = this.identifier(targetParts[0])
528
+ const targetLocation = this.location(targetParts[0])
529
+
530
+ return withParserRanges({
531
+ expression: this.expression(value),
532
+ kind: /** @type {const} */ ("AssignmentStatement"),
533
+ location: this.location(node),
534
+ target: withParserRanges({kind: /** @type {const} */ ("IdentifierExpression"), location: targetLocation, name}, {name: targetLocation})
535
+ }, {operator: this.location(operator)})
536
+ }
537
+
538
+ /**
539
+ * Converts one exact print call.
540
+ * @param {import("tree-sitter").SyntaxNode} node - Call statement.
541
+ * @returns {import("../semantic/types.js").PrintStatement} Semantic print.
542
+ */
543
+ print(node) {
544
+ const parts = this.parts(node)
545
+
546
+ if (node.type != "call_expression" || parts.length != 2 || parts[0].type != "simple_identifier" ||
547
+ this.identifier(parts[0], true) != "print") this.fail(node, "exact print call required")
548
+ const arguments_ = this.arguments(parts[1])
549
+
550
+ if (arguments_.length != 1) this.fail(parts[1], "print argument count")
551
+ return {expression: this.expression(arguments_[0]), kind: /** @type {const} */ ("PrintStatement"), location: this.location(node)}
552
+ }
553
+
554
+ /**
555
+ * Converts one supported statement.
556
+ * @param {import("tree-sitter").SyntaxNode} node - Statement node.
557
+ * @returns {import("../semantic/types.js").Statement} Semantic statement.
558
+ */
559
+ statement(node) {
560
+ if (node.type == "property_declaration") return this.local(node)
561
+ if (node.type == "assignment") return this.assignment(node)
562
+ if (node.type == "if_statement") return this.conditional(node)
563
+ if (node.type == "call_expression") return this.print(node)
564
+ if (node.type == "control_transfer_statement") {
565
+ const result = node.childForFieldName("result")
566
+
567
+ if (!result) this.fail(node, "return without expression")
568
+ this.shape(node, ["return", result])
569
+ return {expression: this.expression(result), kind: /** @type {const} */ ("ReturnStatement"), location: this.location(node)}
570
+ }
571
+ return this.fail(node)
572
+ }
573
+
574
+ /**
575
+ * Converts one parser statements node.
576
+ * @param {import("tree-sitter").SyntaxNode | undefined} node - Optional statements node.
577
+ * @returns {import("../semantic/types.js").Statement[]} Ordered statements.
578
+ */
579
+ statements(node) {
580
+ if (!node) return []
581
+ if (node.type != "statements") this.fail(node, "statement list shape")
582
+ return this.statementList(this.parts(node))
583
+ }
584
+
585
+ /**
586
+ * Converts a statement sequence while collapsing an adjacent generated marker.
587
+ * @param {import("tree-sitter").SyntaxNode[]} nodes - Ordered statement nodes.
588
+ * @returns {import("../semantic/types.js").Statement[]} Semantic statements.
589
+ */
590
+ statementList(nodes) {
591
+ /** @type {import("../semantic/types.js").Statement[]} */
592
+ const statements = []
593
+
594
+ for (const statement of nodes) {
595
+ const parts = this.parts(statement)
596
+ const marker = statement.type == "call_expression" && parts[0]?.text == "semantifold_keep_mutable"
597
+
598
+ if (marker) {
599
+ const previous = statements.at(-1)
600
+
601
+ if (!previous || previous.kind != "LocalDeclaration" || !previous.mutable) this.fail(statement, "Swift mutable-local warning marker")
602
+ this.mutableMarkerCall(statement, previous)
603
+ } else statements.push(this.statement(statement))
604
+ }
605
+ return statements
606
+ }
607
+
608
+ /**
609
+ * Collapses the generated inout call only beside its declared mutable local.
610
+ * @param {import("tree-sitter").SyntaxNode} node - Generated marker call.
611
+ * @param {import("../semantic/types.js").LocalDeclaration} local - Preceding local.
612
+ * @returns {void}
613
+ */
614
+ mutableMarkerCall(node, local) {
615
+ const parts = this.parts(node)
616
+ const arguments_ = parts.length == 2 ? this.arguments(parts[1]) : []
617
+ const argument = arguments_[0]
618
+ const target = argument?.type == "prefix_expression" ? this.field(argument, "target") : undefined
619
+
620
+ if (!this.mutableMarker || parts[0]?.type != "simple_identifier" || parts[0].text != "semantifold_keep_mutable" ||
621
+ arguments_.length != 1 || !target || target.type != "simple_identifier" || target.text != local.name) {
622
+ this.fail(node, "Swift mutable-local warning marker")
623
+ }
624
+ this.shape(node, [parts[0], parts[1]])
625
+ this.shape(argument, ["&", target])
626
+ }
627
+
628
+ /**
629
+ * Converts one exact braced conditional, including direct else-if.
630
+ * @param {import("tree-sitter").SyntaxNode} node - If node.
631
+ * @returns {import("../semantic/types.js").IfStatement} Semantic conditional.
632
+ */
633
+ conditional(node) {
634
+ const parts = this.parts(node)
635
+ const condition = this.field(node, "condition")
636
+ let index = 3
637
+ const consequentStatements = parts[index]?.type == "statements" ? parts[index++] : undefined
638
+
639
+ if (node.type != "if_statement" || parts[0]?.text != "if" || parts[1]?.id != condition.id || parts[2]?.text != "{" ||
640
+ parts[index]?.text != "}") this.fail(node, "if statement shape")
641
+ index += 1
642
+ const statement = {
643
+ condition: this.expression(condition),
644
+ consequent: {kind: /** @type {const} */ ("Block"), location: this.location(consequentStatements ?? node),
645
+ statements: this.statements(consequentStatements)},
646
+ kind: /** @type {const} */ ("IfStatement"),
647
+ location: this.location(node)
648
+ }
649
+
650
+ if (index == parts.length) {
651
+ this.shape(node, ["if", condition, "{", ...(consequentStatements ? [consequentStatements] : []), "}"])
652
+ return statement
653
+ }
654
+ if (parts[index]?.text != "else") this.fail(parts[index] ?? node, "if alternate shape")
655
+ index += 1
656
+ const branch = parts[index]
657
+
658
+ if (branch?.type == "if_statement" && index + 1 == parts.length) {
659
+ this.shape(node, ["if", condition, "{", ...(consequentStatements ? [consequentStatements] : []), "}", "else", branch])
660
+ return {...statement, alternate: {kind: /** @type {const} */ ("Block"), location: this.location(branch), statements: [this.conditional(branch)]}}
661
+ }
662
+ if (branch?.text != "{") this.fail(branch ?? node, "if alternate block shape")
663
+ index += 1
664
+ const alternateStatements = parts[index]?.type == "statements" ? parts[index++] : undefined
665
+
666
+ if (parts[index]?.text != "}" || index + 1 != parts.length) this.fail(parts[index] ?? node, "if alternate block shape")
667
+ this.shape(node, ["if", condition, "{", ...(consequentStatements ? [consequentStatements] : []), "}", "else", "{",
668
+ ...(alternateStatements ? [alternateStatements] : []), "}"])
669
+ return {...statement, alternate: {kind: /** @type {const} */ ("Block"), location: this.location(alternateStatements ?? node),
670
+ statements: this.statements(alternateStatements)}}
671
+ }
672
+
673
+ /**
674
+ * Converts one function body.
675
+ * @param {import("tree-sitter").SyntaxNode} node - Function body.
676
+ * @returns {import("../semantic/types.js").Block} Semantic block.
677
+ */
678
+ block(node) {
679
+ const parts = this.parts(node)
680
+ const statements = parts[1]?.type == "statements" ? parts[1] : undefined
681
+
682
+ if (node.type != "function_body") this.fail(node, "function body shape")
683
+ this.shape(node, ["{", ...(statements ? [statements] : []), "}"])
684
+ return {kind: /** @type {const} */ ("Block"), location: this.location(node), statements: this.statements(statements)}
685
+ }
686
+
687
+ /**
688
+ * Converts one exact underscore-labeled parameter.
689
+ * @param {import("tree-sitter").SyntaxNode} node - Parameter node.
690
+ * @returns {import("../semantic/types.js").Parameter} Semantic parameter.
691
+ */
692
+ parameter(node) {
693
+ const parts = this.parts(node)
694
+
695
+ if (node.type != "parameter" || parts.length != 4 || parts[0].text != "_" || parts[0].type != "simple_identifier" ||
696
+ parts[1].type != "simple_identifier" || parts[2].text != ":") this.fail(node, "parameter shape")
697
+ this.shape(node, [parts[0], parts[1], ":", parts[3]])
698
+ const name = this.identifier(parts[1])
699
+
700
+ return withParserRanges({kind: /** @type {const} */ ("Parameter"), location: this.location(node), name, type: this.type(parts[3])}, {
701
+ name: this.location(parts[1])
702
+ })
703
+ }
704
+
705
+ /**
706
+ * Converts one synchronous top-level scalar function.
707
+ * @param {import("tree-sitter").SyntaxNode} node - Function node.
708
+ * @returns {import("../semantic/types.js").FunctionDeclaration} Semantic function.
709
+ */
710
+ function(node) {
711
+ const parts = this.parts(node)
712
+ const nameNode = node.childForFieldName("name")
713
+ const body = node.childForFieldName("body")
714
+ const parameters = parts.filter((part) => part.type == "parameter")
715
+
716
+ if (!nameNode || !body || node.type != "function_declaration") this.fail(node, "function declaration shape")
717
+ if (parameters.length != 2) this.fail(node, "function parameter count other than two")
718
+ if (!parts.some((part) => part.text == "->")) return missingType("swift", "Function return", this.location(node))
719
+ if (parts.length != 10) this.fail(parts.find((part) => !["func", "(", ",", ")", "->"].includes(part.text) &&
720
+ part.id != nameNode.id && part.id != body.id && !parameters.some((parameter) => parameter.id == part.id)) ?? node, "function declaration shape")
721
+ const returnType = parts[8]
722
+
723
+ this.shape(node, ["func", nameNode, "(", parameters[0], ",", parameters[1], ")", "->", returnType, body])
724
+ const name = this.identifier(nameNode)
725
+
726
+ return withParserRanges({
727
+ body: this.block(body),
728
+ kind: /** @type {const} */ ("FunctionDeclaration"),
729
+ location: this.location(node),
730
+ name,
731
+ parameters: parameters.map((parameter) => this.parameter(parameter)),
732
+ returnType: this.type(returnType)
733
+ }, {name: this.location(nameNode)})
734
+ }
735
+
736
+ /**
737
+ * Compares every child field and leaf token against target-only canonical support.
738
+ * @param {import("tree-sitter").SyntaxNode} actual - Source support node.
739
+ * @param {import("tree-sitter").SyntaxNode} expected - Canonical support node.
740
+ * @param {SwiftReader} canonical - Canonical source reader.
741
+ * @returns {void}
742
+ */
743
+ compareTree(actual, expected, canonical) {
744
+ if (actual.type != expected.type || actual.isNamed != expected.isNamed || actual.isExtra != expected.isExtra ||
745
+ actual.childCount != expected.childCount) this.fail(actual, "modified Swift support node")
746
+ if (!actual.childCount && actual.text != expected.text) this.fail(actual, "modified Swift support token")
747
+ for (let index = 0; index < actual.childCount; index += 1) {
748
+ const left = actual.child(index)
749
+ const right = expected.child(index)
750
+
751
+ if (!left || !right || actual.fieldNameForChild(index) != expected.fieldNameForChild(index)) {
752
+ this.fail(left ?? actual, "modified Swift support field")
753
+ }
754
+ this.compareTree(left, right, canonical)
755
+ }
756
+ }
757
+
758
+ /**
759
+ * Rejects ordinary Swift equality after shared type resolution identifies Strings.
760
+ * @param {import("../semantic/types.js").SemanticModule} module - Validated semantic module.
761
+ * @returns {void}
762
+ */
763
+ rejectNativeStringEquality(module) {
764
+ const pending = [module.entryPoint.body, ...module.functions.map((declaration) => declaration.body)]
765
+
766
+ while (pending.length) {
767
+ const block = pending.pop()
768
+
769
+ if (!block) throw new Error("Swift semantic traversal lost a pending block.")
770
+ for (const statement of block.statements) {
771
+ if (statement.kind == "IfStatement") {
772
+ pending.push(statement.consequent)
773
+ if (statement.alternate) pending.push(statement.alternate)
774
+ this.rejectNativeStringEqualityExpression(statement.condition)
775
+ } else if (statement.kind == "LocalDeclaration") this.rejectNativeStringEqualityExpression(statement.initializer)
776
+ else if (statement.kind == "AssignmentStatement") this.rejectNativeStringEqualityExpression(statement.expression)
777
+ else if (statement.kind == "ExpressionStatement" || statement.kind == "PrintStatement") {
778
+ this.rejectNativeStringEqualityExpression(statement.expression)
779
+ } else if (statement.kind == "ReturnStatement" && statement.expression) {
780
+ this.rejectNativeStringEqualityExpression(statement.expression)
781
+ }
782
+ }
783
+ }
784
+ }
785
+
786
+ /**
787
+ * Checks one validated expression without retaining parser state in public values.
788
+ * @param {import("../semantic/types.js").Expression} root - Validated expression.
789
+ * @returns {void}
790
+ */
791
+ rejectNativeStringEqualityExpression(root) {
792
+ const pending = [root]
793
+
794
+ while (pending.length) {
795
+ const expression = pending.pop()
796
+
797
+ if (!expression) throw new Error("Swift semantic traversal lost a pending expression.")
798
+ if (expression.kind == "BinaryExpression") {
799
+ const operator = this.nativeEqualityOperators.get(expression)
800
+
801
+ if (operator && ["StringEqual", "StringNotEqual"].includes(expression.operation)) {
802
+ this.fail(operator, "ordinary Swift String equality")
803
+ }
804
+ pending.push(expression.left, expression.right)
805
+ } else if (expression.kind == "UnaryExpression") pending.push(expression.operand)
806
+ else if (expression.kind == "CallExpression") pending.push(...expression.arguments)
807
+ }
808
+ }
809
+
810
+ /**
811
+ * Converts the complete source file with declarations before top-level entry statements.
812
+ * @param {import("tree-sitter").SyntaxNode} root - Source root.
813
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
814
+ */
815
+ module(root) {
816
+ this.validateTree(root)
817
+ if (root.type != "source_file") this.fail(root, "source file root")
818
+ const parts = this.parts(root)
819
+ const canonical = new SwiftReader(this.filename, swiftRuntime)
820
+ const support = canonical.parts(parser.parse(swiftRuntime).rootNode)
821
+ let supportIndex = 0
822
+
823
+ while (supportIndex < parts.length && supportIndex < support.length) {
824
+ const node = parts[supportIndex]
825
+ const name = node.type == "function_declaration" ? node.childForFieldName("name") : undefined
826
+ const expectedName = support[supportIndex].childForFieldName("name")
827
+
828
+ if (!name || !expectedName || name.text != expectedName.text) break
829
+ this.compareTree(node, support[supportIndex], canonical)
830
+ if (helperOperations.has(name.text)) this.helpers.add(name.text)
831
+ else if (name.text == "semantifold_keep_mutable") this.mutableMarker = true
832
+ supportIndex += 1
833
+ }
834
+ if (supportIndex > 0 && supportIndex != support.length) this.fail(parts[supportIndex - 1], "complete Swift support required")
835
+ const semanticParts = parts.slice(supportIndex)
836
+ const firstEntry = semanticParts.findIndex((node) => node.type != "function_declaration")
837
+ const split = firstEntry < 0 ? semanticParts.length : firstEntry
838
+ const declarations = semanticParts.slice(0, split)
839
+ const entries = semanticParts.slice(split)
840
+
841
+ if (!declarations.length) this.fail(root, "top-level semantic function required")
842
+ const laterFunction = entries.find((node) => node.type == "function_declaration")
843
+ const unsupportedEntry = entries.find((node) => !["assignment", "call_expression", "control_transfer_statement", "if_statement",
844
+ "property_declaration", "function_declaration"].includes(node.type))
845
+
846
+ if (unsupportedEntry) this.fail(unsupportedEntry)
847
+ if (laterFunction) this.fail(laterFunction, "function declaration after entry statement")
848
+ if (!entries.length) this.fail(root, "top-level entry/print shell required")
849
+ const module = {
850
+ entryPoint: {body: {kind: /** @type {const} */ ("Block"), location: this.location(root),
851
+ statements: this.statementList(entries)}, kind: /** @type {const} */ ("EntryPoint"), location: this.location(root)},
852
+ functions: declarations.map((declaration) => this.function(declaration)),
853
+ kind: /** @type {const} */ ("Module"),
854
+ location: this.location(root)
855
+ }
856
+
857
+ validateParsedModule(module, "swift")
858
+ this.rejectNativeStringEquality(module)
859
+ return module
860
+ }
861
+ }
862
+
863
+ /**
864
+ * Parses the strict Task 022 Swift profile through the qualified grammar.
865
+ * @param {{filename: string, source: string}} input - Exact source request.
866
+ * @returns {import("../semantic/types.js").SemanticModule} Semantic module.
867
+ */
868
+ export function parseSwift({filename, source}) {
869
+ if (!hasOnlyUnicodeScalars(source)) {
870
+ const offset = firstLoneSurrogateOffset(source)
871
+
872
+ throw new SemantifoldDiagnostic({
873
+ code: "PARSE_ERROR",
874
+ language: "swift",
875
+ location: locationFromOffsets(filename, source, offset, offset + 1),
876
+ message: "Swift source contains an invalid lone UTF-16 surrogate."
877
+ })
878
+ }
879
+ let tree
880
+
881
+ try {
882
+ tree = parser.parse(source)
883
+ } catch (error) {
884
+ throw new SemantifoldDiagnostic({
885
+ cause: error instanceof Error ? error : undefined,
886
+ code: "PARSE_ERROR",
887
+ language: "swift",
888
+ location: moduleLocation(filename, source),
889
+ message: "The qualified Swift parser could not produce a complete CST."
890
+ })
891
+ }
892
+ return new SwiftReader(filename, source).module(tree.rootNode)
893
+ }