semantifold 0.9.0 → 0.11.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 (198) hide show
  1. package/README.md +6 -3
  2. package/bin/semantifold.js +6 -0
  3. package/build/bin/semantifold.d.ts +3 -0
  4. package/build/bin/semantifold.d.ts.map +1 -0
  5. package/build/bin/semantifold.js +5 -0
  6. package/build/index.d.ts +8 -0
  7. package/build/index.d.ts.map +1 -1
  8. package/build/index.js +9 -1
  9. package/build/src/artifact-path.d.ts +16 -0
  10. package/build/src/artifact-path.d.ts.map +1 -1
  11. package/build/src/artifact-path.js +29 -3
  12. package/build/src/backends/c-check.d.ts +7 -0
  13. package/build/src/backends/c-check.d.ts.map +1 -0
  14. package/build/src/backends/c-check.js +65 -0
  15. package/build/src/backends/check-plan.d.ts +96 -0
  16. package/build/src/backends/check-plan.d.ts.map +1 -0
  17. package/build/src/backends/check-plan.js +135 -0
  18. package/build/src/backends/cpp-check.d.ts +7 -0
  19. package/build/src/backends/cpp-check.d.ts.map +1 -0
  20. package/build/src/backends/cpp-check.js +59 -0
  21. package/build/src/backends/csharp-check.d.ts +7 -0
  22. package/build/src/backends/csharp-check.d.ts.map +1 -0
  23. package/build/src/backends/csharp-check.js +125 -0
  24. package/build/src/backends/csharp.d.ts +1 -0
  25. package/build/src/backends/csharp.d.ts.map +1 -1
  26. package/build/src/backends/csharp.js +5 -4
  27. package/build/src/backends/dart-check.d.ts +7 -0
  28. package/build/src/backends/dart-check.d.ts.map +1 -0
  29. package/build/src/backends/dart-check.js +103 -0
  30. package/build/src/backends/dart.d.ts +2 -0
  31. package/build/src/backends/dart.d.ts.map +1 -1
  32. package/build/src/backends/dart.js +5 -5
  33. package/build/src/backends/go-check.d.ts +7 -0
  34. package/build/src/backends/go-check.d.ts.map +1 -0
  35. package/build/src/backends/go-check.js +77 -0
  36. package/build/src/backends/go.d.ts +1 -0
  37. package/build/src/backends/go.d.ts.map +1 -1
  38. package/build/src/backends/go.js +3 -3
  39. package/build/src/backends/java-check.d.ts +21 -0
  40. package/build/src/backends/java-check.d.ts.map +1 -0
  41. package/build/src/backends/java-check.js +73 -0
  42. package/build/src/backends/javascript-check.d.ts +7 -0
  43. package/build/src/backends/javascript-check.d.ts.map +1 -0
  44. package/build/src/backends/javascript-check.js +29 -0
  45. package/build/src/backends/kotlin-check.d.ts +7 -0
  46. package/build/src/backends/kotlin-check.d.ts.map +1 -0
  47. package/build/src/backends/kotlin-check.js +31 -0
  48. package/build/src/backends/kotlin.d.ts +1 -1
  49. package/build/src/backends/kotlin.js +2 -2
  50. package/build/src/backends/php-check.d.ts +7 -0
  51. package/build/src/backends/php-check.d.ts.map +1 -0
  52. package/build/src/backends/php-check.js +21 -0
  53. package/build/src/backends/program.d.ts +7 -0
  54. package/build/src/backends/program.d.ts.map +1 -1
  55. package/build/src/backends/program.js +16 -1
  56. package/build/src/backends/python-check.d.ts +7 -0
  57. package/build/src/backends/python-check.d.ts.map +1 -0
  58. package/build/src/backends/python-check.js +28 -0
  59. package/build/src/backends/ruby-check.d.ts +7 -0
  60. package/build/src/backends/ruby-check.d.ts.map +1 -0
  61. package/build/src/backends/ruby-check.js +21 -0
  62. package/build/src/backends/rust-check.d.ts +7 -0
  63. package/build/src/backends/rust-check.d.ts.map +1 -0
  64. package/build/src/backends/rust-check.js +65 -0
  65. package/build/src/backends/shared.d.ts.map +1 -1
  66. package/build/src/backends/shared.js +29 -1
  67. package/build/src/backends/swift-check.d.ts +7 -0
  68. package/build/src/backends/swift-check.d.ts.map +1 -0
  69. package/build/src/backends/swift-check.js +77 -0
  70. package/build/src/backends/typescript-check.d.ts +7 -0
  71. package/build/src/backends/typescript-check.d.ts.map +1 -0
  72. package/build/src/backends/typescript-check.js +33 -0
  73. package/build/src/backends/zig-check.d.ts +7 -0
  74. package/build/src/backends/zig-check.d.ts.map +1 -0
  75. package/build/src/backends/zig-check.js +70 -0
  76. package/build/src/diagnostic.d.ts +13 -1
  77. package/build/src/diagnostic.d.ts.map +1 -1
  78. package/build/src/diagnostic.js +14 -2
  79. package/build/src/frontends/java.d.ts.map +1 -1
  80. package/build/src/frontends/java.js +23 -1
  81. package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
  82. package/build/src/frontends/javascript-typescript.js +45 -4
  83. package/build/src/frontends/php.d.ts.map +1 -1
  84. package/build/src/frontends/php.js +54 -3
  85. package/build/src/frontends/program.d.ts +6 -0
  86. package/build/src/frontends/program.d.ts.map +1 -1
  87. package/build/src/frontends/program.js +9 -1
  88. package/build/src/frontends/ruby.d.ts.map +1 -1
  89. package/build/src/frontends/ruby.js +55 -5
  90. package/build/src/language-registry.d.ts +54 -0
  91. package/build/src/language-registry.d.ts.map +1 -1
  92. package/build/src/language-registry.js +124 -10
  93. package/build/src/project-build.d.ts +172 -0
  94. package/build/src/project-build.d.ts.map +1 -0
  95. package/build/src/project-build.js +320 -0
  96. package/build/src/project-cli.d.ts +40 -0
  97. package/build/src/project-cli.d.ts.map +1 -0
  98. package/build/src/project-cli.js +145 -0
  99. package/build/src/project-manifest.d.ts +148 -0
  100. package/build/src/project-manifest.d.ts.map +1 -0
  101. package/build/src/project-manifest.js +432 -0
  102. package/build/src/project-reporter.d.ts +81 -0
  103. package/build/src/project-reporter.d.ts.map +1 -0
  104. package/build/src/project-reporter.js +293 -0
  105. package/build/src/project-snapshot.d.ts +129 -0
  106. package/build/src/project-snapshot.d.ts.map +1 -0
  107. package/build/src/project-snapshot.js +362 -0
  108. package/build/src/project-watch-reporter.d.ts +125 -0
  109. package/build/src/project-watch-reporter.d.ts.map +1 -0
  110. package/build/src/project-watch-reporter.js +280 -0
  111. package/build/src/project-watch.d.ts +133 -0
  112. package/build/src/project-watch.d.ts.map +1 -0
  113. package/build/src/project-watch.js +839 -0
  114. package/build/src/publication.d.ts +69 -5
  115. package/build/src/publication.d.ts.map +1 -1
  116. package/build/src/publication.js +246 -57
  117. package/build/src/semantic/effects.js +3 -1
  118. package/build/src/semantic/provenance.d.ts.map +1 -1
  119. package/build/src/semantic/provenance.js +11 -1
  120. package/build/src/semantic/types.d.ts +355 -4
  121. package/build/src/semantic/types.d.ts.map +1 -1
  122. package/build/src/semantic/types.js +92 -3
  123. package/build/src/semantic/validate.js +18 -1
  124. package/build/src/subprocess.d.ts +8 -0
  125. package/build/src/subprocess.d.ts.map +1 -1
  126. package/build/src/subprocess.js +50 -9
  127. package/build/src/target-check.d.ts +52 -0
  128. package/build/src/target-check.d.ts.map +1 -0
  129. package/build/src/target-check.js +796 -0
  130. package/build/src/toolchains.d.ts.map +1 -1
  131. package/build/src/toolchains.js +3 -3
  132. package/docs/adr-expression-breadth.md +186 -0
  133. package/docs/architecture.md +3 -1
  134. package/docs/c.md +4 -0
  135. package/docs/cpp.md +4 -0
  136. package/docs/dart.md +4 -0
  137. package/docs/generated-artifact-publication.md +11 -8
  138. package/docs/kotlin.md +2 -2
  139. package/docs/language-support.md +40 -6
  140. package/docs/parser-qualification.md +1 -1
  141. package/docs/project-build-cli.md +147 -0
  142. package/docs/project-watch.md +60 -0
  143. package/docs/rust.md +4 -0
  144. package/docs/swift.md +2 -0
  145. package/docs/testing.md +70 -3
  146. package/docs/watch-build-pipeline.md +39 -23
  147. package/docs/zig.md +2 -0
  148. package/examples/jsdoc-java-watch/expected-output.txt +3 -0
  149. package/examples/jsdoc-java-watch/semantifold.json +23 -0
  150. package/examples/jsdoc-java-watch/src/main.js +21 -0
  151. package/index.js +8 -0
  152. package/package.json +6 -1
  153. package/src/artifact-path.js +31 -2
  154. package/src/backends/c-check.js +80 -0
  155. package/src/backends/check-plan.js +147 -0
  156. package/src/backends/cpp-check.js +73 -0
  157. package/src/backends/csharp-check.js +139 -0
  158. package/src/backends/csharp.js +4 -3
  159. package/src/backends/dart-check.js +117 -0
  160. package/src/backends/dart.js +4 -4
  161. package/src/backends/go-check.js +89 -0
  162. package/src/backends/go.js +2 -2
  163. package/src/backends/java-check.js +77 -0
  164. package/src/backends/javascript-check.js +33 -0
  165. package/src/backends/kotlin-check.js +41 -0
  166. package/src/backends/kotlin.js +1 -1
  167. package/src/backends/php-check.js +23 -0
  168. package/src/backends/program.js +17 -0
  169. package/src/backends/python-check.js +30 -0
  170. package/src/backends/ruby-check.js +23 -0
  171. package/src/backends/rust-check.js +78 -0
  172. package/src/backends/shared.js +30 -0
  173. package/src/backends/swift-check.js +89 -0
  174. package/src/backends/typescript-check.js +37 -0
  175. package/src/backends/zig-check.js +81 -0
  176. package/src/diagnostic.js +9 -1
  177. package/src/frontends/java.js +24 -0
  178. package/src/frontends/javascript-typescript.js +49 -2
  179. package/src/frontends/php.js +61 -2
  180. package/src/frontends/program.js +9 -0
  181. package/src/frontends/ruby.js +62 -2
  182. package/src/language-registry.js +130 -9
  183. package/src/project-build.js +353 -0
  184. package/src/project-cli.js +155 -0
  185. package/src/project-manifest.js +479 -0
  186. package/src/project-reporter.js +320 -0
  187. package/src/project-snapshot.js +403 -0
  188. package/src/project-watch-reporter.js +303 -0
  189. package/src/project-watch.js +870 -0
  190. package/src/publication.js +275 -58
  191. package/src/semantic/effects.js +1 -0
  192. package/src/semantic/provenance.js +8 -0
  193. package/src/semantic/types.js +101 -2
  194. package/src/semantic/validate.js +26 -0
  195. package/src/subprocess.js +49 -8
  196. package/src/target-check.js +844 -0
  197. package/src/toolchains.js +3 -2
  198. package/tsconfig.json +1 -1
@@ -14,6 +14,7 @@ import {
14
14
  ConstantReadNode,
15
15
  DefNode,
16
16
  ElseNode,
17
+ EmbeddedStatementsNode,
17
18
  FalseNode,
18
19
  HashNode,
19
20
  IfNode,
@@ -49,7 +50,7 @@ import {blockReferencesProtectedEntry} from "../semantic/effects.js"
49
50
  import {locationFromOffsets, moduleLocation, utf8ByteOffsetToUtf16Offset} from "../semantic/location.js"
50
51
  import {withAdaptedOperation} from "../semantic/operators.js"
51
52
  import {withParserRanges} from "../semantic/provenance.js"
52
- import {hasOnlyUnicodeScalars} from "../semantic/scalars.js"
53
+ import {hasOnlyUnicodeScalars, scalarType} from "../semantic/scalars.js"
53
54
  import {isTask034ResourceProbe} from "../semantic/capabilities.js"
54
55
  import {hasExactEffectSupport} from "../backends/effects.js"
55
56
  import {requireSourceReturnType} from "./scalars.js"
@@ -207,7 +208,65 @@ function convertExpression(node, filename, source, context, expectedType, preser
207
208
  return withParserRanges({kind: /** @type {const} */ ("StringLiteral"), location, value: decoded.value}, {literal: location})
208
209
  }
209
210
 
210
- if (node instanceof InterpolatedStringNode) return unsupportedSyntax("ruby", "interpolated string", location)
211
+ if (node instanceof InterpolatedStringNode) {
212
+ if (node.openingLoc && slicePrismSource(source, node.openingLoc.startOffset, node.openingLoc.startOffset + node.openingLoc.length).startsWith("<<")) {
213
+ return unsupportedSyntax("ruby", "heredoc string", location)
214
+ }
215
+
216
+ const parts = node.parts.map((part) => {
217
+ if (part instanceof StringNode) return convertExpression(part, filename, source, context, scalarType("string"))
218
+ if (part instanceof EmbeddedStatementsNode) {
219
+ const statements = part.statements
220
+
221
+ if (!statements || statements.body.length != 1) return unsupportedSyntax("ruby", "interpolated statement", nodeLocation(part, filename, source))
222
+
223
+ return convertExpression(statements.body[0], filename, source, context, scalarType("string"))
224
+ }
225
+
226
+ return unsupportedSyntax("ruby", part.constructor.name, nodeLocation(part, filename, source))
227
+ })
228
+
229
+ if (parts.length == 0) return withParserRanges({kind: /** @type {const} */ ("StringLiteral"), location, value: ""}, {literal: location})
230
+
231
+ let lowered = parts[0]
232
+
233
+ for (const part of parts.slice(1)) {
234
+ const semantic = withAdaptedOperation({
235
+ kind: /** @type {const} */ ("BinaryExpression"),
236
+ left: lowered,
237
+ location,
238
+ right: part
239
+ }, /** @type {import("../semantic/operators.js").AdaptedOperation} */ ("StringConcat"))
240
+
241
+ lowered = /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (semantic))
242
+ }
243
+
244
+ return withParserRanges(lowered, {literal: location})
245
+ }
246
+
247
+ if (node instanceof IfNode && !node.ifKeywordLoc) {
248
+ const elseClause = node.subsequent
249
+ const consequentStatements = node.statements
250
+ const consequentArm = consequentStatements && consequentStatements.body.length == 1 ? consequentStatements.body[0] : undefined
251
+
252
+ if (!(elseClause instanceof ElseNode) || !elseClause.statements || elseClause.statements.body.length != 1 || !consequentArm || !node.thenKeywordLoc) {
253
+ return unsupportedSyntax("ruby", "ternary without alternate", location)
254
+ }
255
+
256
+ return /** @type {import("../semantic/types.js").Expression} */ (/** @type {unknown} */ (withParserRanges({
257
+ alternate: convertExpression(elseClause.statements.body[0], filename, source, context),
258
+ condition: convertExpression(node.predicate, filename, source, context),
259
+ consequent: convertExpression(consequentArm, filename, source, context),
260
+ kind: /** @type {const} */ ("ConditionalExpression"),
261
+ location
262
+ }, {
263
+ alternate: nodeLocation(elseClause.statements.body[0], filename, source),
264
+ colon: prismLocation(elseClause.elseKeywordLoc ?? elseClause.location, filename, source),
265
+ condition: nodeLocation(node.predicate, filename, source),
266
+ consequent: nodeLocation(consequentArm, filename, source),
267
+ operator: prismLocation(node.thenKeywordLoc, filename, source)
268
+ })))
269
+ }
211
270
 
212
271
  if (node instanceof OrNode && node.left instanceof LocalVariableReadNode &&
213
272
  context.bindings.get(node.left.name)?.kind == "OptionalType") {
@@ -863,6 +922,7 @@ function convertStatement(node, comments, context, filename, source) {
863
922
  if ((context.loopDepth ?? 0) > 0) return unsupportedSyntax("ruby", "nonlocal return from each block", nodeLocation(node, filename, source))
864
923
  return convertReturn(node, filename, source, context)
865
924
  }
925
+ if (node instanceof IfNode && !node.ifKeywordLoc) return unsupportedSyntax("ruby", "ternary statement", nodeLocation(node, filename, source))
866
926
  if (node instanceof IfNode || node instanceof UnlessNode) return convertIf(node, comments, context, filename, source)
867
927
  if (node instanceof WhileNode) return convertWhile(node, comments, context, filename, source)
868
928
  if (node instanceof BeginNode) return convertRubyTry(node, comments, context, filename, source)
@@ -5,6 +5,7 @@ import {SemantifoldDiagnostic, unsupportedRole} from "./diagnostic.js"
5
5
  import {generateJava} from "./backends/java.js"
6
6
  import {generateKotlin} from "./backends/kotlin.js"
7
7
  import {generateCSharpProject} from "./backends/csharp.js"
8
+ import {createCSharpCheckPlan} from "./backends/csharp-check.js"
8
9
  import {generateGoModule} from "./backends/go.js"
9
10
  import {generateRustProject} from "./backends/rust.js"
10
11
  import {generateSwift} from "./backends/swift.js"
@@ -35,12 +36,27 @@ import {parseJavaScriptTypeScript} from "./frontends/javascript-typescript.js"
35
36
  import {parsePhp} from "./frontends/php.js"
36
37
  import {parsePython} from "./frontends/python.js"
37
38
  import {parseRuby} from "./frontends/ruby.js"
39
+ import {createJavaCheckPlan} from "./backends/java-check.js"
40
+ import {createJavaScriptCheckPlan} from "./backends/javascript-check.js"
41
+ import {createKotlinCheckPlan} from "./backends/kotlin-check.js"
42
+ import {createPhpCheckPlan} from "./backends/php-check.js"
43
+ import {createPythonCheckPlan} from "./backends/python-check.js"
44
+ import {createRubyCheckPlan} from "./backends/ruby-check.js"
45
+ import {createTypeScriptCheckPlan} from "./backends/typescript-check.js"
46
+ import {createGoCheckPlan} from "./backends/go-check.js"
47
+ import {createCCheckPlan} from "./backends/c-check.js"
48
+ import {createCppCheckPlan} from "./backends/cpp-check.js"
49
+ import {createRustCheckPlan} from "./backends/rust-check.js"
50
+ import {createSwiftCheckPlan} from "./backends/swift-check.js"
51
+ import {createDartCheckPlan} from "./backends/dart-check.js"
52
+ import {createZigCheckPlan} from "./backends/zig-check.js"
38
53
 
39
54
  const registryRoles = Object.freeze(["frontend", "textBackend", "binaryBackend", "applicationBackend", "interoperability"])
40
55
  const acceptanceStageOrder = ["parse", "generate", "restore", "compile", "link", "validate", "instantiate", "execute"]
41
56
  const acceptanceStages = new Map(acceptanceStageOrder.map((stage, index) => [stage, index]))
57
+ const developerCheckStages = new Set(["restore", "compile", "link", "validate"])
42
58
  const registryKeys = new Set([
43
- "acceptance", "applicationBackend", "artifactMultiplicity", "binaryBackend", "defaultFilename", "frontend", "id",
59
+ "acceptance", "applicationBackend", "artifactMultiplicity", "binaryBackend", "check", "defaultFilename", "frontend", "id",
44
60
  "features", "interoperability", "mapping", "mediaType", "provider", "roundTrip", "textBackend"
45
61
  ])
46
62
 
@@ -65,6 +81,7 @@ const registryKeys = new Set([
65
81
  * @typedef LanguageRegistryRecord
66
82
  * @property {string} id - Stable identity.
67
83
  * @property {{stages: import("./semantic/types.js").AcceptanceStage[], toolchains: string[]}} acceptance - Acceptance declaration.
84
+ * @property {Readonly<LanguageRegistryCheckRecord>} check - Developer-check declaration.
68
85
  * @property {"single" | "multiple"} artifactMultiplicity - Artifact multiplicity.
69
86
  * @property {import("./semantic/types.js").LanguageFeatureCapabilities} features - Semantic feature capabilities.
70
87
  * @property {import("./semantic/types.js").LanguageMappingCapabilities} mapping - Mapping capabilities.
@@ -79,6 +96,31 @@ const registryKeys = new Set([
79
96
  * @property {RegistryImplementation} [interoperability] - Interoperability bridge.
80
97
  */
81
98
 
99
+ /**
100
+ * @typedef {Readonly<{
101
+ * artifacts: import("./semantic/types.js").GeneratedArtifactSet,
102
+ * buildPath: string,
103
+ * projectId: string,
104
+ * sourcePath: string,
105
+ * targetId: string,
106
+ * tools: readonly import("./semantic/types.js").DiscoveredToolchain[]
107
+ * }>} TargetCheckPlanContext
108
+ */
109
+
110
+ /**
111
+ * @callback TargetCheckPlanFactory
112
+ * @param {TargetCheckPlanContext} context - Exact staged target context.
113
+ * @returns {import("./semantic/types.js").TargetCheckPlan} Immutable plan.
114
+ */
115
+
116
+ /**
117
+ * @typedef LanguageRegistryCheckRecord
118
+ * @property {TargetCheckPlanFactory} [factory] - Target-owned plan factory for supported checks.
119
+ * @property {readonly import("./semantic/types.js").AcceptanceStage[]} stages - Exact non-executing stages.
120
+ * @property {boolean} supported - Whether the target supplies a check plan.
121
+ * @property {readonly string[]} toolchains - Exact declared canonical toolchains.
122
+ */
123
+
82
124
  /**
83
125
  * @typedef LanguageRegistry
84
126
  * @property {readonly import("./semantic/types.js").LanguageCapabilities[]} descriptors - Public descriptors.
@@ -129,6 +171,8 @@ export function createLanguageRegistry(candidateRecords) {
129
171
  const featuresCandidate = candidate.features ?? {
130
172
  closedRecords: false,
131
173
  conditionControlledLoops: false,
174
+ conditionalExpressions: false,
175
+ stringInterpolation: false,
132
176
  effectfulCapabilitiesAndResources: false,
133
177
  generalFunctionsAndCalls: false,
134
178
  immutableCollections: false,
@@ -141,9 +185,10 @@ export function createLanguageRegistry(candidateRecords) {
141
185
  }
142
186
 
143
187
  if (!isPlainObject(featuresCandidate) ||
144
- Object.keys(featuresCandidate).sort().join(",") != "closedRecords,conditionControlledLoops,effectfulCapabilitiesAndResources,generalFunctionsAndCalls,immutableCollections,optionalValues,orderedListIteration,orderedMapIteration,referenceClasses,typeParametersAndGenerics,typedErrors" ||
188
+ Object.keys(featuresCandidate).sort().join(",") != "closedRecords,conditionControlledLoops,conditionalExpressions,effectfulCapabilitiesAndResources,generalFunctionsAndCalls,immutableCollections,optionalValues,orderedListIteration,orderedMapIteration,referenceClasses,stringInterpolation,typeParametersAndGenerics,typedErrors" ||
145
189
  typeof featuresCandidate.closedRecords != "boolean" ||
146
190
  typeof featuresCandidate.conditionControlledLoops != "boolean" ||
191
+ typeof featuresCandidate.conditionalExpressions != "boolean" ||
147
192
  typeof featuresCandidate.effectfulCapabilitiesAndResources != "boolean" ||
148
193
  typeof featuresCandidate.generalFunctionsAndCalls != "boolean" ||
149
194
  typeof featuresCandidate.immutableCollections != "boolean" ||
@@ -151,6 +196,7 @@ export function createLanguageRegistry(candidateRecords) {
151
196
  typeof featuresCandidate.orderedListIteration != "boolean" ||
152
197
  typeof featuresCandidate.orderedMapIteration != "boolean" ||
153
198
  typeof featuresCandidate.referenceClasses != "boolean" ||
199
+ typeof featuresCandidate.stringInterpolation != "boolean" ||
154
200
  typeof featuresCandidate.typedErrors != "boolean" ||
155
201
  typeof featuresCandidate.typeParametersAndGenerics != "boolean") {
156
202
  invalidRegistry(`Registry record '${id}' has an invalid feature declaration.`, id)
@@ -158,6 +204,7 @@ export function createLanguageRegistry(candidateRecords) {
158
204
  const features = deepFreeze(/** @type {import("./semantic/types.js").LanguageFeatureCapabilities} */ ({
159
205
  closedRecords: featuresCandidate.closedRecords,
160
206
  conditionControlledLoops: featuresCandidate.conditionControlledLoops,
207
+ conditionalExpressions: featuresCandidate.conditionalExpressions,
161
208
  effectfulCapabilitiesAndResources: featuresCandidate.effectfulCapabilitiesAndResources,
162
209
  generalFunctionsAndCalls: featuresCandidate.generalFunctionsAndCalls,
163
210
  immutableCollections: featuresCandidate.immutableCollections,
@@ -165,6 +212,7 @@ export function createLanguageRegistry(candidateRecords) {
165
212
  orderedListIteration: featuresCandidate.orderedListIteration,
166
213
  orderedMapIteration: featuresCandidate.orderedMapIteration,
167
214
  referenceClasses: featuresCandidate.referenceClasses,
215
+ stringInterpolation: featuresCandidate.stringInterpolation,
168
216
  typedErrors: featuresCandidate.typedErrors,
169
217
  typeParametersAndGenerics: featuresCandidate.typeParametersAndGenerics
170
218
  }))
@@ -218,6 +266,52 @@ export function createLanguageRegistry(candidateRecords) {
218
266
  if (new Set(toolchains).size != toolchains.length) {
219
267
  invalidRegistry(`Registry record '${id}' has duplicate acceptance toolchains.`, id)
220
268
  }
269
+ const checkCandidate = candidate.check
270
+ /** @type {Readonly<LanguageRegistryCheckRecord>} */
271
+ let check
272
+
273
+ if (checkCandidate === undefined) {
274
+ check = deepFreeze({stages: [], supported: false, toolchains: []})
275
+ } else {
276
+ if (!isPlainObject(checkCandidate) || Object.keys(checkCandidate).sort().join(",") != "factory,stages,toolchains" ||
277
+ typeof checkCandidate.factory != "function" || !isDenseArray(checkCandidate.stages) ||
278
+ !isDenseArray(checkCandidate.toolchains) || checkCandidate.stages.length == 0) {
279
+ invalidRegistry(`Registry record '${id}' has an invalid developer-check declaration.`, id)
280
+ }
281
+ /** @type {unknown[]} */
282
+ const checkStageSnapshot = []
283
+ /** @type {unknown[]} */
284
+ const checkToolchainSnapshot = []
285
+
286
+ for (let index = 0; index < checkCandidate.stages.length; index += 1) {
287
+ checkStageSnapshot.push(checkCandidate.stages[index])
288
+ }
289
+ for (let index = 0; index < checkCandidate.toolchains.length; index += 1) {
290
+ checkToolchainSnapshot.push(checkCandidate.toolchains[index])
291
+ }
292
+ if (!checkStageSnapshot.every(stage => typeof stage == "string" && developerCheckStages.has(stage) &&
293
+ declaredStages.has(stage)) || !checkToolchainSnapshot.every(toolchain => typeof toolchain == "string" &&
294
+ toolchains.includes(toolchain)) || new Set(checkStageSnapshot).size != checkStageSnapshot.length ||
295
+ new Set(checkToolchainSnapshot).size != checkToolchainSnapshot.length) {
296
+ invalidRegistry(`Registry record '${id}' developer checks must use ordered non-executing declared stages and toolchains.`, id)
297
+ }
298
+ let previousCheckStage = -1
299
+
300
+ for (const stage of checkStageSnapshot) {
301
+ const stageIndex = /** @type {number} */ (acceptanceStages.get(/** @type {string} */ (stage)))
302
+
303
+ if (stageIndex < previousCheckStage) {
304
+ invalidRegistry(`Registry record '${id}' has unordered developer-check stages.`, id)
305
+ }
306
+ previousCheckStage = stageIndex
307
+ }
308
+ check = deepFreeze({
309
+ factory: /** @type {TargetCheckPlanFactory} */ (checkCandidate.factory),
310
+ stages: /** @type {import("./semantic/types.js").AcceptanceStage[]} */ (checkStageSnapshot),
311
+ supported: true,
312
+ toolchains: /** @type {string[]} */ (checkToolchainSnapshot)
313
+ })
314
+ }
221
315
 
222
316
  const hasFrontend = typeof candidate.frontend == "function"
223
317
  const hasTextBackend = typeof candidate.textBackend == "function"
@@ -225,6 +319,10 @@ export function createLanguageRegistry(candidateRecords) {
225
319
  const hasApplicationBackend = typeof candidate.applicationBackend == "function"
226
320
  const hasBackend = hasTextBackend || hasBinaryBackend || hasApplicationBackend
227
321
 
322
+ if (check.supported && !hasBackend) {
323
+ invalidRegistry(`Registry record '${id}' declares developer checks without a backend role.`, id)
324
+ }
325
+
228
326
  if ((mapping.richText || mapping.sourceMapV3 || mapping.binaryRanges) && !hasBackend ||
229
327
  mapping.sourceMapV3 && !mapping.richText ||
230
328
  mapping.binaryRanges && !hasBinaryBackend && !hasApplicationBackend) {
@@ -255,6 +353,7 @@ export function createLanguageRegistry(candidateRecords) {
255
353
  const record = deepFreeze(/** @type {LanguageRegistryRecord} */ ({
256
354
  acceptance,
257
355
  artifactMultiplicity,
356
+ check,
258
357
  features,
259
358
  id,
260
359
  mapping,
@@ -271,6 +370,7 @@ export function createLanguageRegistry(candidateRecords) {
271
370
  const descriptor = deepFreeze(/** @type {import("./semantic/types.js").LanguageCapabilities} */ ({
272
371
  acceptance,
273
372
  artifactMultiplicity,
373
+ check: deepFreeze({stages: check.stages, supported: check.supported, toolchains: check.toolchains}),
274
374
  features,
275
375
  id,
276
376
  mapping,
@@ -384,7 +484,8 @@ const zigFrontend = ({filename, source}) => parseZig({filename, source})
384
484
 
385
485
  const records = [
386
486
  language({
387
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["php82"]},
487
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["php82"]},
488
+ check: {factory: createPhpCheckPlan, stages: ["validate"], toolchains: ["php82"]},
388
489
  defaultFilename: "program.php",
389
490
  frontend: phpFrontend,
390
491
  id: "php",
@@ -392,7 +493,8 @@ const records = [
392
493
  textBackend: generatePhp
393
494
  }),
394
495
  language({
395
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["ruby"]},
496
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["ruby"]},
497
+ check: {factory: createRubyCheckPlan, stages: ["validate"], toolchains: ["ruby"]},
396
498
  defaultFilename: "program.rb",
397
499
  frontend: rubyFrontend,
398
500
  id: "ruby",
@@ -400,7 +502,8 @@ const records = [
400
502
  textBackend: generateRuby
401
503
  }),
402
504
  language({
403
- acceptance: {stages: ["parse", "generate", "execute"], toolchains: ["node"]},
505
+ acceptance: {stages: ["parse", "generate", "validate", "execute"], toolchains: ["node"]},
506
+ check: {factory: createJavaScriptCheckPlan, stages: ["validate"], toolchains: ["node"]},
404
507
  defaultFilename: "program.js",
405
508
  frontend: javaScriptFrontend,
406
509
  id: "javascript",
@@ -409,6 +512,7 @@ const records = [
409
512
  }),
410
513
  language({
411
514
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["tsc", "node"]},
515
+ check: {factory: createTypeScriptCheckPlan, stages: ["compile"], toolchains: ["tsc"]},
412
516
  defaultFilename: "program.ts",
413
517
  frontend: typeScriptFrontend,
414
518
  id: "typescript",
@@ -417,6 +521,7 @@ const records = [
417
521
  }),
418
522
  language({
419
523
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["javac", "java"]},
524
+ check: {factory: createJavaCheckPlan, stages: ["compile"], toolchains: ["javac"]},
420
525
  defaultFilename: "Main.java",
421
526
  frontend: javaFrontend,
422
527
  id: "java",
@@ -425,6 +530,7 @@ const records = [
425
530
  }),
426
531
  language({
427
532
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["kotlinc", "java25"]},
533
+ check: {factory: createKotlinCheckPlan, stages: ["compile"], toolchains: ["kotlinc"]},
428
534
  defaultFilename: "Program.kt",
429
535
  frontend: kotlinFrontend,
430
536
  id: "kotlin",
@@ -433,6 +539,7 @@ const records = [
433
539
  }),
434
540
  language({
435
541
  acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["python"]},
542
+ check: {factory: createPythonCheckPlan, stages: ["compile"], toolchains: ["python"]},
436
543
  defaultFilename: "program.py",
437
544
  frontend: pythonFrontend,
438
545
  id: "python",
@@ -442,6 +549,7 @@ const records = [
442
549
  language({
443
550
  acceptance: {stages: ["parse", "generate", "restore", "compile", "execute"], toolchains: ["dotnet"]},
444
551
  artifactMultiplicity: "multiple",
552
+ check: {factory: createCSharpCheckPlan, stages: ["restore", "compile"], toolchains: ["dotnet"]},
445
553
  defaultFilename: "Program.cs",
446
554
  frontend: csharpFrontend,
447
555
  id: "csharp",
@@ -451,6 +559,7 @@ const records = [
451
559
  language({
452
560
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["go"]},
453
561
  artifactMultiplicity: "multiple",
562
+ check: {factory: createGoCheckPlan, stages: ["compile", "validate"], toolchains: ["go"]},
454
563
  defaultFilename: "main.go",
455
564
  frontend: goFrontend,
456
565
  id: "go",
@@ -460,6 +569,7 @@ const records = [
460
569
  language({
461
570
  acceptance: {stages: ["parse", "generate", "compile", "link", "execute"], toolchains: ["clang"]},
462
571
  artifactMultiplicity: "multiple",
572
+ check: {factory: createCCheckPlan, stages: ["compile", "link"], toolchains: ["clang"]},
463
573
  defaultFilename: "program.c",
464
574
  frontend: parseC,
465
575
  id: "c",
@@ -468,22 +578,28 @@ const records = [
468
578
  }),
469
579
  language({
470
580
  acceptance: {stages: ["parse", "generate", "compile", "link", "execute"], toolchains: ["clangpp"]},
581
+ check: {factory: createCppCheckPlan, stages: ["compile", "link"], toolchains: ["clangpp"]},
471
582
  defaultFilename: "program.cpp", frontend: parseCpp, id: "cpp", mediaType: "text/x-c++src", textBackend: generateCpp
472
583
  }),
473
584
  language({
474
585
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["rustc", "cargo"]},
475
586
  artifactMultiplicity: "multiple",
587
+ check: {factory: createRustCheckPlan, stages: ["compile", "validate"], toolchains: ["rustc", "cargo"]},
476
588
  defaultFilename: "src/main.rs", frontend: parseRust, id: "rust", mediaType: "text/x-rust", textBackend: generateRustProject
477
589
  }),
478
590
  language({acceptance: {stages: ["parse", "generate", "compile", "execute"], toolchains: ["swiftc"]},
591
+ check: {factory: createSwiftCheckPlan, stages: ["compile"], toolchains: ["swiftc"]},
479
592
  defaultFilename: "program.swift", frontend: parseSwift, id: "swift", mediaType: "text/x-swift", textBackend: generateSwift}),
480
593
  language({
481
594
  acceptance: {stages: ["parse", "generate", "restore", "compile", "validate", "execute"], toolchains: ["dart"]},
482
595
  artifactMultiplicity: "multiple",
596
+ check: {factory: createDartCheckPlan, stages: ["restore", "compile", "validate"], toolchains: ["dart"]},
483
597
  defaultFilename: "bin/program.dart",
484
598
  features: {
485
599
  closedRecords: false,
486
600
  conditionControlledLoops: false,
601
+ conditionalExpressions: false,
602
+ stringInterpolation: false,
487
603
  effectfulCapabilitiesAndResources: false,
488
604
  generalFunctionsAndCalls: true,
489
605
  immutableCollections: false,
@@ -502,10 +618,13 @@ const records = [
502
618
  language({
503
619
  acceptance: {stages: ["parse", "generate", "compile", "validate", "execute"], toolchains: ["zig"]},
504
620
  artifactMultiplicity: "multiple",
621
+ check: {factory: createZigCheckPlan, stages: ["compile", "validate"], toolchains: ["zig"]},
505
622
  defaultFilename: "src/main.zig",
506
623
  features: {
507
624
  closedRecords: false,
508
625
  conditionControlledLoops: false,
626
+ conditionalExpressions: false,
627
+ stringInterpolation: false,
509
628
  effectfulCapabilitiesAndResources: false,
510
629
  generalFunctionsAndCalls: true,
511
630
  immutableCollections: false,
@@ -527,7 +646,7 @@ const records = [
527
646
  artifactMultiplicity: "multiple",
528
647
  binaryBackend: generateBrowserWasm,
529
648
  defaultFilename: "program.wasm",
530
- features: {closedRecords: false, conditionControlledLoops: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
649
+ features: {closedRecords: false, conditionControlledLoops: false, conditionalExpressions: false, stringInterpolation: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
531
650
  id: "wasm",
532
651
  mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
533
652
  mediaType: "application/wasm",
@@ -537,7 +656,7 @@ const records = [
537
656
  acceptance: {stages: ["generate", "compile", "validate", "instantiate", "execute"], toolchains: ["android"]},
538
657
  applicationBackend: generateAndroidApplication,
539
658
  artifactMultiplicity: "multiple",
540
- features: {closedRecords: false, conditionControlledLoops: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
659
+ features: {closedRecords: false, conditionControlledLoops: false, conditionalExpressions: false, stringInterpolation: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
541
660
  id: "android",
542
661
  mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
543
662
  roundTrip: false
@@ -546,7 +665,7 @@ const records = [
546
665
  acceptance: {stages: ["generate"], toolchains: []},
547
666
  applicationBackend: generateIosApplication,
548
667
  artifactMultiplicity: "multiple",
549
- features: {closedRecords: false, conditionControlledLoops: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
668
+ features: {closedRecords: false, conditionControlledLoops: false, conditionalExpressions: false, stringInterpolation: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
550
669
  id: "ios",
551
670
  mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
552
671
  roundTrip: false
@@ -555,7 +674,7 @@ const records = [
555
674
  acceptance: {stages: ["generate", "restore", "compile", "validate", "instantiate", "execute"], toolchains: ["flutter", "android"]},
556
675
  applicationBackend: generateFlutterApplication,
557
676
  artifactMultiplicity: "multiple",
558
- features: {closedRecords: false, conditionControlledLoops: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
677
+ features: {closedRecords: false, conditionControlledLoops: false, conditionalExpressions: false, stringInterpolation: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
559
678
  id: "flutter",
560
679
  mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
561
680
  roundTrip: false
@@ -580,6 +699,8 @@ function language(values) {
580
699
  features: {
581
700
  closedRecords: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),
582
701
  conditionControlledLoops: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),
702
+ conditionalExpressions: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),
703
+ stringInterpolation: ["php", "ruby", "javascript", "typescript"].includes(String(values.id)),
583
704
  effectfulCapabilitiesAndResources: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),
584
705
  generalFunctionsAndCalls: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),
585
706
  immutableCollections: ["php", "ruby", "javascript", "typescript", "java"].includes(String(values.id)),