semantifold 0.3.0 → 0.5.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 (303) hide show
  1. package/README.md +61 -15
  2. package/build/index.d.ts +52 -2
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +60 -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/android.d.ts +49 -0
  11. package/build/src/backends/android.d.ts.map +1 -0
  12. package/build/src/backends/android.js +1274 -0
  13. package/build/src/backends/c-validation.d.ts.map +1 -1
  14. package/build/src/backends/c-validation.js +7 -3
  15. package/build/src/backends/cpp-validation.d.ts.map +1 -1
  16. package/build/src/backends/cpp-validation.js +7 -3
  17. package/build/src/backends/csharp.js +7 -1
  18. package/build/src/backends/dart-runtime.d.ts +2 -0
  19. package/build/src/backends/dart-runtime.d.ts.map +1 -0
  20. package/build/src/backends/dart-runtime.js +41 -0
  21. package/build/src/backends/dart.d.ts +20 -0
  22. package/build/src/backends/dart.d.ts.map +1 -0
  23. package/build/src/backends/dart.js +321 -0
  24. package/build/src/backends/effects.d.ts +60 -0
  25. package/build/src/backends/effects.d.ts.map +1 -0
  26. package/build/src/backends/effects.js +746 -0
  27. package/build/src/backends/go.js +18 -4
  28. package/build/src/backends/identifiers.d.ts +36 -4
  29. package/build/src/backends/identifiers.d.ts.map +1 -1
  30. package/build/src/backends/identifiers.js +160 -10
  31. package/build/src/backends/index.d.ts.map +1 -1
  32. package/build/src/backends/index.js +27 -4
  33. package/build/src/backends/ios.d.ts +68 -0
  34. package/build/src/backends/ios.d.ts.map +1 -0
  35. package/build/src/backends/ios.js +1503 -0
  36. package/build/src/backends/java.d.ts.map +1 -1
  37. package/build/src/backends/java.js +429 -36
  38. package/build/src/backends/javascript.d.ts +6 -0
  39. package/build/src/backends/javascript.d.ts.map +1 -1
  40. package/build/src/backends/javascript.js +380 -24
  41. package/build/src/backends/kotlin-runtime.d.ts +3 -0
  42. package/build/src/backends/kotlin-runtime.d.ts.map +1 -0
  43. package/build/src/backends/kotlin-runtime.js +29 -0
  44. package/build/src/backends/kotlin.d.ts +33 -0
  45. package/build/src/backends/kotlin.d.ts.map +1 -0
  46. package/build/src/backends/kotlin.js +138 -0
  47. package/build/src/backends/native-validation.d.ts +2 -2
  48. package/build/src/backends/native-validation.d.ts.map +1 -1
  49. package/build/src/backends/native-validation.js +2 -2
  50. package/build/src/backends/ordered-expressions.d.ts.map +1 -1
  51. package/build/src/backends/ordered-expressions.js +39 -7
  52. package/build/src/backends/php-stdlib-support.d.ts +19 -0
  53. package/build/src/backends/php-stdlib-support.d.ts.map +1 -0
  54. package/build/src/backends/php-stdlib-support.js +227 -0
  55. package/build/src/backends/php.d.ts.map +1 -1
  56. package/build/src/backends/php.js +448 -33
  57. package/build/src/backends/program.d.ts +83 -0
  58. package/build/src/backends/program.d.ts.map +1 -0
  59. package/build/src/backends/program.js +1309 -0
  60. package/build/src/backends/python.js +7 -1
  61. package/build/src/backends/ruby.d.ts.map +1 -1
  62. package/build/src/backends/ruby.js +310 -24
  63. package/build/src/backends/rust-runtime.d.ts +7 -0
  64. package/build/src/backends/rust-runtime.d.ts.map +1 -0
  65. package/build/src/backends/rust-runtime.js +32 -0
  66. package/build/src/backends/rust-validation.d.ts +9 -0
  67. package/build/src/backends/rust-validation.d.ts.map +1 -0
  68. package/build/src/backends/rust-validation.js +78 -0
  69. package/build/src/backends/rust.d.ts +24 -0
  70. package/build/src/backends/rust.d.ts.map +1 -0
  71. package/build/src/backends/rust.js +344 -0
  72. package/build/src/backends/scalars.d.ts +14 -6
  73. package/build/src/backends/scalars.d.ts.map +1 -1
  74. package/build/src/backends/scalars.js +167 -17
  75. package/build/src/backends/shared.d.ts +23 -4
  76. package/build/src/backends/shared.d.ts.map +1 -1
  77. package/build/src/backends/shared.js +2174 -62
  78. package/build/src/backends/stdlib-support.d.ts +14 -0
  79. package/build/src/backends/stdlib-support.d.ts.map +1 -0
  80. package/build/src/backends/stdlib-support.js +237 -0
  81. package/build/src/backends/swift-runtime.d.ts +3 -0
  82. package/build/src/backends/swift-runtime.d.ts.map +1 -0
  83. package/build/src/backends/swift-runtime.js +14 -0
  84. package/build/src/backends/swift.d.ts +8 -0
  85. package/build/src/backends/swift.d.ts.map +1 -0
  86. package/build/src/backends/swift.js +127 -0
  87. package/build/src/backends/typescript.d.ts.map +1 -1
  88. package/build/src/backends/typescript.js +344 -24
  89. package/build/src/backends/wasm.d.ts +43 -0
  90. package/build/src/backends/wasm.d.ts.map +1 -0
  91. package/build/src/backends/wasm.js +2164 -0
  92. package/build/src/backends/writer.d.ts +255 -4
  93. package/build/src/backends/writer.d.ts.map +1 -1
  94. package/build/src/backends/writer.js +491 -3
  95. package/build/src/diagnostic.d.ts +4 -3
  96. package/build/src/diagnostic.d.ts.map +1 -1
  97. package/build/src/diagnostic.js +5 -3
  98. package/build/src/frontends/c.d.ts.map +1 -1
  99. package/build/src/frontends/c.js +5 -3
  100. package/build/src/frontends/cpp.d.ts.map +1 -1
  101. package/build/src/frontends/cpp.js +5 -3
  102. package/build/src/frontends/csharp.d.ts.map +1 -1
  103. package/build/src/frontends/csharp.js +7 -3
  104. package/build/src/frontends/dart.d.ts +10 -0
  105. package/build/src/frontends/dart.d.ts.map +1 -0
  106. package/build/src/frontends/dart.js +913 -0
  107. package/build/src/frontends/index.d.ts +3 -1
  108. package/build/src/frontends/index.d.ts.map +1 -1
  109. package/build/src/frontends/index.js +15 -5
  110. package/build/src/frontends/java.d.ts +110 -1
  111. package/build/src/frontends/java.d.ts.map +1 -1
  112. package/build/src/frontends/java.js +1725 -70
  113. package/build/src/frontends/javascript-typescript.d.ts +69 -1
  114. package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
  115. package/build/src/frontends/javascript-typescript.js +1825 -93
  116. package/build/src/frontends/kotlin.d.ts +10 -0
  117. package/build/src/frontends/kotlin.d.ts.map +1 -0
  118. package/build/src/frontends/kotlin.js +685 -0
  119. package/build/src/frontends/php.d.ts +118 -1
  120. package/build/src/frontends/php.d.ts.map +1 -1
  121. package/build/src/frontends/php.js +1583 -76
  122. package/build/src/frontends/program.d.ts +74 -0
  123. package/build/src/frontends/program.d.ts.map +1 -0
  124. package/build/src/frontends/program.js +989 -0
  125. package/build/src/frontends/ruby.d.ts +68 -1
  126. package/build/src/frontends/ruby.d.ts.map +1 -1
  127. package/build/src/frontends/ruby.js +1446 -101
  128. package/build/src/frontends/rust-parser.d.ts +11 -0
  129. package/build/src/frontends/rust-parser.d.ts.map +1 -0
  130. package/build/src/frontends/rust-parser.js +15 -0
  131. package/build/src/frontends/rust.d.ts +14 -0
  132. package/build/src/frontends/rust.d.ts.map +1 -0
  133. package/build/src/frontends/rust.js +715 -0
  134. package/build/src/frontends/scalars.d.ts +10 -0
  135. package/build/src/frontends/scalars.d.ts.map +1 -1
  136. package/build/src/frontends/scalars.js +28 -2
  137. package/build/src/frontends/swift.d.ts +10 -0
  138. package/build/src/frontends/swift.d.ts.map +1 -0
  139. package/build/src/frontends/swift.js +860 -0
  140. package/build/src/frontends/types.d.ts +186 -0
  141. package/build/src/frontends/types.d.ts.map +1 -0
  142. package/build/src/frontends/types.js +634 -0
  143. package/build/src/language-registry.d.ts +46 -4
  144. package/build/src/language-registry.d.ts.map +1 -1
  145. package/build/src/language-registry.js +177 -13
  146. package/build/src/mapping.d.ts +2 -2
  147. package/build/src/mapping.d.ts.map +1 -1
  148. package/build/src/mapping.js +31 -10
  149. package/build/src/semantic/capabilities.d.ts +66 -0
  150. package/build/src/semantic/capabilities.d.ts.map +1 -0
  151. package/build/src/semantic/capabilities.js +649 -0
  152. package/build/src/semantic/effects.d.ts +26 -0
  153. package/build/src/semantic/effects.d.ts.map +1 -0
  154. package/build/src/semantic/effects.js +764 -0
  155. package/build/src/semantic/generics.d.ts +23 -0
  156. package/build/src/semantic/generics.d.ts.map +1 -0
  157. package/build/src/semantic/generics.js +61 -0
  158. package/build/src/semantic/lifetime.d.ts +37 -0
  159. package/build/src/semantic/lifetime.d.ts.map +1 -0
  160. package/build/src/semantic/lifetime.js +527 -0
  161. package/build/src/semantic/provenance.d.ts +9 -2
  162. package/build/src/semantic/provenance.d.ts.map +1 -1
  163. package/build/src/semantic/provenance.js +462 -20
  164. package/build/src/semantic/scalars.d.ts +11 -0
  165. package/build/src/semantic/scalars.d.ts.map +1 -1
  166. package/build/src/semantic/scalars.js +16 -1
  167. package/build/src/semantic/stdlib.d.ts +254 -0
  168. package/build/src/semantic/stdlib.d.ts.map +1 -0
  169. package/build/src/semantic/stdlib.js +880 -0
  170. package/build/src/semantic/types.d.ts +3108 -178
  171. package/build/src/semantic/types.d.ts.map +1 -1
  172. package/build/src/semantic/types.js +730 -15
  173. package/build/src/semantic/validate.d.ts +85 -5
  174. package/build/src/semantic/validate.d.ts.map +1 -1
  175. package/build/src/semantic/validate.js +2576 -98
  176. package/build/src/stdlib-facades.d.ts +304 -0
  177. package/build/src/stdlib-facades.d.ts.map +1 -0
  178. package/build/src/stdlib-facades.js +1167 -0
  179. package/build/src/stdlib-negotiation.d.ts +69 -0
  180. package/build/src/stdlib-negotiation.d.ts.map +1 -0
  181. package/build/src/stdlib-negotiation.js +403 -0
  182. package/build/src/stdlib-providers.d.ts +72 -0
  183. package/build/src/stdlib-providers.d.ts.map +1 -0
  184. package/build/src/stdlib-providers.js +339 -0
  185. package/build/src/toolchains.d.ts +55 -1
  186. package/build/src/toolchains.d.ts.map +1 -1
  187. package/build/src/toolchains.js +15 -4
  188. package/docs/android.md +79 -0
  189. package/docs/architecture.md +47 -13
  190. package/docs/dart.md +60 -0
  191. package/docs/goals.md +3 -3
  192. package/docs/ios.md +121 -0
  193. package/docs/kotlin.md +42 -0
  194. package/docs/language-support.md +238 -26
  195. package/docs/multi-file-modules.md +52 -0
  196. package/docs/parser-qualification.md +121 -8
  197. package/docs/plans/2026-09-05-standard-library-portability.md +10 -10
  198. package/docs/rust.md +88 -0
  199. package/docs/source-maps.md +17 -7
  200. package/docs/specification.md +5 -0
  201. package/docs/standard-library-portability.md +39 -8
  202. package/docs/swift.md +44 -0
  203. package/docs/testing.md +381 -4
  204. package/docs/webassembly.md +52 -0
  205. package/index.js +66 -8
  206. package/node_modules/semantifold-tree-sitter-legacy-internal/README.md +2 -2
  207. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/LICENSE +21 -0
  208. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/README.md +45 -0
  209. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/binding.gyp +30 -0
  210. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding.cc +20 -0
  211. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding_test.js +9 -0
  212. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.d.ts +28 -0
  213. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.js +11 -0
  214. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/grammar.js +1630 -0
  215. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/package.json +64 -0
  216. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-arm64/tree-sitter-rust.node +0 -0
  217. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-x64/tree-sitter-rust.node +0 -0
  218. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-arm64/tree-sitter-rust.node +0 -0
  219. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-x64/tree-sitter-rust.node +0 -0
  220. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-arm64/tree-sitter-rust.node +0 -0
  221. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-x64/tree-sitter-rust.node +0 -0
  222. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/highlights.scm +159 -0
  223. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/injections.scm +9 -0
  224. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/tags.scm +60 -0
  225. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/grammar.json +9405 -0
  226. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/node-types.json +5399 -0
  227. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/parser.c +192569 -0
  228. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/scanner.c +393 -0
  229. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/alloc.h +54 -0
  230. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/array.h +290 -0
  231. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/parser.h +266 -0
  232. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter-rust.wasm +0 -0
  233. package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter.json +53 -0
  234. package/node_modules/semantifold-tree-sitter-legacy-internal/package.json +3 -2
  235. package/node_modules/semantifold-tree-sitter-legacy-internal/src/c.js +5 -4
  236. package/package.json +5 -2
  237. package/src/artifact-path.js +47 -2
  238. package/src/artifacts.js +67 -0
  239. package/src/backends/android.js +1370 -0
  240. package/src/backends/c-validation.js +6 -1
  241. package/src/backends/cpp-validation.js +6 -1
  242. package/src/backends/csharp.js +3 -0
  243. package/src/backends/dart-runtime.js +41 -0
  244. package/src/backends/dart.js +326 -0
  245. package/src/backends/effects.js +705 -0
  246. package/src/backends/go.js +14 -2
  247. package/src/backends/identifiers.js +166 -9
  248. package/src/backends/index.js +27 -2
  249. package/src/backends/ios.js +1612 -0
  250. package/src/backends/java.js +454 -36
  251. package/src/backends/javascript.js +389 -23
  252. package/src/backends/kotlin-runtime.js +29 -0
  253. package/src/backends/kotlin.js +144 -0
  254. package/src/backends/native-validation.js +1 -1
  255. package/src/backends/ordered-expressions.js +40 -6
  256. package/src/backends/php-stdlib-support.js +239 -0
  257. package/src/backends/php.js +469 -32
  258. package/src/backends/program.js +1408 -0
  259. package/src/backends/python.js +3 -0
  260. package/src/backends/ruby.js +326 -23
  261. package/src/backends/rust-runtime.js +34 -0
  262. package/src/backends/rust-validation.js +75 -0
  263. package/src/backends/rust.js +335 -0
  264. package/src/backends/scalars.js +141 -16
  265. package/src/backends/shared.js +2314 -115
  266. package/src/backends/stdlib-support.js +234 -0
  267. package/src/backends/swift-runtime.js +14 -0
  268. package/src/backends/swift.js +132 -0
  269. package/src/backends/typescript.js +349 -23
  270. package/src/backends/wasm.js +2208 -0
  271. package/src/backends/writer.js +545 -2
  272. package/src/diagnostic.js +4 -2
  273. package/src/frontends/c.js +4 -2
  274. package/src/frontends/cpp.js +4 -2
  275. package/src/frontends/csharp.js +4 -2
  276. package/src/frontends/dart.js +963 -0
  277. package/src/frontends/index.js +14 -4
  278. package/src/frontends/java.js +1977 -69
  279. package/src/frontends/javascript-typescript.js +2046 -102
  280. package/src/frontends/kotlin.js +713 -0
  281. package/src/frontends/php.js +1725 -79
  282. package/src/frontends/program.js +1062 -0
  283. package/src/frontends/ruby.js +1624 -98
  284. package/src/frontends/rust-parser.js +18 -0
  285. package/src/frontends/rust.js +714 -0
  286. package/src/frontends/scalars.js +31 -1
  287. package/src/frontends/swift.js +893 -0
  288. package/src/frontends/types.js +750 -0
  289. package/src/language-registry.js +182 -12
  290. package/src/mapping.js +33 -9
  291. package/src/semantic/capabilities.js +671 -0
  292. package/src/semantic/effects.js +737 -0
  293. package/src/semantic/generics.js +58 -0
  294. package/src/semantic/lifetime.js +517 -0
  295. package/src/semantic/provenance.js +412 -19
  296. package/src/semantic/scalars.js +17 -0
  297. package/src/semantic/stdlib.js +921 -0
  298. package/src/semantic/types.js +810 -14
  299. package/src/semantic/validate.js +2934 -209
  300. package/src/stdlib-facades.js +1211 -0
  301. package/src/stdlib-negotiation.js +446 -0
  302. package/src/stdlib-providers.js +377 -0
  303. package/src/toolchains.js +16 -3
@@ -0,0 +1,750 @@
1
+ // @ts-check
2
+
3
+ import {missingType, unsupportedSyntax} from "../diagnostic.js"
4
+ import {recordTypeSubstitutions, substituteValueType, typeContainsAnyVariable} from "../semantic/generics.js"
5
+ import {locationFromOffsets} from "../semantic/location.js"
6
+ import {parserRangeFor, setParserRanges} from "../semantic/provenance.js"
7
+ import {sourceScalarType} from "./scalars.js"
8
+
9
+ /**
10
+ * Resolves the value presented to list iteration after canonical optional unwrap.
11
+ * Semantic validation remains responsible for requiring the matching presence proof.
12
+ * @param {import("../semantic/types.js").SemanticFunctionReturnType | import("../semantic/types.js").ErrorType | undefined} type - Parser-resolved operand type.
13
+ * @returns {import("../semantic/types.js").SemanticFunctionReturnType | import("../semantic/types.js").ErrorType | undefined} Iterated value type.
14
+ */
15
+ export function iterationOperandType(type) {
16
+ return type?.kind == "OptionalType" ? type.valueType : type
17
+ }
18
+
19
+ /**
20
+ * Copies a resolved list element type for one parser-owned iteration binding.
21
+ * The binding location is its own deterministic derived type anchor.
22
+ * @param {import("../semantic/types.js").SemanticValueType} type - Resolved element type.
23
+ * @param {import("../semantic/types.js").SourceLocation} location - Binding token location.
24
+ * @returns {import("../semantic/types.js").SemanticValueType} Detached semantic type.
25
+ */
26
+ export function iterationBindingType(type, location) {
27
+ if (type.kind == "TypeReference") {
28
+ const copied = {kind: /** @type {const} */ ("TypeReference"), name: type.name}
29
+
30
+ setParserRanges(copied, {type: location})
31
+ return copied
32
+ }
33
+ if (type.kind == "TypeVariableReference") return typeVariable(type.parameterId, location)
34
+ if (type.kind == "ListType") {
35
+ return listType(iterationBindingType(type.elementType, location), location, location)
36
+ }
37
+ if (type.kind == "MapType" || type.kind == "OrderedMapType") {
38
+ const keyType = iterationBindingType(type.keyType, location)
39
+
40
+ return type.kind == "OrderedMapType" ? orderedMapType(
41
+ /** @type {import("../semantic/types.js").TypeReference} */ (keyType),
42
+ iterationBindingType(type.valueType, location),
43
+ location,
44
+ location,
45
+ location
46
+ ) : mapType(
47
+ /** @type {import("../semantic/types.js").TypeReference} */ (keyType),
48
+ iterationBindingType(type.valueType, location),
49
+ location,
50
+ location,
51
+ location
52
+ )
53
+ }
54
+
55
+ if (type.kind == "RecordType") return recordType(type.declarationId, location,
56
+ type.arguments?.map((argument) => iterationBindingType(argument, location)))
57
+ if (type.kind == "ReferenceType") return referenceType(type.declarationId, location)
58
+ if (type.kind == "OwnedResourceType") return ownedResourceType(type.resourceId, location)
59
+ if (type.kind == "OwnedReferenceType") return ownedReferenceType(type.declarationId, location)
60
+
61
+ return optionalType(iterationBindingType(type.valueType, location), location, location)
62
+ }
63
+
64
+ /**
65
+ * Builds one recursive semantic list type with parser-owned constituent ranges.
66
+ * @param {import("../semantic/types.js").SemanticValueType} elementType - Element type.
67
+ * @param {import("../semantic/types.js").SourceLocation} location - Complete type-expression range.
68
+ * @param {import("../semantic/types.js").SourceLocation} elementLocation - Element type-expression range.
69
+ * @returns {import("../semantic/types.js").ListType} List type.
70
+ */
71
+ export function listType(elementType, location, elementLocation) {
72
+ const type = {elementType, kind: /** @type {const} */ ("ListType")}
73
+
74
+ setParserRanges(type, {elementType: elementLocation, type: location})
75
+ return type
76
+ }
77
+
78
+ /**
79
+ * Builds one recursive semantic map type with parser-owned constituent ranges.
80
+ * @param {import("../semantic/types.js").TypeReference} keyType - Key type.
81
+ * @param {import("../semantic/types.js").SemanticValueType} valueType - Value type.
82
+ * @param {import("../semantic/types.js").SourceLocation} location - Complete type-expression range.
83
+ * @param {import("../semantic/types.js").SourceLocation} keyLocation - Key type-expression range.
84
+ * @param {import("../semantic/types.js").SourceLocation} valueLocation - Value type-expression range.
85
+ * @returns {import("../semantic/types.js").MapType} Map type.
86
+ */
87
+ export function mapType(keyType, valueType, location, keyLocation, valueLocation) {
88
+ const type = {keyType, kind: /** @type {const} */ ("MapType"), valueType}
89
+
90
+ setParserRanges(type, {keyType: keyLocation, type: location, valueType: valueLocation})
91
+ return type
92
+ }
93
+
94
+ /**
95
+ * Builds one insertion-ordered recursive semantic map type.
96
+ * @param {import("../semantic/types.js").TypeReference} keyType - Key type.
97
+ * @param {import("../semantic/types.js").SemanticValueType} valueType - Value type.
98
+ * @param {import("../semantic/types.js").SourceLocation} location - Complete type range.
99
+ * @param {import("../semantic/types.js").SourceLocation} keyLocation - Key range.
100
+ * @param {import("../semantic/types.js").SourceLocation} valueLocation - Value range.
101
+ * @returns {import("../semantic/types.js").OrderedMapType} Ordered-map type.
102
+ */
103
+ export function orderedMapType(keyType, valueType, location, keyLocation, valueLocation) {
104
+ const type = {keyType, kind: /** @type {const} */ ("OrderedMapType"), order: /** @type {const} */ ("insertion"), valueType}
105
+
106
+ setParserRanges(type, {keyType: keyLocation, type: location, valueType: valueLocation})
107
+ return type
108
+ }
109
+
110
+ /**
111
+ * Promotes one parser-proven ordinary map annotation into the distinct ordered-map capability.
112
+ * @param {import("../semantic/types.js").MapType} type - Parsed homogeneous map type.
113
+ * @param {import("../semantic/types.js").SourceLocation} fallbackLocation - Owning declaration location.
114
+ * @returns {import("../semantic/types.js").OrderedMapType} Ordered counterpart with the same parser ranges.
115
+ */
116
+ export function orderedMapTypeFromMap(type, fallbackLocation) {
117
+ const ranges = type.sourceProvenance?.ranges
118
+
119
+ return orderedMapType(
120
+ type.keyType,
121
+ type.valueType,
122
+ ranges?.type ?? fallbackLocation,
123
+ ranges?.keyType ?? fallbackLocation,
124
+ ranges?.valueType ?? fallbackLocation
125
+ )
126
+ }
127
+
128
+ /**
129
+ * Builds one recursive semantic optional type with parser-owned constituent ranges.
130
+ * @param {import("../semantic/types.js").SemanticValueType} valueType - Present-value type.
131
+ * @param {import("../semantic/types.js").SourceLocation} location - Complete type-expression range.
132
+ * @param {import("../semantic/types.js").SourceLocation} valueLocation - Present-value type range.
133
+ * @returns {import("../semantic/types.js").OptionalType} Optional type.
134
+ */
135
+ export function optionalType(valueType, location, valueLocation) {
136
+ const type = {kind: /** @type {const} */ ("OptionalType"), valueType}
137
+
138
+ setParserRanges(type, {type: location, valueType: valueLocation})
139
+ return type
140
+ }
141
+
142
+ /**
143
+ * Builds one nominal semantic record type with a parser-owned name range.
144
+ * @param {string} declarationId - Stable declaration identity.
145
+ * @param {import("../semantic/types.js").SourceLocation} location - Record type-name range.
146
+ * @param {import("../semantic/types.js").SemanticValueType[]} [arguments_] - Exact generic arguments.
147
+ * @returns {import("../semantic/types.js").RecordType} Record type.
148
+ */
149
+ export function recordType(declarationId, location, arguments_) {
150
+ const type = {declarationId, kind: /** @type {const} */ ("RecordType"), ...(arguments_ ? {arguments: arguments_} : {})}
151
+
152
+ setParserRanges(type, {type: location})
153
+ return type
154
+ }
155
+
156
+ /**
157
+ * Builds one nominal reference-class type with a parser-owned name range.
158
+ * @param {string} declarationId - Stable class identity.
159
+ * @param {import("../semantic/types.js").SourceLocation} location - Class type-name range.
160
+ * @returns {import("../semantic/types.js").ReferenceType} Reference type.
161
+ */
162
+ export function referenceType(declarationId, location) {
163
+ const type = {declarationId, kind: /** @type {const} */ ("ReferenceType")}
164
+
165
+ setParserRanges(type, {type: location})
166
+ return type
167
+ }
168
+
169
+ /**
170
+ * Builds one compiler-owned resource type with a parser-owned name range.
171
+ * @param {string} resourceId - Stable capability resource identity.
172
+ * @param {import("../semantic/types.js").SourceLocation} location - Resource type-name range.
173
+ * @returns {import("../semantic/types.js").OwnedResourceType} Owned resource type.
174
+ */
175
+ export function ownedResourceType(resourceId, location) {
176
+ const type = {kind: /** @type {const} */ ("OwnedResourceType"), resourceId}
177
+ setParserRanges(type, {type: location})
178
+ return type
179
+ }
180
+
181
+ /**
182
+ * Builds one linear owned-reference type with a parser-owned name range.
183
+ * @param {string} declarationId - Stable owned class identity.
184
+ * @param {import("../semantic/types.js").SourceLocation} location - Class type-name range.
185
+ * @returns {import("../semantic/types.js").OwnedReferenceType} Owned reference type.
186
+ */
187
+ export function ownedReferenceType(declarationId, location) {
188
+ const type = {declarationId, kind: /** @type {const} */ ("OwnedReferenceType")}
189
+ setParserRanges(type, {type: location})
190
+ return type
191
+ }
192
+
193
+ /**
194
+ * Builds parser-context signatures for compiler-authorized operations without exposing a source declaration.
195
+ * @param {readonly import("../semantic/types.js").EffectCapabilityDeclaration[]} capabilities - Authorized declarations.
196
+ * @param {import("../semantic/types.js").SourceLocation} location - Synthetic parser-context anchor.
197
+ * @returns {Map<string, {location: import("../semantic/types.js").SourceLocation, nameLocation: import("../semantic/types.js").SourceLocation, name: string, parameters: import("../semantic/types.js").Parameter[], returnType: import("../semantic/types.js").SemanticFunctionReturnType, typeParameters?: import("../semantic/types.js").TypeParameter[]}>} Signatures by source spelling.
198
+ */
199
+ export function capabilityFunctionSignatures(capabilities, location) {
200
+ return new Map(capabilities.flatMap(({operations}) => operations).map((operation) => [operation.name, {
201
+ location,
202
+ name: operation.name,
203
+ nameLocation: location,
204
+ parameters: operation.parameters.map((parameter) => ({kind: /** @type {const} */ ("Parameter"), location, ...parameter})),
205
+ returnType: operation.returnType
206
+ }]))
207
+ }
208
+
209
+ /**
210
+ * Builds one declaration-scoped type-variable reference.
211
+ * @param {string} parameterId - Stable type-parameter identity.
212
+ * @param {import("../semantic/types.js").SourceLocation} location - Exact reference range.
213
+ * @returns {import("../semantic/types.js").TypeVariableReference} Type-variable reference.
214
+ */
215
+ export function typeVariable(parameterId, location) {
216
+ const type = {kind: /** @type {const} */ ("TypeVariableReference"), location, parameterId}
217
+
218
+ setParserRanges(type, {type: location})
219
+ return type
220
+ }
221
+
222
+ /**
223
+ * Compares semantic type expressions while ignoring parser-owned locations.
224
+ * @param {import("../semantic/types.js").SemanticValueType} left - Left type.
225
+ * @param {import("../semantic/types.js").SemanticValueType} right - Right type.
226
+ * @returns {boolean} Whether the semantic structures are identical.
227
+ */
228
+ export function sameValueType(left, right) {
229
+ if (left.kind != right.kind) return false
230
+ if (left.kind == "TypeReference" && right.kind == "TypeReference") return left.name == right.name
231
+ if (left.kind == "TypeVariableReference" && right.kind == "TypeVariableReference") return left.parameterId == right.parameterId
232
+ if (left.kind == "ListType" && right.kind == "ListType") return sameValueType(left.elementType, right.elementType)
233
+ if (left.kind == "OptionalType" && right.kind == "OptionalType") return sameValueType(left.valueType, right.valueType)
234
+ if ((left.kind == "MapType" && right.kind == "MapType") ||
235
+ (left.kind == "OrderedMapType" && right.kind == "OrderedMapType")) {
236
+ return sameValueType(left.keyType, right.keyType) && sameValueType(left.valueType, right.valueType)
237
+ }
238
+ if (left.kind == "RecordType" && right.kind == "RecordType") {
239
+ const leftArguments = left.arguments ?? []
240
+ const rightArguments = right.arguments ?? []
241
+
242
+ return left.declarationId == right.declarationId && leftArguments.length == rightArguments.length &&
243
+ leftArguments.every((argument, index) => sameValueType(argument, rightArguments[index]))
244
+ }
245
+ if (left.kind == "ReferenceType" && right.kind == "ReferenceType") return left.declarationId == right.declarationId
246
+ if (left.kind == "OwnedResourceType" && right.kind == "OwnedResourceType") return left.resourceId == right.resourceId
247
+ if (left.kind == "OwnedReferenceType" && right.kind == "OwnedReferenceType") return left.declarationId == right.declarationId
248
+
249
+ return false
250
+ }
251
+
252
+ /**
253
+ * Resolves one generic record field against a complete application for parser
254
+ * contextual conversion. Invalid/raw applications remain unchanged so the
255
+ * semantic validator owns their stable diagnostic.
256
+ * @param {import("../semantic/types.js").RecordDeclaration} declaration - Resolved record declaration.
257
+ * @param {import("../semantic/types.js").SemanticValueType[] | undefined} arguments_ - Parsed application arguments.
258
+ * @param {number} index - Constructor field index.
259
+ * @returns {import("../semantic/types.js").SemanticValueType | undefined} Closed field type when available.
260
+ */
261
+ export function instantiatedRecordFieldType(declaration, arguments_, index) {
262
+ const field = declaration.fields[index]
263
+ const parameters = declaration.typeParameters ?? []
264
+
265
+ if (!field || parameters.length == 0 || !arguments_ || arguments_.length != parameters.length) return field?.type
266
+ const application = /** @type {import("../semantic/types.js").RecordType} */ ({
267
+ arguments: arguments_,
268
+ declarationId: /** @type {string} */ (declaration.id),
269
+ kind: "RecordType"
270
+ })
271
+
272
+ return substituteValueType(field.type, recordTypeSubstitutions(application, declaration))
273
+ }
274
+
275
+ /**
276
+ * Applies parser-known generic-call argument evidence to its declared return.
277
+ * An unresolved variable remains open: this is conservative context discovery
278
+ * only, while semantic validation still performs authoritative inference.
279
+ * @param {{parameters: import("../semantic/types.js").Parameter[], returnType: import("../semantic/types.js").SemanticFunctionReturnType}} signature - Declared signature.
280
+ * @param {(import("../semantic/types.js").SemanticFunctionReturnType | import("../semantic/types.js").ErrorType | undefined)[]} arguments_ - Parser-known argument types.
281
+ * @returns {import("../semantic/types.js").SemanticFunctionReturnType | undefined} Known result with available substitutions.
282
+ */
283
+ export function knownCallReturnType(signature, arguments_) {
284
+ if (signature.returnType.kind == "TypeReference" && signature.returnType.name == "void") return signature.returnType
285
+ const substitutions = knownCallSubstitutions(signature, arguments_)
286
+
287
+ return substitutions ? substituteValueType(signature.returnType, substitutions) : undefined
288
+ }
289
+
290
+ /**
291
+ * Applies conservative parser-known call evidence to every parameter context.
292
+ * Unresolved variables remain open for the language frontend to handle only in
293
+ * a matching lexical type-parameter scope.
294
+ * @param {{parameters: import("../semantic/types.js").Parameter[]}} signature - Declared signature.
295
+ * @param {(import("../semantic/types.js").SemanticFunctionReturnType | import("../semantic/types.js").ErrorType | undefined)[]} arguments_ - Parser-known argument types.
296
+ * @returns {import("../semantic/types.js").SemanticValueType[] | undefined} Substituted parameter contexts.
297
+ */
298
+ export function knownCallParameterTypes(signature, arguments_) {
299
+ const substitutions = knownCallSubstitutions(signature, arguments_)
300
+
301
+ return substitutions
302
+ ? signature.parameters.map((parameter) => substituteValueType(parameter.type, substitutions))
303
+ : undefined
304
+ }
305
+
306
+ /**
307
+ * Collects conservative parser-known substitutions once for call context and
308
+ * result classification. Semantic validation remains authoritative.
309
+ * @param {{parameters: import("../semantic/types.js").Parameter[]}} signature - Declared signature.
310
+ * @param {(import("../semantic/types.js").SemanticFunctionReturnType | import("../semantic/types.js").ErrorType | undefined)[]} arguments_ - Parser-known argument types.
311
+ * @returns {Map<string, import("../semantic/types.js").SemanticValueType> | undefined} Compatible substitutions.
312
+ */
313
+ function knownCallSubstitutions(signature, arguments_) {
314
+ /** @type {Map<string, import("../semantic/types.js").SemanticValueType>} */
315
+ const substitutions = new Map()
316
+
317
+ for (let index = 0; index < signature.parameters.length; index += 1) {
318
+ const actual = arguments_[index]
319
+
320
+ if (actual && actual.kind != "ErrorType" && !(actual.kind == "TypeReference" && actual.name == "void") &&
321
+ !collectKnownSubstitutions(signature.parameters[index].type,
322
+ /** @type {import("../semantic/types.js").SemanticValueType} */ (actual), substitutions)) {
323
+ return undefined
324
+ }
325
+ }
326
+
327
+ return substitutions
328
+ }
329
+
330
+ /**
331
+ * Preserves an optional binding when a generic formal needs its wrapped type as
332
+ * argument-only inference evidence. The semantic validator remains the sole
333
+ * authority for unification and presence-proof checks.
334
+ * @param {{parameters: import("../semantic/types.js").Parameter[], typeParameters?: import("../semantic/types.js").TypeParameter[]} | undefined} signature - Known direct-call signature.
335
+ * @param {number} index - Argument index.
336
+ * @returns {boolean} Whether frontend conversion must retain optionality.
337
+ */
338
+ export function preservesGenericOptionalEvidence(signature, index) {
339
+ const formal = signature?.parameters[index]?.type
340
+
341
+ return Boolean(signature?.typeParameters?.length && formal && typeContainsAnyVariable(formal))
342
+ }
343
+
344
+ /**
345
+ * Conservatively collects structurally matching parser-known substitutions.
346
+ * @param {import("../semantic/types.js").SemanticValueType} formal - Open formal type.
347
+ * @param {import("../semantic/types.js").SemanticValueType} actual - Known argument type.
348
+ * @param {Map<string, import("../semantic/types.js").SemanticValueType>} substitutions - Collected substitutions.
349
+ * @returns {boolean} Whether the known structures remain compatible.
350
+ */
351
+ function collectKnownSubstitutions(formal, actual, substitutions) {
352
+ if (formal.kind == "TypeVariableReference") {
353
+ const prior = substitutions.get(formal.parameterId)
354
+
355
+ if (prior) return sameValueType(prior, actual)
356
+ substitutions.set(formal.parameterId, actual)
357
+ return true
358
+ }
359
+ if (formal.kind == "OptionalType") {
360
+ return collectKnownSubstitutions(formal.valueType,
361
+ actual.kind == "OptionalType" ? actual.valueType : actual, substitutions)
362
+ }
363
+ if (formal.kind != actual.kind) return false
364
+ if (formal.kind == "TypeReference") return sameValueType(formal, actual)
365
+ if (formal.kind == "ReferenceType" && actual.kind == "ReferenceType") return sameValueType(formal, actual)
366
+ if (formal.kind == "OwnedResourceType" && actual.kind == "OwnedResourceType") return sameValueType(formal, actual)
367
+ if (formal.kind == "OwnedReferenceType" && actual.kind == "OwnedReferenceType") return sameValueType(formal, actual)
368
+ if (formal.kind == "RecordType" && actual.kind == "RecordType") {
369
+ if (formal.declarationId != actual.declarationId || (formal.arguments?.length ?? 0) != (actual.arguments?.length ?? 0)) return false
370
+
371
+ return (formal.arguments ?? []).every((argument, index) => collectKnownSubstitutions(
372
+ argument, /** @type {import("../semantic/types.js").SemanticValueType} */ (actual.arguments?.[index]), substitutions
373
+ ))
374
+ }
375
+ if (formal.kind == "ListType" && actual.kind == "ListType") {
376
+ return collectKnownSubstitutions(formal.elementType, actual.elementType, substitutions)
377
+ }
378
+ if ((formal.kind == "MapType" && actual.kind == "MapType") ||
379
+ (formal.kind == "OrderedMapType" && actual.kind == "OrderedMapType")) {
380
+ return collectKnownSubstitutions(formal.keyType, actual.keyType, substitutions) &&
381
+ collectKnownSubstitutions(formal.valueType, actual.valueType, substitutions)
382
+ }
383
+
384
+ return false
385
+ }
386
+
387
+ /**
388
+ * Converts one parser/comment-parser-owned bounded type expression. This parser
389
+ * recognizes only Task 006's concrete scalar/list/map grammar; it never scans
390
+ * source outside the already-associated type token.
391
+ * @param {object} input - Documented type input.
392
+ * @param {"javascript" | "php" | "ruby"} input.language - Comment profile.
393
+ * @param {import("../semantic/types.js").SourceLocation} input.location - Exact type token range.
394
+ * @param {import("../semantic/types.js").SourceLocation} input.ownerLocation - Owning declaration range.
395
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} [input.records] - Available nominal declarations by source name.
396
+ * @param {Map<string, import("../semantic/types.js").TypeParameter>} [input.typeParameters] - Declaration-scoped parameters by name.
397
+ * @param {string} input.source - Complete parser input for exact subranges.
398
+ * @param {string | undefined} input.sourceType - Exact comment-parser/Prism-owned type token.
399
+ * @param {string} input.subject - Diagnostic subject.
400
+ * @returns {import("../semantic/types.js").SemanticValueType} Semantic value type.
401
+ */
402
+ export function documentedValueType({language, location, ownerLocation, records = new Map(), source, sourceType, subject, typeParameters = new Map()}) {
403
+ if (!sourceType) return missingType(language, subject, ownerLocation)
404
+
405
+ if (language == "php" && sourceType.startsWith("?")) {
406
+ const valueText = sourceType.slice(1)
407
+ const valueLocation = locationFromOffsets(
408
+ location.filename,
409
+ source,
410
+ location.start.offset + 1,
411
+ location.end.offset
412
+ )
413
+
414
+ return optionalType(
415
+ documentedValueType({language, location: valueLocation, ownerLocation, records, source, sourceType: valueText, subject, typeParameters}),
416
+ location,
417
+ valueLocation
418
+ )
419
+ }
420
+ if (language == "php" && sourceType.includes("|")) {
421
+ return unsupportedSyntax(language, "arbitrary union type", location)
422
+ }
423
+ if (language == "javascript" && sourceType.endsWith("|null") && sourceType.indexOf("|") == sourceType.length - "|null".length) {
424
+ const valueText = sourceType.slice(0, -"|null".length)
425
+ const valueLocation = locationFromOffsets(
426
+ location.filename,
427
+ source,
428
+ location.start.offset,
429
+ location.start.offset + valueText.length
430
+ )
431
+
432
+ return optionalType(
433
+ documentedValueType({language, location: valueLocation, ownerLocation, records, source, sourceType: valueText, subject, typeParameters}),
434
+ location,
435
+ valueLocation
436
+ )
437
+ }
438
+ if (language == "javascript" && sourceType.includes("|") &&
439
+ !sourceType.startsWith("ReadonlyArray") && !sourceType.startsWith("ReadonlyMap") &&
440
+ !records.has(sourceType.slice(0, sourceType.indexOf("<") < 0 ? sourceType.length : sourceType.indexOf("<")))) {
441
+ return unsupportedSyntax(language, "arbitrary union type", location)
442
+ }
443
+
444
+ const scalar = sourceScalarType(language, sourceType, location)
445
+
446
+ if (scalar) return scalar
447
+ const unwrappedName = language == "ruby" && sourceType.startsWith("[") && sourceType.endsWith("]")
448
+ ? sourceType.slice(1, -1)
449
+ : sourceType
450
+ const directRecord = records.get(unwrappedName)
451
+
452
+ if (directRecord?.id) return directRecord.kind == "ClassDeclaration"
453
+ ? referenceType(directRecord.id, location)
454
+ : directRecord.kind == "EffectResourceDeclaration"
455
+ ? ownedResourceType(directRecord.id, location)
456
+ : recordType(directRecord.id, location)
457
+ const directTypeParameter = typeParameters.get(unwrappedName)
458
+
459
+ if (directTypeParameter?.id) return typeVariable(directTypeParameter.id, location)
460
+ const collectionPrefixes = language == "ruby" ? ["[Array", "[Hash", "[Integer?", "[bool?", "[String?"] :
461
+ language == "php" ? ["list", "array"] : ["ReadonlyArray", "ReadonlyMap"]
462
+ const optionalRecord = language == "ruby" && sourceType.startsWith("[") && sourceType.endsWith("?]") &&
463
+ records.has(sourceType.slice(1, -2))
464
+
465
+ const possibleName = unwrappedName.slice(0, unwrappedName.search(/[<[?]/u) < 0 ? unwrappedName.length : unwrappedName.search(/[<[?]/u))
466
+
467
+ if (!optionalRecord && !collectionPrefixes.some((prefix) => sourceType.startsWith(prefix)) &&
468
+ !records.has(possibleName) && !typeParameters.has(possibleName)) {
469
+ return missingType(language, subject, ownerLocation)
470
+ }
471
+
472
+ const parser = new DocumentedTypeParser(language, sourceType, location, source, records, typeParameters)
473
+ const type = parser.parse()
474
+
475
+ if (!parser.atEnd()) return unsupportedSyntax(language, "unsupported collection type", parser.remainingLocation())
476
+
477
+ return type
478
+ }
479
+
480
+ class DocumentedTypeParser {
481
+ /**
482
+ * Creates a bounded parser over one parser/comment-parser-owned token.
483
+ * @param {"javascript" | "php" | "ruby"} language - Exact comment profile.
484
+ * @param {string} text - Parser-owned type text.
485
+ * @param {import("../semantic/types.js").SourceLocation} location - Whole token location.
486
+ * @param {string} source - Complete source.
487
+ * @param {Map<string, import("../semantic/types.js").RecordDeclaration | import("../semantic/types.js").ClassDeclaration | import("../semantic/types.js").EffectResourceDeclaration>} records - Available nominal declarations.
488
+ * @param {Map<string, import("../semantic/types.js").TypeParameter>} typeParameters - Declaration-scoped parameters.
489
+ */
490
+ constructor(language, text, location, source, records, typeParameters) {
491
+ this.language = language
492
+ this.text = text
493
+ this.location = location
494
+ this.source = source
495
+ this.records = records
496
+ this.typeParameters = typeParameters
497
+ this.offset = 0
498
+ }
499
+
500
+ /**
501
+ * Parses the complete documented type.
502
+ * @returns {import("../semantic/types.js").SemanticValueType} Parsed type.
503
+ */
504
+ parse() {
505
+ this.skipWhitespace()
506
+ if (this.language == "ruby") {
507
+ if (!this.consume("[")) return this.failure()
508
+ const type = this.parseNamedType()
509
+
510
+ this.skipWhitespace()
511
+ if (!this.consume("]")) return this.failure()
512
+ this.skipWhitespace()
513
+ return type
514
+ }
515
+
516
+ const type = this.parseNamedType()
517
+
518
+ this.skipWhitespace()
519
+ return type
520
+ }
521
+
522
+ /**
523
+ * Parses one nested type expression.
524
+ * @returns {import("../semantic/types.js").SemanticValueType} Parsed nested type.
525
+ */
526
+ parseNamedType() {
527
+ this.skipWhitespace()
528
+ const start = this.offset
529
+
530
+ if (this.language == "php" && this.consume("?")) {
531
+ const valueStart = this.offset
532
+ const valueType = this.parseNamedType()
533
+
534
+ return optionalType(
535
+ valueType,
536
+ this.range(start, this.offset),
537
+ this.typeRange(valueType, valueStart, this.offset)
538
+ )
539
+ }
540
+
541
+ while (isTypeIdentifierCharacter(this.text[this.offset]) || this.language == "ruby" &&
542
+ this.text[this.offset] == ":" && this.text[this.offset + 1] == ":" &&
543
+ isTypeIdentifierCharacter(this.text[this.offset + 2])) {
544
+ this.offset += this.text[this.offset] == ":" ? 2 : 1
545
+ }
546
+ const nameEnd = this.offset
547
+ const name = this.text.slice(start, nameEnd)
548
+
549
+ if (!name) return this.failure()
550
+ const scalarSpelling = this.language == "ruby" ? `[${name}]` : name
551
+ const scalar = sourceScalarType(this.language, scalarSpelling, this.range(start, nameEnd))
552
+
553
+ this.skipWhitespace()
554
+ if (scalar && this.text[this.offset] != "<" && this.text[this.offset] != "[") {
555
+ if (this.language == "ruby" && this.consume("?")) {
556
+ return optionalType(scalar, this.range(start, this.offset), this.typeRange(scalar, start, nameEnd))
557
+ }
558
+ if (this.language == "javascript" && this.consume("|null")) {
559
+ return optionalType(scalar, this.range(start, this.offset), this.typeRange(scalar, start, nameEnd))
560
+ }
561
+
562
+ return scalar
563
+ }
564
+ const record = this.records.get(name)
565
+ const typeParameter = this.typeParameters.get(name)
566
+
567
+ if (typeParameter?.id && this.text[this.offset] != "<" && this.text[this.offset] != "[") {
568
+ const type = typeVariable(typeParameter.id, this.range(start, nameEnd))
569
+
570
+ if (this.language == "ruby" && this.consume("?")) {
571
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, nameEnd))
572
+ }
573
+ if (this.language == "javascript" && this.consume("|null")) {
574
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, nameEnd))
575
+ }
576
+
577
+ return type
578
+ }
579
+
580
+ if (record?.id && this.text[this.offset] != "<" && this.text[this.offset] != "[") {
581
+ const type = record.kind == "ClassDeclaration"
582
+ ? referenceType(record.id, this.range(start, nameEnd))
583
+ : record.kind == "EffectResourceDeclaration"
584
+ ? ownedResourceType(record.id, this.range(start, nameEnd))
585
+ : recordType(record.id, this.range(start, nameEnd))
586
+
587
+ if (this.language == "ruby" && this.consume("?")) {
588
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, nameEnd))
589
+ }
590
+ if (this.language == "javascript" && this.consume("|null")) {
591
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, nameEnd))
592
+ }
593
+
594
+ return type
595
+ }
596
+
597
+ const listName = this.language == "ruby" ? "Array" : this.language == "php" ? "list" : "ReadonlyArray"
598
+ const mapName = this.language == "ruby" ? "Hash" : this.language == "php" ? "array" : "ReadonlyMap"
599
+ const opening = this.language == "ruby" ? "[" : "<"
600
+ const closing = this.language == "ruby" ? "]" : ">"
601
+
602
+ if (name != listName && name != mapName && !record || !this.consume(opening)) return this.failure()
603
+ const first = this.parseNamedType()
604
+ const firstEnd = this.offset
605
+
606
+ this.skipWhitespace()
607
+ if (record?.id) {
608
+ const arguments_ = [first]
609
+
610
+ while (this.consume(",")) arguments_.push(this.parseNamedType())
611
+ if (!this.consume(closing)) return this.failure()
612
+
613
+ const applicationEnd = this.offset
614
+ const type = recordType(record.id, this.range(start, nameEnd), arguments_)
615
+
616
+ if (this.language == "ruby" && this.consume("?")) {
617
+ return optionalType(type, this.range(start, this.offset), this.range(start, applicationEnd))
618
+ }
619
+ if (this.language == "javascript" && this.consume("|null")) {
620
+ return optionalType(type, this.range(start, this.offset), this.range(start, applicationEnd))
621
+ }
622
+
623
+ return type
624
+ }
625
+ if (name == listName) {
626
+ if (!this.consume(closing)) return this.failure()
627
+ const type = listType(first, this.range(start, this.offset), this.typeRange(first, start, firstEnd))
628
+
629
+ if (this.language == "ruby" && this.consume("?")) {
630
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, firstEnd))
631
+ }
632
+ if (this.language == "javascript" && this.consume("|null")) {
633
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, firstEnd))
634
+ }
635
+
636
+ return type
637
+ }
638
+ if (!this.consume(",")) return this.failure()
639
+ const second = this.parseNamedType()
640
+ const secondEnd = this.offset
641
+
642
+ this.skipWhitespace()
643
+ if (!this.consume(closing)) return this.failure()
644
+ if (first.kind != "TypeReference") {
645
+ return unsupportedSyntax(this.language, "map key type other than string", this.typeRange(first, start, firstEnd))
646
+ }
647
+
648
+ const type = mapType(
649
+ first,
650
+ second,
651
+ this.range(start, this.offset),
652
+ this.typeRange(first, start, firstEnd),
653
+ this.typeRange(second, firstEnd, secondEnd)
654
+ )
655
+
656
+ if (this.language == "ruby" && this.consume("?")) {
657
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, secondEnd))
658
+ }
659
+ if (this.language == "javascript" && this.consume("|null")) {
660
+ return optionalType(type, this.range(start, this.offset), this.typeRange(type, start, secondEnd))
661
+ }
662
+
663
+ return type
664
+ }
665
+
666
+ /**
667
+ * Reports whether the complete token was consumed.
668
+ * @returns {boolean} Whether the whole token was consumed.
669
+ */
670
+ atEnd() {
671
+ return this.offset == this.text.length
672
+ }
673
+
674
+ /**
675
+ * Locates the remaining invalid suffix.
676
+ * @returns {import("../semantic/types.js").SourceLocation} Remaining invalid range.
677
+ */
678
+ remainingLocation() {
679
+ return this.range(this.offset, Math.max(this.offset + 1, this.text.length))
680
+ }
681
+
682
+ /**
683
+ * Consumes one exact punctuation token.
684
+ * @param {string} token - Exact punctuation.
685
+ * @returns {boolean} Whether consumed.
686
+ */
687
+ consume(token) {
688
+ this.skipWhitespace()
689
+ if (!this.text.startsWith(token, this.offset)) return false
690
+ this.offset += token.length
691
+ return true
692
+ }
693
+
694
+ /**
695
+ * Skips bounded type-expression whitespace.
696
+ * @returns {void}
697
+ */
698
+ skipWhitespace() {
699
+ while ([" ", "\t", "\r", "\n"].includes(this.text[this.offset])) this.offset++
700
+ }
701
+
702
+ /**
703
+ * Converts relative offsets into parser-owned source coordinates.
704
+ * @param {number} start - Relative start.
705
+ * @param {number} end - Relative end.
706
+ * @returns {import("../semantic/types.js").SourceLocation} Exact source range.
707
+ */
708
+ range(start, end) {
709
+ return locationFromOffsets(
710
+ this.location.filename,
711
+ this.source,
712
+ this.location.start.offset + start,
713
+ this.location.start.offset + Math.min(end, this.text.length)
714
+ )
715
+ }
716
+
717
+ /**
718
+ * Returns a nested type's parser range.
719
+ * @param {import("../semantic/types.js").SemanticValueType} type - Parsed type.
720
+ * @param {number} start - Fallback start.
721
+ * @param {number} end - Fallback end.
722
+ * @returns {import("../semantic/types.js").SourceLocation} Exact type range.
723
+ */
724
+ typeRange(type, start, end) {
725
+ return parserRangeFor(type, "type") ?? this.range(start, end)
726
+ }
727
+
728
+ /**
729
+ * Reports a bounded type-parser failure.
730
+ * @returns {import("../semantic/types.js").SemanticValueType} Unreachable semantic type.
731
+ */
732
+ failure() {
733
+ return unsupportedSyntax(
734
+ this.language,
735
+ this.text.slice(this.offset).includes("|") ? "arbitrary union type" : "unsupported collection type",
736
+ this.remainingLocation()
737
+ )
738
+ }
739
+ }
740
+
741
+ /**
742
+ * Checks the bounded identifier alphabet.
743
+ * @param {string | undefined} character - Candidate source character.
744
+ * @returns {boolean} Whether it belongs to the bounded ASCII type grammar.
745
+ */
746
+ function isTypeIdentifierCharacter(character) {
747
+ return (character !== undefined && character >= "A" && character <= "Z") ||
748
+ (character !== undefined && character >= "a" && character <= "z") ||
749
+ (character !== undefined && character >= "0" && character <= "9") || character == "_"
750
+ }