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.
- package/README.md +61 -15
- package/build/index.d.ts +52 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +60 -8
- package/build/src/artifact-path.d.ts +23 -1
- package/build/src/artifact-path.d.ts.map +1 -1
- package/build/src/artifact-path.js +45 -3
- package/build/src/artifacts.d.ts.map +1 -1
- package/build/src/artifacts.js +66 -1
- package/build/src/backends/android.d.ts +49 -0
- package/build/src/backends/android.d.ts.map +1 -0
- package/build/src/backends/android.js +1274 -0
- package/build/src/backends/c-validation.d.ts.map +1 -1
- package/build/src/backends/c-validation.js +7 -3
- package/build/src/backends/cpp-validation.d.ts.map +1 -1
- package/build/src/backends/cpp-validation.js +7 -3
- package/build/src/backends/csharp.js +7 -1
- package/build/src/backends/dart-runtime.d.ts +2 -0
- package/build/src/backends/dart-runtime.d.ts.map +1 -0
- package/build/src/backends/dart-runtime.js +41 -0
- package/build/src/backends/dart.d.ts +20 -0
- package/build/src/backends/dart.d.ts.map +1 -0
- package/build/src/backends/dart.js +321 -0
- package/build/src/backends/effects.d.ts +60 -0
- package/build/src/backends/effects.d.ts.map +1 -0
- package/build/src/backends/effects.js +746 -0
- package/build/src/backends/go.js +18 -4
- package/build/src/backends/identifiers.d.ts +36 -4
- package/build/src/backends/identifiers.d.ts.map +1 -1
- package/build/src/backends/identifiers.js +160 -10
- package/build/src/backends/index.d.ts.map +1 -1
- package/build/src/backends/index.js +27 -4
- package/build/src/backends/ios.d.ts +68 -0
- package/build/src/backends/ios.d.ts.map +1 -0
- package/build/src/backends/ios.js +1503 -0
- package/build/src/backends/java.d.ts.map +1 -1
- package/build/src/backends/java.js +429 -36
- package/build/src/backends/javascript.d.ts +6 -0
- package/build/src/backends/javascript.d.ts.map +1 -1
- package/build/src/backends/javascript.js +380 -24
- package/build/src/backends/kotlin-runtime.d.ts +3 -0
- package/build/src/backends/kotlin-runtime.d.ts.map +1 -0
- package/build/src/backends/kotlin-runtime.js +29 -0
- package/build/src/backends/kotlin.d.ts +33 -0
- package/build/src/backends/kotlin.d.ts.map +1 -0
- package/build/src/backends/kotlin.js +138 -0
- package/build/src/backends/native-validation.d.ts +2 -2
- package/build/src/backends/native-validation.d.ts.map +1 -1
- package/build/src/backends/native-validation.js +2 -2
- package/build/src/backends/ordered-expressions.d.ts.map +1 -1
- package/build/src/backends/ordered-expressions.js +39 -7
- package/build/src/backends/php-stdlib-support.d.ts +19 -0
- package/build/src/backends/php-stdlib-support.d.ts.map +1 -0
- package/build/src/backends/php-stdlib-support.js +227 -0
- package/build/src/backends/php.d.ts.map +1 -1
- package/build/src/backends/php.js +448 -33
- package/build/src/backends/program.d.ts +83 -0
- package/build/src/backends/program.d.ts.map +1 -0
- package/build/src/backends/program.js +1309 -0
- package/build/src/backends/python.js +7 -1
- package/build/src/backends/ruby.d.ts.map +1 -1
- package/build/src/backends/ruby.js +310 -24
- package/build/src/backends/rust-runtime.d.ts +7 -0
- package/build/src/backends/rust-runtime.d.ts.map +1 -0
- package/build/src/backends/rust-runtime.js +32 -0
- package/build/src/backends/rust-validation.d.ts +9 -0
- package/build/src/backends/rust-validation.d.ts.map +1 -0
- package/build/src/backends/rust-validation.js +78 -0
- package/build/src/backends/rust.d.ts +24 -0
- package/build/src/backends/rust.d.ts.map +1 -0
- package/build/src/backends/rust.js +344 -0
- package/build/src/backends/scalars.d.ts +14 -6
- package/build/src/backends/scalars.d.ts.map +1 -1
- package/build/src/backends/scalars.js +167 -17
- package/build/src/backends/shared.d.ts +23 -4
- package/build/src/backends/shared.d.ts.map +1 -1
- package/build/src/backends/shared.js +2174 -62
- package/build/src/backends/stdlib-support.d.ts +14 -0
- package/build/src/backends/stdlib-support.d.ts.map +1 -0
- package/build/src/backends/stdlib-support.js +237 -0
- package/build/src/backends/swift-runtime.d.ts +3 -0
- package/build/src/backends/swift-runtime.d.ts.map +1 -0
- package/build/src/backends/swift-runtime.js +14 -0
- package/build/src/backends/swift.d.ts +8 -0
- package/build/src/backends/swift.d.ts.map +1 -0
- package/build/src/backends/swift.js +127 -0
- package/build/src/backends/typescript.d.ts.map +1 -1
- package/build/src/backends/typescript.js +344 -24
- package/build/src/backends/wasm.d.ts +43 -0
- package/build/src/backends/wasm.d.ts.map +1 -0
- package/build/src/backends/wasm.js +2164 -0
- package/build/src/backends/writer.d.ts +255 -4
- package/build/src/backends/writer.d.ts.map +1 -1
- package/build/src/backends/writer.js +491 -3
- package/build/src/diagnostic.d.ts +4 -3
- package/build/src/diagnostic.d.ts.map +1 -1
- package/build/src/diagnostic.js +5 -3
- package/build/src/frontends/c.d.ts.map +1 -1
- package/build/src/frontends/c.js +5 -3
- package/build/src/frontends/cpp.d.ts.map +1 -1
- package/build/src/frontends/cpp.js +5 -3
- package/build/src/frontends/csharp.d.ts.map +1 -1
- package/build/src/frontends/csharp.js +7 -3
- package/build/src/frontends/dart.d.ts +10 -0
- package/build/src/frontends/dart.d.ts.map +1 -0
- package/build/src/frontends/dart.js +913 -0
- package/build/src/frontends/index.d.ts +3 -1
- package/build/src/frontends/index.d.ts.map +1 -1
- package/build/src/frontends/index.js +15 -5
- package/build/src/frontends/java.d.ts +110 -1
- package/build/src/frontends/java.d.ts.map +1 -1
- package/build/src/frontends/java.js +1725 -70
- package/build/src/frontends/javascript-typescript.d.ts +69 -1
- package/build/src/frontends/javascript-typescript.d.ts.map +1 -1
- package/build/src/frontends/javascript-typescript.js +1825 -93
- package/build/src/frontends/kotlin.d.ts +10 -0
- package/build/src/frontends/kotlin.d.ts.map +1 -0
- package/build/src/frontends/kotlin.js +685 -0
- package/build/src/frontends/php.d.ts +118 -1
- package/build/src/frontends/php.d.ts.map +1 -1
- package/build/src/frontends/php.js +1583 -76
- package/build/src/frontends/program.d.ts +74 -0
- package/build/src/frontends/program.d.ts.map +1 -0
- package/build/src/frontends/program.js +989 -0
- package/build/src/frontends/ruby.d.ts +68 -1
- package/build/src/frontends/ruby.d.ts.map +1 -1
- package/build/src/frontends/ruby.js +1446 -101
- package/build/src/frontends/rust-parser.d.ts +11 -0
- package/build/src/frontends/rust-parser.d.ts.map +1 -0
- package/build/src/frontends/rust-parser.js +15 -0
- package/build/src/frontends/rust.d.ts +14 -0
- package/build/src/frontends/rust.d.ts.map +1 -0
- package/build/src/frontends/rust.js +715 -0
- package/build/src/frontends/scalars.d.ts +10 -0
- package/build/src/frontends/scalars.d.ts.map +1 -1
- package/build/src/frontends/scalars.js +28 -2
- package/build/src/frontends/swift.d.ts +10 -0
- package/build/src/frontends/swift.d.ts.map +1 -0
- package/build/src/frontends/swift.js +860 -0
- package/build/src/frontends/types.d.ts +186 -0
- package/build/src/frontends/types.d.ts.map +1 -0
- package/build/src/frontends/types.js +634 -0
- package/build/src/language-registry.d.ts +46 -4
- package/build/src/language-registry.d.ts.map +1 -1
- package/build/src/language-registry.js +177 -13
- package/build/src/mapping.d.ts +2 -2
- package/build/src/mapping.d.ts.map +1 -1
- package/build/src/mapping.js +31 -10
- package/build/src/semantic/capabilities.d.ts +66 -0
- package/build/src/semantic/capabilities.d.ts.map +1 -0
- package/build/src/semantic/capabilities.js +649 -0
- package/build/src/semantic/effects.d.ts +26 -0
- package/build/src/semantic/effects.d.ts.map +1 -0
- package/build/src/semantic/effects.js +764 -0
- package/build/src/semantic/generics.d.ts +23 -0
- package/build/src/semantic/generics.d.ts.map +1 -0
- package/build/src/semantic/generics.js +61 -0
- package/build/src/semantic/lifetime.d.ts +37 -0
- package/build/src/semantic/lifetime.d.ts.map +1 -0
- package/build/src/semantic/lifetime.js +527 -0
- package/build/src/semantic/provenance.d.ts +9 -2
- package/build/src/semantic/provenance.d.ts.map +1 -1
- package/build/src/semantic/provenance.js +462 -20
- package/build/src/semantic/scalars.d.ts +11 -0
- package/build/src/semantic/scalars.d.ts.map +1 -1
- package/build/src/semantic/scalars.js +16 -1
- package/build/src/semantic/stdlib.d.ts +254 -0
- package/build/src/semantic/stdlib.d.ts.map +1 -0
- package/build/src/semantic/stdlib.js +880 -0
- package/build/src/semantic/types.d.ts +3108 -178
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +730 -15
- package/build/src/semantic/validate.d.ts +85 -5
- package/build/src/semantic/validate.d.ts.map +1 -1
- package/build/src/semantic/validate.js +2576 -98
- package/build/src/stdlib-facades.d.ts +304 -0
- package/build/src/stdlib-facades.d.ts.map +1 -0
- package/build/src/stdlib-facades.js +1167 -0
- package/build/src/stdlib-negotiation.d.ts +69 -0
- package/build/src/stdlib-negotiation.d.ts.map +1 -0
- package/build/src/stdlib-negotiation.js +403 -0
- package/build/src/stdlib-providers.d.ts +72 -0
- package/build/src/stdlib-providers.d.ts.map +1 -0
- package/build/src/stdlib-providers.js +339 -0
- package/build/src/toolchains.d.ts +55 -1
- package/build/src/toolchains.d.ts.map +1 -1
- package/build/src/toolchains.js +15 -4
- package/docs/android.md +79 -0
- package/docs/architecture.md +47 -13
- package/docs/dart.md +60 -0
- package/docs/goals.md +3 -3
- package/docs/ios.md +121 -0
- package/docs/kotlin.md +42 -0
- package/docs/language-support.md +238 -26
- package/docs/multi-file-modules.md +52 -0
- package/docs/parser-qualification.md +121 -8
- package/docs/plans/2026-09-05-standard-library-portability.md +10 -10
- package/docs/rust.md +88 -0
- package/docs/source-maps.md +17 -7
- package/docs/specification.md +5 -0
- package/docs/standard-library-portability.md +39 -8
- package/docs/swift.md +44 -0
- package/docs/testing.md +381 -4
- package/docs/webassembly.md +52 -0
- package/index.js +66 -8
- package/node_modules/semantifold-tree-sitter-legacy-internal/README.md +2 -2
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/LICENSE +21 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/README.md +45 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/binding.gyp +30 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding.cc +20 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/binding_test.js +9 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.d.ts +28 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/bindings/node/index.js +11 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/grammar.js +1630 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/package.json +64 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/darwin-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/linux-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-arm64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/prebuilds/win32-x64/tree-sitter-rust.node +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/highlights.scm +159 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/injections.scm +9 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/queries/tags.scm +60 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/grammar.json +9405 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/node-types.json +5399 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/parser.c +192569 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/scanner.c +393 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/alloc.h +54 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/array.h +290 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/src/tree_sitter/parser.h +266 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter-rust.wasm +0 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/node_modules/tree-sitter-rust/tree-sitter.json +53 -0
- package/node_modules/semantifold-tree-sitter-legacy-internal/package.json +3 -2
- package/node_modules/semantifold-tree-sitter-legacy-internal/src/c.js +5 -4
- package/package.json +5 -2
- package/src/artifact-path.js +47 -2
- package/src/artifacts.js +67 -0
- package/src/backends/android.js +1370 -0
- package/src/backends/c-validation.js +6 -1
- package/src/backends/cpp-validation.js +6 -1
- package/src/backends/csharp.js +3 -0
- package/src/backends/dart-runtime.js +41 -0
- package/src/backends/dart.js +326 -0
- package/src/backends/effects.js +705 -0
- package/src/backends/go.js +14 -2
- package/src/backends/identifiers.js +166 -9
- package/src/backends/index.js +27 -2
- package/src/backends/ios.js +1612 -0
- package/src/backends/java.js +454 -36
- package/src/backends/javascript.js +389 -23
- package/src/backends/kotlin-runtime.js +29 -0
- package/src/backends/kotlin.js +144 -0
- package/src/backends/native-validation.js +1 -1
- package/src/backends/ordered-expressions.js +40 -6
- package/src/backends/php-stdlib-support.js +239 -0
- package/src/backends/php.js +469 -32
- package/src/backends/program.js +1408 -0
- package/src/backends/python.js +3 -0
- package/src/backends/ruby.js +326 -23
- package/src/backends/rust-runtime.js +34 -0
- package/src/backends/rust-validation.js +75 -0
- package/src/backends/rust.js +335 -0
- package/src/backends/scalars.js +141 -16
- package/src/backends/shared.js +2314 -115
- package/src/backends/stdlib-support.js +234 -0
- package/src/backends/swift-runtime.js +14 -0
- package/src/backends/swift.js +132 -0
- package/src/backends/typescript.js +349 -23
- package/src/backends/wasm.js +2208 -0
- package/src/backends/writer.js +545 -2
- package/src/diagnostic.js +4 -2
- package/src/frontends/c.js +4 -2
- package/src/frontends/cpp.js +4 -2
- package/src/frontends/csharp.js +4 -2
- package/src/frontends/dart.js +963 -0
- package/src/frontends/index.js +14 -4
- package/src/frontends/java.js +1977 -69
- package/src/frontends/javascript-typescript.js +2046 -102
- package/src/frontends/kotlin.js +713 -0
- package/src/frontends/php.js +1725 -79
- package/src/frontends/program.js +1062 -0
- package/src/frontends/ruby.js +1624 -98
- package/src/frontends/rust-parser.js +18 -0
- package/src/frontends/rust.js +714 -0
- package/src/frontends/scalars.js +31 -1
- package/src/frontends/swift.js +893 -0
- package/src/frontends/types.js +750 -0
- package/src/language-registry.js +182 -12
- package/src/mapping.js +33 -9
- package/src/semantic/capabilities.js +671 -0
- package/src/semantic/effects.js +737 -0
- package/src/semantic/generics.js +58 -0
- package/src/semantic/lifetime.js +517 -0
- package/src/semantic/provenance.js +412 -19
- package/src/semantic/scalars.js +17 -0
- package/src/semantic/stdlib.js +921 -0
- package/src/semantic/types.js +810 -14
- package/src/semantic/validate.js +2934 -209
- package/src/stdlib-facades.js +1211 -0
- package/src/stdlib-negotiation.js +446 -0
- package/src/stdlib-providers.js +377 -0
- package/src/toolchains.js +16 -3
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {isDenseArray} from "./array.js"
|
|
4
|
+
import {isSafeArtifactPath} from "./artifact-path.js"
|
|
5
|
+
import {SemantifoldDiagnostic} from "./diagnostic.js"
|
|
6
|
+
import {
|
|
7
|
+
compareStdlibVersions, parseStdlibVersion, parseStdlibVersionRange, resolveStdlibModule, stdlibVersionSatisfies
|
|
8
|
+
} from "./semantic/stdlib.js"
|
|
9
|
+
|
|
10
|
+
const facadeIdentityPattern = /^[a-z][a-z0-9.-]*$/u
|
|
11
|
+
const moduleIdPattern = /^[a-z][a-z0-9_]*(?:[.-][a-z][a-z0-9_]*)*$/u
|
|
12
|
+
const declarationNamePattern = /^[A-Za-z_][A-Za-z0-9_]*$/u
|
|
13
|
+
const supportedLanguages = new Set(["php", "ruby", "javascript", "typescript", "java"])
|
|
14
|
+
const canonicalTypes = new Set(["boolean", "integer", "string", "void"])
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef StdlibFacadeFunctionDeclaration
|
|
18
|
+
* @property {"function"} kind - Closed public declaration kind.
|
|
19
|
+
* @property {string} name - Exact source-visible symbol.
|
|
20
|
+
* @property {{name: string, type: string}[]} parameters - Ordered source signature.
|
|
21
|
+
* @property {string} returnType - Canonical result type.
|
|
22
|
+
* @property {string[]} effects - Closed public effects.
|
|
23
|
+
* @property {string[]} failures - Escaping canonical failure names.
|
|
24
|
+
* @property {("direct-call" | "unqualified-call" | "receiver-call")[]} forms - Accepted source call forms.
|
|
25
|
+
* @property {"not-applicable"} ownership - Initial scalar qualification ownership.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* @typedef StdlibFacadeClassDeclaration
|
|
29
|
+
* @property {"class"} kind - Closed public declaration kind.
|
|
30
|
+
* @property {string} name - Exact source-visible class symbol.
|
|
31
|
+
* @property {["constructor-call"]} forms - Accepted construction form.
|
|
32
|
+
* @property {"owned-reference"} ownership - Class instance ownership.
|
|
33
|
+
* @property {{effects: string[], failures: string[], ownership: "acquired", parameters: {name: string, type: string}[]}} constructor - Constructor contract.
|
|
34
|
+
* @property {{effects: string[], failures: string[], forms: ["receiver-call"], name: string, ownership: "borrowed" | "consumed", parameters: {name: string, type: string}[], returnType: string}[]} methods - Public instance methods.
|
|
35
|
+
*/
|
|
36
|
+
/** @typedef {StdlibFacadeFunctionDeclaration | StdlibFacadeClassDeclaration} StdlibFacadePublicDeclaration */
|
|
37
|
+
/**
|
|
38
|
+
* @typedef StdlibFacadeRecord
|
|
39
|
+
* @property {{identity: string, range: string}[]} dependencies - Facade-module dependencies.
|
|
40
|
+
* @property {string} identity - Versioned facade identity.
|
|
41
|
+
* @property {import("./semantic/types.js").SemanticLanguage} language - Source language.
|
|
42
|
+
* @property {({identity: string, kind: "module", symbols: string[]} | {forms: ("unqualified-call" | "receiver-call")[], identity: string, kind: "builtin", symbols: string[]})[]} nativeModules - Exact source native identities.
|
|
43
|
+
* @property {StdlibFacadePublicDeclaration[]} publicDeclarations - Public source surface.
|
|
44
|
+
* @property {{module: string, operations: string[], range: string}[]} requirements - Canonical-only requirements.
|
|
45
|
+
* @property {string} runtimeProfile - Exact compatible source/runtime profile.
|
|
46
|
+
* @property {{content: string, filename: string, id: string}} source - Executable compiler-owned source module.
|
|
47
|
+
* @property {string} version - Exact facade version.
|
|
48
|
+
* @property {"internal" | "public"} visibility - Native-selectable visibility.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* @typedef FacadeSourceNames
|
|
52
|
+
* @property {string} extension - Source filename extension.
|
|
53
|
+
* @property {string} nativeModule - Public native stdlib module identity.
|
|
54
|
+
* @property {string} publicName - Public native symbol.
|
|
55
|
+
* @property {string} unusedName - Unused-elimination fixture symbol.
|
|
56
|
+
* @property {string} unusedNativeModule - Unused-elimination fixture module.
|
|
57
|
+
* @property {string} probeSource - Public executable facade source.
|
|
58
|
+
* @property {string} runnerSource - Internal canonical runner source.
|
|
59
|
+
* @property {string} unusedSource - Unused executable facade source.
|
|
60
|
+
*/
|
|
61
|
+
/**
|
|
62
|
+
* @typedef StdlibFacadeRegistry
|
|
63
|
+
* @property {readonly StdlibFacadeRecord[]} facades - Stable immutable facade records.
|
|
64
|
+
* @property {(language: string, nativeModule: string, symbol: string, range?: string) => StdlibFacadeRecord} resolveFacade - Exact native identity resolver.
|
|
65
|
+
* @property {(identity: string, language: string, range?: string) => StdlibFacadeRecord} resolveIdentity - Facade dependency resolver.
|
|
66
|
+
* @property {(language: string, nativeModule: string, range?: string) => StdlibFacadeRecord} resolveModule - Exact native module resolver.
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Creates a detached immutable source-language facade registry.
|
|
71
|
+
* @param {unknown} records - Optional facade definitions; built-in qualification definitions by default.
|
|
72
|
+
* @returns {Readonly<StdlibFacadeRegistry>} Validated facade registry.
|
|
73
|
+
*/
|
|
74
|
+
export function createStdlibFacadeRegistry(records = builtinFacadeRecords()) {
|
|
75
|
+
if (!isDenseArray(records)) invalidFacade("Facade records must be an ordered dense array.")
|
|
76
|
+
/** @type {StdlibFacadeRecord[]} */
|
|
77
|
+
const facades = []
|
|
78
|
+
/** @type {Map<string, Map<string, StdlibFacadeRecord>>} */
|
|
79
|
+
const byIdentity = new Map()
|
|
80
|
+
/** @type {Map<string, StdlibFacadeRecord[]>} */
|
|
81
|
+
const byNativeModule = new Map()
|
|
82
|
+
const sourceIds = new Map()
|
|
83
|
+
const sourceFilenames = new Map()
|
|
84
|
+
|
|
85
|
+
for (let index = 0; index < records.length; index += 1) {
|
|
86
|
+
const record = validateFacadeRecord(records[index])
|
|
87
|
+
const identityKey = `${record.language}\0${record.identity}`
|
|
88
|
+
const versions = byIdentity.get(identityKey) ?? new Map()
|
|
89
|
+
|
|
90
|
+
if (versions.has(record.version)) invalidFacade(`Duplicate facade '${record.identity}' version '${record.version}' for '${record.language}'.`)
|
|
91
|
+
if (sourceIds.has(record.source.id) && sourceIds.get(record.source.id) != identityKey) {
|
|
92
|
+
invalidFacade(`Duplicate facade source module identity '${record.source.id}'.`)
|
|
93
|
+
}
|
|
94
|
+
if (sourceFilenames.has(record.source.filename) && sourceFilenames.get(record.source.filename) != identityKey) {
|
|
95
|
+
invalidFacade(`Duplicate facade source filename '${record.source.filename}'.`)
|
|
96
|
+
}
|
|
97
|
+
versions.set(record.version, record)
|
|
98
|
+
byIdentity.set(identityKey, versions)
|
|
99
|
+
sourceIds.set(record.source.id, identityKey)
|
|
100
|
+
sourceFilenames.set(record.source.filename, identityKey)
|
|
101
|
+
facades.push(record)
|
|
102
|
+
|
|
103
|
+
for (const nativeModule of record.nativeModules) {
|
|
104
|
+
const nativeKey = `${record.language}\0${nativeModule.identity}`
|
|
105
|
+
const nativeRecords = byNativeModule.get(nativeKey) ?? []
|
|
106
|
+
|
|
107
|
+
nativeRecords.push(record)
|
|
108
|
+
byNativeModule.set(nativeKey, nativeRecords)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const record of facades) {
|
|
113
|
+
for (const dependency of record.dependencies) {
|
|
114
|
+
resolveIdentityFromStore(byIdentity, dependency.identity, record.language, dependency.range, record.identity)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
validateFacadeDependencyCycles(facades, byIdentity)
|
|
118
|
+
|
|
119
|
+
return Object.freeze(/** @type {StdlibFacadeRegistry} */ ({
|
|
120
|
+
facades: Object.freeze(facades),
|
|
121
|
+
resolveFacade(language, nativeModule, symbol, range) {
|
|
122
|
+
return resolveNativeFacadeFromStore(byNativeModule, language, nativeModule, symbol, range)
|
|
123
|
+
},
|
|
124
|
+
resolveIdentity(identity, language, range) {
|
|
125
|
+
return resolveIdentityFromStore(byIdentity, identity, language, range)
|
|
126
|
+
},
|
|
127
|
+
resolveModule(language, nativeModule, range) {
|
|
128
|
+
const records = byNativeModule.get(`${language}\0${nativeModule}`)
|
|
129
|
+
|
|
130
|
+
if (!records) unprovedIdentity(language, nativeModule)
|
|
131
|
+
const identities = new Set(/** @type {StdlibFacadeRecord[]} */ (records).map(({identity}) => identity))
|
|
132
|
+
|
|
133
|
+
if (identities.size != 1) invalidFacade(`Native facade module '${nativeModule}' is ambiguous for '${language}'.`)
|
|
134
|
+
return selectFacadeVersion(new Map(/** @type {StdlibFacadeRecord[]} */ (records).map((record) => [record.version, record])),
|
|
135
|
+
/** @type {StdlibFacadeRecord} */ (records[0]).identity, language, range)
|
|
136
|
+
}
|
|
137
|
+
}))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Rejects cycles after every versioned dependency has resolved successfully.
|
|
142
|
+
* @param {StdlibFacadeRecord[]} facades - Validated facade records.
|
|
143
|
+
* @param {Map<string, Map<string, StdlibFacadeRecord>>} store - Records by language and identity.
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
146
|
+
function validateFacadeDependencyCycles(facades, store) {
|
|
147
|
+
const active = new Set()
|
|
148
|
+
const complete = new Set()
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Visits one exact selected facade version.
|
|
152
|
+
* @param {StdlibFacadeRecord} record - Facade record.
|
|
153
|
+
* @returns {void}
|
|
154
|
+
*/
|
|
155
|
+
function visit(record) {
|
|
156
|
+
const key = `${record.language}\0${record.identity}\0${record.version}`
|
|
157
|
+
|
|
158
|
+
if (complete.has(key)) return
|
|
159
|
+
if (active.has(key)) invalidFacade(`Facade dependency cycle includes '${record.identity}'.`)
|
|
160
|
+
active.add(key)
|
|
161
|
+
for (const dependency of record.dependencies) {
|
|
162
|
+
visit(resolveIdentityFromStore(store, dependency.identity, record.language, dependency.range, record.identity))
|
|
163
|
+
}
|
|
164
|
+
active.delete(key)
|
|
165
|
+
complete.add(key)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
for (const record of facades) visit(record)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Lists all built-in public and internal facade modules in stable order.
|
|
173
|
+
* @returns {readonly StdlibFacadeRecord[]} Immutable facade definitions.
|
|
174
|
+
*/
|
|
175
|
+
export function listStdlibFacades() {
|
|
176
|
+
return stdlibFacadeRegistry.facades
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Resolves one built-in facade from parser-proved native module and symbol identities.
|
|
181
|
+
* @param {string} language - Source language.
|
|
182
|
+
* @param {string} nativeModule - Exact native module identity.
|
|
183
|
+
* @param {string} symbol - Exact imported or qualified symbol.
|
|
184
|
+
* @param {string} [range] - Compatible facade version range.
|
|
185
|
+
* @returns {StdlibFacadeRecord} Immutable facade definition.
|
|
186
|
+
*/
|
|
187
|
+
export function resolveStdlibFacade(language, nativeModule, symbol, range) {
|
|
188
|
+
return stdlibFacadeRegistry.resolveFacade(language, nativeModule, symbol, range)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Resolves a dependency-first, cycle-free facade module closure.
|
|
193
|
+
* @param {StdlibFacadeRecord[]} roots - Parser-selected facade roots.
|
|
194
|
+
* @param {Readonly<StdlibFacadeRegistry>} [registry] - Facade registry.
|
|
195
|
+
* @returns {StdlibFacadeRecord[]} Stable dependency-first closure.
|
|
196
|
+
*/
|
|
197
|
+
export function resolveStdlibFacadeClosure(roots, registry = stdlibFacadeRegistry) {
|
|
198
|
+
const active = new Set()
|
|
199
|
+
const complete = new Set()
|
|
200
|
+
/** @type {StdlibFacadeRecord[]} */
|
|
201
|
+
const result = []
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Visits one selected facade and its declared dependencies.
|
|
205
|
+
* @param {StdlibFacadeRecord} record - Facade to visit.
|
|
206
|
+
* @returns {void}
|
|
207
|
+
*/
|
|
208
|
+
function visit(record) {
|
|
209
|
+
const key = `${record.language}\0${record.identity}\0${record.version}`
|
|
210
|
+
|
|
211
|
+
if (complete.has(key)) return
|
|
212
|
+
if (active.has(key)) invalidFacade(`Facade dependency cycle includes '${record.identity}'.`)
|
|
213
|
+
active.add(key)
|
|
214
|
+
for (const dependency of record.dependencies) {
|
|
215
|
+
visit(registry.resolveIdentity(dependency.identity, record.language, dependency.range))
|
|
216
|
+
}
|
|
217
|
+
active.delete(key)
|
|
218
|
+
complete.add(key)
|
|
219
|
+
result.push(record)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
for (const root of roots) visit(root)
|
|
223
|
+
return result
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Creates the detached, deterministic program descriptor for one selected facade closure.
|
|
228
|
+
* @param {import("./semantic/types.js").SemanticLanguage} language - Source language profile.
|
|
229
|
+
* @param {StdlibFacadeRecord[]} facades - Dependency-first selected facade records.
|
|
230
|
+
* @returns {import("./semantic/types.js").StdlibFacadeProgramDescriptor} Plain program descriptor.
|
|
231
|
+
*/
|
|
232
|
+
export function stdlibFacadeProgramDescriptor(language, facades) {
|
|
233
|
+
return {
|
|
234
|
+
language,
|
|
235
|
+
modules: facades.map((facade) => ({
|
|
236
|
+
dependencies: facade.dependencies.map((dependency) => ({...dependency})),
|
|
237
|
+
identity: facade.identity,
|
|
238
|
+
nativeModules: facade.nativeModules.map((module) => ({...module,
|
|
239
|
+
...(module.kind == "builtin" ? {forms: [...module.forms]} : {}), symbols: [...module.symbols]})),
|
|
240
|
+
publicDeclarations: facade.publicDeclarations.map(detachPublicDeclaration),
|
|
241
|
+
requirements: facade.requirements.map((requirement) => ({...requirement, operations: [...requirement.operations]})),
|
|
242
|
+
runtimeProfile: facade.runtimeProfile,
|
|
243
|
+
sourceModule: facade.source.id,
|
|
244
|
+
version: facade.version,
|
|
245
|
+
visibility: facade.visibility
|
|
246
|
+
})),
|
|
247
|
+
schema: "SemantifoldStdlibFacades",
|
|
248
|
+
version: 1
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Derives compiler-owned semantic capability authority from selected facade requirements.
|
|
254
|
+
* The initial executable qualification corpus intentionally targets one canonical module.
|
|
255
|
+
* @param {StdlibFacadeRecord[]} records - Selected facade closure.
|
|
256
|
+
* @returns {{contract: {contractVersion: string, identity: string}, input: import("./semantic/types.js").CapabilityAuthorityInput} | {contracts: {contractVersion: string, identity: string}[], input: import("./semantic/types.js").CapabilityAuthorityInput} | null} Authority input.
|
|
257
|
+
*/
|
|
258
|
+
export function facadeCapabilityAuthority(records) {
|
|
259
|
+
const requirements = records.flatMap((record) => record.requirements)
|
|
260
|
+
|
|
261
|
+
if (requirements.length == 0) return null
|
|
262
|
+
const identities = new Set(requirements.map(({module}) => module))
|
|
263
|
+
const ranges = new Set(requirements.map(({range}) => range))
|
|
264
|
+
|
|
265
|
+
const task037 = records.some(({identity}) => identity.startsWith("semantifold.task037."))
|
|
266
|
+
|
|
267
|
+
if (task037) {
|
|
268
|
+
const requirementByModule = new Map()
|
|
269
|
+
|
|
270
|
+
for (const requirement of requirements) {
|
|
271
|
+
const current = requirementByModule.get(requirement.module)
|
|
272
|
+
|
|
273
|
+
if (current && current.range != requirement.range) invalidFacade("Task 037 facade requirements disagree on a canonical range.")
|
|
274
|
+
const operations = new Set(current?.operations ?? [])
|
|
275
|
+
|
|
276
|
+
for (const operation of requirement.operations) operations.add(operation)
|
|
277
|
+
requirementByModule.set(requirement.module, {operations, range: requirement.range})
|
|
278
|
+
}
|
|
279
|
+
const modules = [...requirementByModule.entries()].map(([identity, requirement]) => {
|
|
280
|
+
const contract = resolveStdlibModule(identity, requirement.range)
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
capabilities: [{
|
|
284
|
+
failures: contract.failures.map(({name}) => ({name})),
|
|
285
|
+
name: canonicalCapabilityName(identity),
|
|
286
|
+
operations: contract.operations.filter(({name}) => requirement.operations.has(name)).map((operation) => ({
|
|
287
|
+
effects: /** @type {["host"]} */ ([...operation.effects]),
|
|
288
|
+
failures: operation.failures.map(detachCanonicalReference),
|
|
289
|
+
name: operation.name,
|
|
290
|
+
parameters: operation.parameters.map((parameter) => ({
|
|
291
|
+
name: parameter.name,
|
|
292
|
+
type: canonicalCapabilityParameterType(parameter.type)
|
|
293
|
+
})),
|
|
294
|
+
resourceFlow: detachResourceFlow(operation.resourceFlow),
|
|
295
|
+
returnType: canonicalCapabilityType(operation.returnType)
|
|
296
|
+
})),
|
|
297
|
+
resources: contract.resources.map(({name}) => ({name}))
|
|
298
|
+
}],
|
|
299
|
+
contractVersion: requirement.range,
|
|
300
|
+
identity
|
|
301
|
+
}
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
contracts: modules.map(({contractVersion, identity}) => ({contractVersion, identity})),
|
|
306
|
+
input: {id: "semantifold.task037.blocking-tcp", modules, schema: "SemantifoldCapabilityAuthority", schemaVersion: 2}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (identities.size != 1 || ranges.size != 1) {
|
|
310
|
+
invalidFacade("The Task 036 qualification facade closure must resolve one canonical module and version range.")
|
|
311
|
+
}
|
|
312
|
+
const identity = requirements[0].module
|
|
313
|
+
const contractVersion = requirements[0].range
|
|
314
|
+
const contract = resolveStdlibModule(identity, contractVersion)
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
contract: {contractVersion, identity},
|
|
318
|
+
input: {
|
|
319
|
+
capabilities: [{
|
|
320
|
+
failures: contract.failures.map(({name}) => ({name})),
|
|
321
|
+
name: "ResourceProbe",
|
|
322
|
+
operations: contract.operations.map((operation) => ({
|
|
323
|
+
effects: [...operation.effects],
|
|
324
|
+
failures: [...operation.failures],
|
|
325
|
+
name: operation.name,
|
|
326
|
+
parameters: operation.parameters.map((parameter) => ({
|
|
327
|
+
name: parameter.name,
|
|
328
|
+
type: canonicalCapabilityParameterType(parameter.type)
|
|
329
|
+
})),
|
|
330
|
+
resourceFlow: /** @type {import("./semantic/types.js").CapabilityResourceFlowInput} */ ({...operation.resourceFlow}),
|
|
331
|
+
returnType: canonicalCapabilityType(operation.returnType)
|
|
332
|
+
})),
|
|
333
|
+
resources: contract.resources.map(({name}) => ({name}))
|
|
334
|
+
}],
|
|
335
|
+
contractVersion,
|
|
336
|
+
id: identity,
|
|
337
|
+
schema: "SemantifoldCapabilityAuthority",
|
|
338
|
+
schemaVersion: 1
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Converts one registry contract type to a capability-authority input type.
|
|
345
|
+
* @param {string | import("./semantic/stdlib.js").CanonicalDeclarationReference} type - Canonical contract type.
|
|
346
|
+
* @returns {import("./semantic/types.js").FunctionReturnTypeName | {kind: "OwnedResourceType", resource: string | import("./semantic/types.js").CapabilityDeclarationReferenceInput} | {kind: "OptionalType", valueType: import("./semantic/types.js").SemanticTypeName}} Semantic authority type.
|
|
347
|
+
*/
|
|
348
|
+
function canonicalCapabilityType(type) {
|
|
349
|
+
if (typeof type != "string") return {kind: "OwnedResourceType", resource: detachCanonicalReference(type)}
|
|
350
|
+
if (type == "void" || type == "boolean" || type == "integer" || type == "string") return type
|
|
351
|
+
if (type.startsWith("optional:")) return {kind: "OptionalType",
|
|
352
|
+
valueType: /** @type {import("./semantic/types.js").SemanticTypeName} */ (type.slice("optional:".length))}
|
|
353
|
+
return {kind: "OwnedResourceType", resource: type}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Converts a non-void registry parameter type to capability-authority input.
|
|
358
|
+
* @param {string | import("./semantic/stdlib.js").CanonicalDeclarationReference} type - Canonical parameter type.
|
|
359
|
+
* @returns {import("./semantic/types.js").SemanticTypeName | {kind: "OwnedResourceType", resource: string} | {kind: "OptionalType", valueType: import("./semantic/types.js").SemanticTypeName}} Semantic parameter type.
|
|
360
|
+
*/
|
|
361
|
+
function canonicalCapabilityParameterType(type) {
|
|
362
|
+
const converted = canonicalCapabilityType(type)
|
|
363
|
+
|
|
364
|
+
if (converted == "void") invalidFacade("Canonical facade requirement parameters cannot have void type.")
|
|
365
|
+
return /** @type {import("./semantic/types.js").SemanticTypeName | {kind: "OwnedResourceType", resource: string} | {kind: "OptionalType", valueType: import("./semantic/types.js").SemanticTypeName}} */ (converted)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Resolves one dependency identity from a validated registry store.
|
|
370
|
+
* @param {Map<string, Map<string, StdlibFacadeRecord>>} store - Records by language and identity.
|
|
371
|
+
* @param {string} identity - Facade identity.
|
|
372
|
+
* @param {string} language - Source language.
|
|
373
|
+
* @param {string | undefined} range - Compatible range.
|
|
374
|
+
* @param {string} [owner] - Depending facade for diagnostics.
|
|
375
|
+
* @returns {StdlibFacadeRecord} Highest compatible record.
|
|
376
|
+
*/
|
|
377
|
+
function resolveIdentityFromStore(store, identity, language, range, owner) {
|
|
378
|
+
const versions = store.get(`${language}\0${identity}`)
|
|
379
|
+
|
|
380
|
+
if (!versions) {
|
|
381
|
+
invalidFacade(owner ? `Facade '${owner}' depends on unknown facade '${identity}' for '${language}'.` :
|
|
382
|
+
`Unknown facade identity '${identity}' for '${language}'.`)
|
|
383
|
+
}
|
|
384
|
+
return selectFacadeVersion(/** @type {Map<string, StdlibFacadeRecord>} */ (versions), identity, language, range)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Resolves one exact native identity from a validated registry store.
|
|
389
|
+
* @param {Map<string, StdlibFacadeRecord[]>} store - Records by language and native module.
|
|
390
|
+
* @param {string} language - Source language.
|
|
391
|
+
* @param {string} nativeModule - Exact parser-owned native module identity.
|
|
392
|
+
* @param {string} symbol - Exact source-visible symbol.
|
|
393
|
+
* @param {string | undefined} range - Compatible range.
|
|
394
|
+
* @returns {StdlibFacadeRecord} Highest compatible record.
|
|
395
|
+
*/
|
|
396
|
+
function resolveNativeFacadeFromStore(store, language, nativeModule, symbol, range) {
|
|
397
|
+
if (!supportedLanguages.has(language) || typeof nativeModule != "string" || nativeModule.length == 0) {
|
|
398
|
+
unprovedIdentity(language, nativeModule)
|
|
399
|
+
}
|
|
400
|
+
const moduleRecords = store.get(`${language}\0${nativeModule}`)
|
|
401
|
+
|
|
402
|
+
if (!moduleRecords) unprovedIdentity(language, nativeModule)
|
|
403
|
+
const symbolRecords = /** @type {StdlibFacadeRecord[]} */ (moduleRecords).filter((record) => record.nativeModules.some((module) =>
|
|
404
|
+
module.identity == nativeModule && module.symbols.includes(symbol)))
|
|
405
|
+
|
|
406
|
+
if (symbolRecords.length == 0) unsupportedMember(language, nativeModule, symbol)
|
|
407
|
+
const identities = new Set(symbolRecords.map(({identity}) => identity))
|
|
408
|
+
|
|
409
|
+
if (identities.size != 1) invalidFacade(`Native facade identity '${nativeModule}#${symbol}' is ambiguous for '${language}'.`)
|
|
410
|
+
const versions = new Map(symbolRecords.map((record) => [record.version, record]))
|
|
411
|
+
|
|
412
|
+
return selectFacadeVersion(versions, symbolRecords[0].identity, language, range)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Selects the highest facade version satisfying a canonical range.
|
|
417
|
+
* @param {Map<string, StdlibFacadeRecord>} versions - Records by exact version.
|
|
418
|
+
* @param {string} identity - Facade identity.
|
|
419
|
+
* @param {string} language - Source language.
|
|
420
|
+
* @param {string | undefined} range - Compatible range.
|
|
421
|
+
* @returns {StdlibFacadeRecord} Selected record.
|
|
422
|
+
*/
|
|
423
|
+
function selectFacadeVersion(versions, identity, language, range) {
|
|
424
|
+
const parsedRange = range === undefined ? {lower: /** @type {[number, number, number]} */ ([0, 0, 0]), upper: null} :
|
|
425
|
+
parseStdlibVersionRange(range)
|
|
426
|
+
|
|
427
|
+
if (!parsedRange) facadeVersionMalformed(language, String(range))
|
|
428
|
+
/** @type {[number, number, number] | undefined} */
|
|
429
|
+
let selected
|
|
430
|
+
|
|
431
|
+
for (const version of versions.keys()) {
|
|
432
|
+
const parsed = /** @type {[number, number, number]} */ (parseStdlibVersion(version))
|
|
433
|
+
|
|
434
|
+
if (stdlibVersionSatisfies(parsed, parsedRange) && (!selected || compareStdlibVersions(parsed, selected) > 0)) selected = parsed
|
|
435
|
+
}
|
|
436
|
+
if (!selected) facadeVersionIncompatible(language, identity)
|
|
437
|
+
|
|
438
|
+
return /** @type {StdlibFacadeRecord} */ (versions.get(selected.join(".")))
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Validates and detaches one executable facade record.
|
|
443
|
+
* @param {unknown} candidate - Candidate record.
|
|
444
|
+
* @returns {StdlibFacadeRecord} Detached frozen record.
|
|
445
|
+
*/
|
|
446
|
+
function validateFacadeRecord(candidate) {
|
|
447
|
+
if (!isPlainObject(candidate)) invalidFacade("Every facade record must be a plain object.")
|
|
448
|
+
requireKeys(candidate, ["dependencies", "identity", "language", "nativeModules", "publicDeclarations", "requirements",
|
|
449
|
+
"runtimeProfile", "source", "version", "visibility"], "facade record")
|
|
450
|
+
const identity = requireString(candidate.identity, "Facade identity")
|
|
451
|
+
const language = requireString(candidate.language, "Facade language")
|
|
452
|
+
const version = requireString(candidate.version, "Facade version")
|
|
453
|
+
const runtimeProfile = requireString(candidate.runtimeProfile, "Facade runtime profile")
|
|
454
|
+
const visibility = candidate.visibility
|
|
455
|
+
|
|
456
|
+
if (!facadeIdentityPattern.test(identity)) invalidFacade(`Facade identity '${identity}' is invalid.`)
|
|
457
|
+
if (!supportedLanguages.has(language)) invalidFacade(`Facade language '${language}' is outside the adopted cohort.`)
|
|
458
|
+
if (!parseStdlibVersion(version)) invalidFacade(`Facade version '${version}' is invalid.`)
|
|
459
|
+
if (!/^[a-z][a-z0-9.-]*$/u.test(runtimeProfile)) invalidFacade(`Facade runtime profile '${runtimeProfile}' is invalid.`)
|
|
460
|
+
if (visibility != "public" && visibility != "internal") invalidFacade(`Facade '${identity}' has invalid visibility.`)
|
|
461
|
+
const source = validateSource(candidate.source, identity, language)
|
|
462
|
+
const publicDeclarations = validatePublicDeclarations(candidate.publicDeclarations, identity)
|
|
463
|
+
const nativeModules = validateNativeModules(candidate.nativeModules, identity, publicDeclarations)
|
|
464
|
+
const requirements = validateRequirements(candidate.requirements, identity)
|
|
465
|
+
const dependencies = validateDependencies(candidate.dependencies, identity)
|
|
466
|
+
|
|
467
|
+
if (visibility == "public" && (publicDeclarations.length == 0 || nativeModules.length == 0)) {
|
|
468
|
+
invalidFacade(`Public facade '${identity}' requires declarations and native identities.`)
|
|
469
|
+
}
|
|
470
|
+
if (visibility == "internal" && nativeModules.length > 0) invalidFacade(`Internal facade '${identity}' cannot expose native identities.`)
|
|
471
|
+
|
|
472
|
+
return deepFreeze({
|
|
473
|
+
dependencies,
|
|
474
|
+
identity,
|
|
475
|
+
language: /** @type {import("./semantic/types.js").SemanticLanguage} */ (language),
|
|
476
|
+
nativeModules,
|
|
477
|
+
publicDeclarations,
|
|
478
|
+
requirements,
|
|
479
|
+
runtimeProfile,
|
|
480
|
+
source,
|
|
481
|
+
version,
|
|
482
|
+
visibility: /** @type {"internal" | "public"} */ (visibility)
|
|
483
|
+
})
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Validates one compiler-owned executable facade source.
|
|
488
|
+
* @param {unknown} candidate - Candidate source descriptor.
|
|
489
|
+
* @param {string} identity - Owning facade identity.
|
|
490
|
+
* @param {string} language - Facade source language.
|
|
491
|
+
* @returns {{content: string, filename: string, id: string}} Validated source descriptor.
|
|
492
|
+
*/
|
|
493
|
+
function validateSource(candidate, identity, language) {
|
|
494
|
+
if (!isPlainObject(candidate)) invalidFacade(`Facade '${identity}' requires an executable source descriptor.`)
|
|
495
|
+
requireKeys(candidate, ["content", "filename", "id"], `facade '${identity}' source`)
|
|
496
|
+
const content = requireString(candidate.content, `Facade '${identity}' source content`)
|
|
497
|
+
const filename = requireString(candidate.filename, `Facade '${identity}' source filename`)
|
|
498
|
+
const id = requireString(candidate.id, `Facade '${identity}' source module identity`)
|
|
499
|
+
|
|
500
|
+
if (content.length == 0 || !isSafeArtifactPath(filename) || !filename.startsWith(`__semantifold_facades__/${language}/`) ||
|
|
501
|
+
!moduleIdPattern.test(id) || !id.startsWith(`semantifold.facade.${language}.`)) {
|
|
502
|
+
invalidFacade(`Facade '${identity}' has an invalid compiler-owned source descriptor.`)
|
|
503
|
+
}
|
|
504
|
+
return {content, filename, id}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Validates one facade's closed public declaration surface.
|
|
509
|
+
* @param {unknown} candidate - Candidate declarations.
|
|
510
|
+
* @param {string} identity - Owning facade identity.
|
|
511
|
+
* @returns {StdlibFacadePublicDeclaration[]} Validated declarations.
|
|
512
|
+
*/
|
|
513
|
+
function validatePublicDeclarations(candidate, identity) {
|
|
514
|
+
if (!isDenseArray(candidate)) invalidFacade(`Facade '${identity}' public declarations must be a dense array.`)
|
|
515
|
+
const names = new Set()
|
|
516
|
+
return candidate.map((value) => {
|
|
517
|
+
if (!isPlainObject(value)) invalidFacade(`Facade '${identity}' public declarations must be plain objects.`)
|
|
518
|
+
const name = requireString(value.name, `Facade '${identity}' declaration name`)
|
|
519
|
+
|
|
520
|
+
if (!declarationNamePattern.test(name) || names.has(name)) {
|
|
521
|
+
invalidFacade(`Facade '${identity}' has an invalid or duplicate public declaration.`)
|
|
522
|
+
}
|
|
523
|
+
names.add(name)
|
|
524
|
+
if (value.kind == "class") return validatePublicClass(value, identity, name)
|
|
525
|
+
requireKeys(value, ["effects", "failures", "forms", "kind", "name", "ownership", "parameters", "returnType"],
|
|
526
|
+
`facade '${identity}' public declaration`)
|
|
527
|
+
if (value.kind != "function") invalidFacade(`Facade '${identity}' has an invalid public declaration kind.`)
|
|
528
|
+
if (!isDenseArray(value.effects) || !value.effects.every((effect) => effect == "host") || new Set(value.effects).size != value.effects.length ||
|
|
529
|
+
!isDenseArray(value.failures) || !value.failures.every((failure) => typeof failure == "string" && declarationNamePattern.test(failure)) ||
|
|
530
|
+
!isDenseArray(value.forms) || value.forms.length == 0 || !value.forms.every((form) =>
|
|
531
|
+
typeof form == "string" && ["direct-call", "unqualified-call", "receiver-call"].includes(form)) ||
|
|
532
|
+
new Set(value.forms).size != value.forms.length ||
|
|
533
|
+
value.ownership != "not-applicable" ||
|
|
534
|
+
!isDenseArray(value.parameters)) invalidFacade(`Facade '${identity}' declaration '${name}' has an invalid public contract.`)
|
|
535
|
+
const parameters = validateFacadeParameters(value.parameters, identity, name)
|
|
536
|
+
const returnType = requireString(value.returnType, `Facade '${identity}' return type`)
|
|
537
|
+
|
|
538
|
+
if (!isFacadeType(returnType, true)) invalidFacade(`Facade '${identity}' declaration '${name}' has an invalid return type.`)
|
|
539
|
+
return {
|
|
540
|
+
effects: /** @type {string[]} */ ([...value.effects]),
|
|
541
|
+
failures: /** @type {string[]} */ ([...value.failures]),
|
|
542
|
+
forms: /** @type {("direct-call" | "unqualified-call" | "receiver-call")[]} */ ([...value.forms]),
|
|
543
|
+
kind: /** @type {const} */ ("function"),
|
|
544
|
+
name,
|
|
545
|
+
ownership: /** @type {const} */ ("not-applicable"),
|
|
546
|
+
parameters,
|
|
547
|
+
returnType
|
|
548
|
+
}
|
|
549
|
+
})
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Validates the exact native module and symbol identities selecting a facade.
|
|
554
|
+
* @param {unknown} candidate - Candidate native modules.
|
|
555
|
+
* @param {string} identity - Owning facade identity.
|
|
556
|
+
* @param {StdlibFacadePublicDeclaration[]} declarations - Validated public surface.
|
|
557
|
+
* @returns {({identity: string, kind: "module", symbols: string[]} | {forms: ("unqualified-call" | "receiver-call")[], identity: string, kind: "builtin", symbols: string[]})[]} Validated native identities.
|
|
558
|
+
*/
|
|
559
|
+
function validateNativeModules(candidate, identity, declarations) {
|
|
560
|
+
if (!isDenseArray(candidate)) invalidFacade(`Facade '${identity}' native modules must be a dense array.`)
|
|
561
|
+
const modules = new Set()
|
|
562
|
+
const publicNames = new Set(declarations.map(({name}) => name))
|
|
563
|
+
return candidate.map((value) => {
|
|
564
|
+
if (!isPlainObject(value)) invalidFacade(`Facade '${identity}' native modules must be plain objects.`)
|
|
565
|
+
const builtin = value.kind == "builtin"
|
|
566
|
+
|
|
567
|
+
requireKeys(value, builtin ? ["forms", "identity", "kind", "symbols"] : ["identity", "kind", "symbols"],
|
|
568
|
+
`facade '${identity}' native module`)
|
|
569
|
+
const moduleIdentity = requireString(value.identity, `Facade '${identity}' native module identity`)
|
|
570
|
+
|
|
571
|
+
if (value.kind != "module" && value.kind != "builtin" || modules.has(moduleIdentity) ||
|
|
572
|
+
!isDenseArray(value.symbols) || value.symbols.length == 0 ||
|
|
573
|
+
!value.symbols.every((symbol) => typeof symbol == "string" && publicNames.has(symbol)) ||
|
|
574
|
+
new Set(value.symbols).size != value.symbols.length) {
|
|
575
|
+
invalidFacade(`Facade '${identity}' has an invalid native module declaration.`)
|
|
576
|
+
}
|
|
577
|
+
if (builtin && (!isDenseArray(value.forms) || value.forms.length == 0 ||
|
|
578
|
+
!value.forms.every((form) => form == "unqualified-call" || form == "receiver-call") ||
|
|
579
|
+
new Set(value.forms).size != value.forms.length)) invalidFacade(`Facade '${identity}' has invalid builtin forms.`)
|
|
580
|
+
modules.add(moduleIdentity)
|
|
581
|
+
return builtin
|
|
582
|
+
? {forms: /** @type {("unqualified-call" | "receiver-call")[]} */ ([.../** @type {unknown[]} */ (value.forms)]), identity: moduleIdentity,
|
|
583
|
+
kind: /** @type {const} */ ("builtin"), symbols: /** @type {string[]} */ ([...value.symbols])}
|
|
584
|
+
: {identity: moduleIdentity, kind: /** @type {const} */ ("module"), symbols: /** @type {string[]} */ ([...value.symbols])}
|
|
585
|
+
})
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Validates canonical-only facade capability requirements.
|
|
590
|
+
* @param {unknown} candidate - Candidate requirements.
|
|
591
|
+
* @param {string} identity - Owning facade identity.
|
|
592
|
+
* @returns {{module: string, operations: string[], range: string}[]} Validated requirements.
|
|
593
|
+
*/
|
|
594
|
+
function validateRequirements(candidate, identity) {
|
|
595
|
+
if (!isDenseArray(candidate)) invalidFacade(`Facade '${identity}' requirements must be a dense array.`)
|
|
596
|
+
const modules = new Set()
|
|
597
|
+
return candidate.map((value) => {
|
|
598
|
+
if (!isPlainObject(value)) invalidFacade(`Facade '${identity}' requirements must be plain objects.`)
|
|
599
|
+
requireKeys(value, ["module", "operations", "range"], `facade '${identity}' requirement`)
|
|
600
|
+
const module = requireString(value.module, `Facade '${identity}' canonical module`)
|
|
601
|
+
const range = requireString(value.range, `Facade '${identity}' canonical range`)
|
|
602
|
+
|
|
603
|
+
if (modules.has(module) || !parseStdlibVersionRange(range) || !isDenseArray(value.operations) || value.operations.length == 0 ||
|
|
604
|
+
!value.operations.every((operation) => typeof operation == "string" && declarationNamePattern.test(operation)) ||
|
|
605
|
+
new Set(value.operations).size != value.operations.length) invalidFacade(`Facade '${identity}' has an invalid canonical requirement.`)
|
|
606
|
+
const contract = resolveStdlibModule(module, range)
|
|
607
|
+
const declared = new Set(contract.operations.map(({name}) => name))
|
|
608
|
+
|
|
609
|
+
if (!/** @type {string[]} */ (value.operations).every((operation) => declared.has(operation))) {
|
|
610
|
+
invalidFacade(`Facade '${identity}' requires an undeclared canonical operation.`)
|
|
611
|
+
}
|
|
612
|
+
modules.add(module)
|
|
613
|
+
return {module, operations: /** @type {string[]} */ ([...value.operations]), range}
|
|
614
|
+
})
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Validates versioned same-language facade dependencies.
|
|
619
|
+
* @param {unknown} candidate - Candidate dependencies.
|
|
620
|
+
* @param {string} identity - Owning facade identity.
|
|
621
|
+
* @returns {{identity: string, range: string}[]} Validated dependencies.
|
|
622
|
+
*/
|
|
623
|
+
function validateDependencies(candidate, identity) {
|
|
624
|
+
if (!isDenseArray(candidate)) invalidFacade(`Facade '${identity}' dependencies must be a dense array.`)
|
|
625
|
+
const identities = new Set()
|
|
626
|
+
return candidate.map((value) => {
|
|
627
|
+
if (!isPlainObject(value)) invalidFacade(`Facade '${identity}' dependencies must be plain objects.`)
|
|
628
|
+
requireKeys(value, ["identity", "range"], `facade '${identity}' dependency`)
|
|
629
|
+
const dependencyIdentity = requireString(value.identity, `Facade '${identity}' dependency identity`)
|
|
630
|
+
const range = requireString(value.range, `Facade '${identity}' dependency range`)
|
|
631
|
+
|
|
632
|
+
if (!facadeIdentityPattern.test(dependencyIdentity) || dependencyIdentity == identity || identities.has(dependencyIdentity) ||
|
|
633
|
+
!parseStdlibVersionRange(range)) invalidFacade(`Facade '${identity}' has an invalid dependency.`)
|
|
634
|
+
identities.add(dependencyIdentity)
|
|
635
|
+
return {identity: dependencyIdentity, range}
|
|
636
|
+
})
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Builds the bounded original-five qualification facade definitions.
|
|
641
|
+
* @returns {unknown[]} Unvalidated built-in qualification facade definitions.
|
|
642
|
+
*/
|
|
643
|
+
function builtinFacadeRecords() {
|
|
644
|
+
return ["php", "ruby", "javascript", "typescript", "java"].flatMap((language) => builtinLanguageFacades(language))
|
|
645
|
+
.concat(builtinTask037RubyFacades())
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Builds one source language's public, internal, and unreachable qualification facades.
|
|
650
|
+
* @param {string} language - Source language.
|
|
651
|
+
* @returns {unknown[]} Language facade definitions.
|
|
652
|
+
*/
|
|
653
|
+
function builtinLanguageFacades(language) {
|
|
654
|
+
const names = facadeNames(language)
|
|
655
|
+
const base = `semantifold.task036.${language}`
|
|
656
|
+
const sourceBase = `semantifold.facade.${language}`
|
|
657
|
+
const sourceDirectory = `__semantifold_facades__/${language}`
|
|
658
|
+
const probeFilename = language == "java" ? `${sourceDirectory}/semantifold/facade/java/probe/Probe.java` :
|
|
659
|
+
`${sourceDirectory}/probe.${names.extension}`
|
|
660
|
+
const runnerFilename = language == "java" ? `${sourceDirectory}/semantifold/facade/java/proberunner/ProbeRunner.java` :
|
|
661
|
+
`${sourceDirectory}/probe-runner.${names.extension}`
|
|
662
|
+
const unusedFilename = language == "java" ? `${sourceDirectory}/semantifold/facade/java/unused/Unused.java` :
|
|
663
|
+
`${sourceDirectory}/unused.${names.extension}`
|
|
664
|
+
|
|
665
|
+
return [{
|
|
666
|
+
dependencies: [{identity: `${base}.probe-runner`, range: "1"}],
|
|
667
|
+
identity: `${base}.probe`,
|
|
668
|
+
language,
|
|
669
|
+
nativeModules: [{identity: names.nativeModule, kind: "module", symbols: [names.publicName]}],
|
|
670
|
+
publicDeclarations: [publicDeclaration(names.publicName)],
|
|
671
|
+
requirements: [],
|
|
672
|
+
runtimeProfile: `${language}-task036-v1`,
|
|
673
|
+
source: {content: names.probeSource, filename: probeFilename, id: `${sourceBase}.probe`},
|
|
674
|
+
version: "1.0.0",
|
|
675
|
+
visibility: "public"
|
|
676
|
+
}, {
|
|
677
|
+
dependencies: [],
|
|
678
|
+
identity: `${base}.probe-runner`,
|
|
679
|
+
language,
|
|
680
|
+
nativeModules: [],
|
|
681
|
+
publicDeclarations: [],
|
|
682
|
+
requirements: [{module: "semantifold.task034.resource-probe", operations: ["probeEffect", "probeTrace"], range: "1"}],
|
|
683
|
+
runtimeProfile: `${language}-task036-v1`,
|
|
684
|
+
source: {content: names.runnerSource, filename: runnerFilename, id: `${sourceBase}.probe_runner`},
|
|
685
|
+
version: "1.0.0",
|
|
686
|
+
visibility: "internal"
|
|
687
|
+
}, {
|
|
688
|
+
dependencies: [],
|
|
689
|
+
identity: `${base}.unused`,
|
|
690
|
+
language,
|
|
691
|
+
nativeModules: [{identity: names.unusedNativeModule, kind: "module", symbols: [names.unusedName]}],
|
|
692
|
+
publicDeclarations: [publicDeclaration(names.unusedName)],
|
|
693
|
+
requirements: [{module: "semantifold.task034.resource-probe", operations: ["probeTrace"], range: "1"}],
|
|
694
|
+
runtimeProfile: `${language}-task036-v1`,
|
|
695
|
+
source: {content: names.unusedSource, filename: unusedFilename, id: `${sourceBase}.unused`},
|
|
696
|
+
version: "1.0.0",
|
|
697
|
+
visibility: "public"
|
|
698
|
+
}]
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Builds the common bounded qualification function declaration.
|
|
703
|
+
* @param {string} name - Source-visible function name.
|
|
704
|
+
* @returns {StdlibFacadePublicDeclaration} Public facade declaration.
|
|
705
|
+
*/
|
|
706
|
+
function publicDeclaration(name) {
|
|
707
|
+
return {
|
|
708
|
+
effects: ["host"], failures: [], forms: ["direct-call"], kind: "function", name,
|
|
709
|
+
ownership: "not-applicable", parameters: [{name: "label", type: "string"}], returnType: "string"
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Builds the exact Ruby Task 037 socket and output compatibility facades.
|
|
715
|
+
* @returns {unknown[]} Unvalidated facade records.
|
|
716
|
+
*/
|
|
717
|
+
function builtinTask037RubyFacades() {
|
|
718
|
+
return [{
|
|
719
|
+
dependencies: [],
|
|
720
|
+
identity: "semantifold.task037.ruby.socket",
|
|
721
|
+
language: "ruby",
|
|
722
|
+
nativeModules: [{identity: "socket", kind: "module", symbols: ["TCPSocket"]}],
|
|
723
|
+
publicDeclarations: [{
|
|
724
|
+
constructor: {
|
|
725
|
+
effects: ["host"], failures: ["InvalidHost", "InvalidPort", "ConnectionFailure"], ownership: "acquired",
|
|
726
|
+
parameters: [{name: "host", type: "string"}, {name: "port", type: "integer"}]
|
|
727
|
+
},
|
|
728
|
+
forms: ["constructor-call"],
|
|
729
|
+
kind: "class",
|
|
730
|
+
methods: [{
|
|
731
|
+
effects: ["host"], failures: ["ReadFailure", "DecodeFailure", "ResourceClosed"], forms: ["receiver-call"],
|
|
732
|
+
name: "gets", ownership: "borrowed", parameters: [], returnType: "optional:string"
|
|
733
|
+
}, {
|
|
734
|
+
effects: ["host"], failures: ["CloseFailure", "ResourceClosed"], forms: ["receiver-call"],
|
|
735
|
+
name: "close", ownership: "consumed", parameters: [], returnType: "void"
|
|
736
|
+
}],
|
|
737
|
+
name: "TCPSocket",
|
|
738
|
+
ownership: "owned-reference"
|
|
739
|
+
}],
|
|
740
|
+
requirements: [
|
|
741
|
+
{module: "semantifold.socket-client", operations: ["v1_connect"], range: "1"},
|
|
742
|
+
{module: "semantifold.text-stream", operations: ["v1_read_line"], range: "1"},
|
|
743
|
+
{module: "semantifold.resource", operations: ["v1_close"], range: "1"}
|
|
744
|
+
],
|
|
745
|
+
runtimeProfile: "ruby-task037-socket-v1",
|
|
746
|
+
source: {
|
|
747
|
+
content: `module SemantifoldTask037Socket
|
|
748
|
+
class TCPSocket
|
|
749
|
+
# @param host [String]
|
|
750
|
+
# @param port [Integer]
|
|
751
|
+
def initialize(host, port)
|
|
752
|
+
@resource = v1_connect(host, port)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# @return [String?]
|
|
756
|
+
def gets
|
|
757
|
+
return v1_read_line(@resource)
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
# @return [void]
|
|
761
|
+
def close
|
|
762
|
+
v1_close(@resource)
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
`,
|
|
767
|
+
filename: "__semantifold_facades__/ruby/socket.rb",
|
|
768
|
+
id: "semantifold.facade.ruby.socket"
|
|
769
|
+
},
|
|
770
|
+
version: "1.0.0",
|
|
771
|
+
visibility: "public"
|
|
772
|
+
}, {
|
|
773
|
+
dependencies: [],
|
|
774
|
+
identity: "semantifold.task037.ruby.output",
|
|
775
|
+
language: "ruby",
|
|
776
|
+
nativeModules: [{forms: ["unqualified-call", "receiver-call"], identity: "ruby:Kernel", kind: "builtin", symbols: ["puts"]}],
|
|
777
|
+
publicDeclarations: [{
|
|
778
|
+
effects: ["host"], failures: ["WriteFailure"], forms: ["unqualified-call", "receiver-call"], kind: "function",
|
|
779
|
+
name: "puts", ownership: "not-applicable", parameters: [{name: "text", type: "string"}], returnType: "void"
|
|
780
|
+
}],
|
|
781
|
+
requirements: [{module: "semantifold.output", operations: ["v1_write_line"], range: "1"}],
|
|
782
|
+
runtimeProfile: "ruby-task037-output-v1",
|
|
783
|
+
source: {
|
|
784
|
+
content: `module SemantifoldTask037Output
|
|
785
|
+
module_function
|
|
786
|
+
# @param text [String]
|
|
787
|
+
# @return [void]
|
|
788
|
+
def puts(text)
|
|
789
|
+
v1_write_line(text)
|
|
790
|
+
return
|
|
791
|
+
end
|
|
792
|
+
end
|
|
793
|
+
`,
|
|
794
|
+
filename: "__semantifold_facades__/ruby/output.rb",
|
|
795
|
+
id: "semantifold.facade.ruby.output"
|
|
796
|
+
},
|
|
797
|
+
version: "1.0.0",
|
|
798
|
+
visibility: "public"
|
|
799
|
+
}]
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Validates one public facade class descriptor.
|
|
804
|
+
* @param {Record<string, unknown>} value - Candidate class.
|
|
805
|
+
* @param {string} identity - Owning facade.
|
|
806
|
+
* @param {string} name - Validated class name.
|
|
807
|
+
* @returns {StdlibFacadeClassDeclaration} Detached class descriptor.
|
|
808
|
+
*/
|
|
809
|
+
function validatePublicClass(value, identity, name) {
|
|
810
|
+
requireKeys(value, ["constructor", "forms", "kind", "methods", "name", "ownership"],
|
|
811
|
+
`facade '${identity}' public class`)
|
|
812
|
+
if (!isDenseArray(value.forms) || value.forms.length != 1 || value.forms[0] != "constructor-call" ||
|
|
813
|
+
value.ownership != "owned-reference" || !isPlainObject(value.constructor) || !isDenseArray(value.methods)) {
|
|
814
|
+
invalidFacade(`Facade '${identity}' class '${name}' has an invalid public contract.`)
|
|
815
|
+
}
|
|
816
|
+
const constructor = /** @type {Record<string, unknown>} */ (value.constructor)
|
|
817
|
+
|
|
818
|
+
requireKeys(constructor, ["effects", "failures", "ownership", "parameters"], `facade '${identity}' constructor`)
|
|
819
|
+
if (constructor.ownership != "acquired" || !validFacadeEffects(constructor.effects) ||
|
|
820
|
+
!validFacadeFailures(constructor.failures)) invalidFacade(`Facade '${identity}' class '${name}' has an invalid constructor.`)
|
|
821
|
+
const parameters = validateFacadeParameters(constructor.parameters, identity, `${name}.new`)
|
|
822
|
+
const methodNames = new Set()
|
|
823
|
+
const methods = value.methods.map((method) => {
|
|
824
|
+
if (!isPlainObject(method)) invalidFacade(`Facade '${identity}' class '${name}' has an invalid method.`)
|
|
825
|
+
requireKeys(method, ["effects", "failures", "forms", "name", "ownership", "parameters", "returnType"],
|
|
826
|
+
`facade '${identity}' class method`)
|
|
827
|
+
const methodName = requireString(method.name, `Facade '${identity}' method name`)
|
|
828
|
+
const returnType = requireString(method.returnType, `Facade '${identity}' method return type`)
|
|
829
|
+
|
|
830
|
+
if (!declarationNamePattern.test(methodName) || methodNames.has(methodName) || !validFacadeEffects(method.effects) ||
|
|
831
|
+
!validFacadeFailures(method.failures) || !isDenseArray(method.forms) || method.forms.length != 1 ||
|
|
832
|
+
method.forms[0] != "receiver-call" || method.ownership != "borrowed" && method.ownership != "consumed" ||
|
|
833
|
+
!isFacadeType(returnType, true)) invalidFacade(`Facade '${identity}' class '${name}' has an invalid method.`)
|
|
834
|
+
methodNames.add(methodName)
|
|
835
|
+
return {
|
|
836
|
+
effects: /** @type {string[]} */ ([.../** @type {unknown[]} */ (method.effects)]),
|
|
837
|
+
failures: /** @type {string[]} */ ([.../** @type {unknown[]} */ (method.failures)]),
|
|
838
|
+
forms: /** @type {["receiver-call"]} */ (["receiver-call"]),
|
|
839
|
+
name: methodName,
|
|
840
|
+
ownership: /** @type {"borrowed" | "consumed"} */ (method.ownership),
|
|
841
|
+
parameters: validateFacadeParameters(method.parameters, identity, `${name}.${methodName}`),
|
|
842
|
+
returnType
|
|
843
|
+
}
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
return {
|
|
847
|
+
constructor: {
|
|
848
|
+
effects: /** @type {string[]} */ ([.../** @type {unknown[]} */ (constructor.effects)]),
|
|
849
|
+
failures: /** @type {string[]} */ ([.../** @type {unknown[]} */ (constructor.failures)]),
|
|
850
|
+
ownership: "acquired",
|
|
851
|
+
parameters
|
|
852
|
+
},
|
|
853
|
+
forms: ["constructor-call"],
|
|
854
|
+
kind: "class",
|
|
855
|
+
methods,
|
|
856
|
+
name,
|
|
857
|
+
ownership: "owned-reference"
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* Validates facade parameters shared by functions, constructors, and methods.
|
|
863
|
+
* @param {unknown} candidate - Candidate parameters.
|
|
864
|
+
* @param {string} identity - Owning facade.
|
|
865
|
+
* @param {string} callable - Callable name.
|
|
866
|
+
* @returns {{name: string, type: string}[]} Detached parameters.
|
|
867
|
+
*/
|
|
868
|
+
function validateFacadeParameters(candidate, identity, callable) {
|
|
869
|
+
if (!isDenseArray(candidate)) invalidFacade(`Facade '${identity}' declaration '${callable}' has invalid parameters.`)
|
|
870
|
+
const names = new Set()
|
|
871
|
+
|
|
872
|
+
return candidate.map((parameter) => {
|
|
873
|
+
if (!isPlainObject(parameter)) invalidFacade(`Facade '${identity}' declaration '${callable}' has an invalid parameter.`)
|
|
874
|
+
requireKeys(parameter, ["name", "type"], `facade '${identity}' declaration parameter`)
|
|
875
|
+
const name = requireString(parameter.name, `Facade '${identity}' parameter name`)
|
|
876
|
+
const type = requireString(parameter.type, `Facade '${identity}' parameter type`)
|
|
877
|
+
|
|
878
|
+
if (!declarationNamePattern.test(name) || names.has(name) || !isFacadeType(type, false)) {
|
|
879
|
+
invalidFacade(`Facade '${identity}' declaration '${callable}' has an invalid parameter.`)
|
|
880
|
+
}
|
|
881
|
+
names.add(name)
|
|
882
|
+
return {name, type}
|
|
883
|
+
})
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* Checks one facade effect list.
|
|
888
|
+
* @param {unknown} candidate - Candidate effects.
|
|
889
|
+
* @returns {boolean} Whether effects are exact.
|
|
890
|
+
*/
|
|
891
|
+
function validFacadeEffects(candidate) {
|
|
892
|
+
return isDenseArray(candidate) && candidate.every((effect) => effect == "host") && new Set(candidate).size == candidate.length
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/**
|
|
896
|
+
* Checks one facade failure list.
|
|
897
|
+
* @param {unknown} candidate - Candidate failures.
|
|
898
|
+
* @returns {candidate is string[]} Whether failures are exact.
|
|
899
|
+
*/
|
|
900
|
+
function validFacadeFailures(candidate) {
|
|
901
|
+
return isDenseArray(candidate) && candidate.every((failure) => typeof failure == "string" && declarationNamePattern.test(failure)) &&
|
|
902
|
+
new Set(candidate).size == candidate.length
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Checks one facade type spelling.
|
|
907
|
+
* @param {string} type - Candidate type.
|
|
908
|
+
* @param {boolean} allowVoid - Whether void is valid in this position.
|
|
909
|
+
* @returns {boolean} Whether the type is canonical.
|
|
910
|
+
*/
|
|
911
|
+
function isFacadeType(type, allowVoid) {
|
|
912
|
+
if (canonicalTypes.has(type)) return allowVoid || type != "void"
|
|
913
|
+
const optional = /^optional:(boolean|integer|string)$/u.exec(type)
|
|
914
|
+
|
|
915
|
+
return optional !== null
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Detaches one descriptor for the public program record.
|
|
920
|
+
* @param {StdlibFacadePublicDeclaration} declaration - Registry declaration.
|
|
921
|
+
* @returns {StdlibFacadePublicDeclaration} Detached declaration.
|
|
922
|
+
*/
|
|
923
|
+
function detachPublicDeclaration(declaration) {
|
|
924
|
+
if (declaration.kind == "function") return {...declaration, effects: [...declaration.effects], failures: [...declaration.failures],
|
|
925
|
+
forms: [...declaration.forms], parameters: declaration.parameters.map((parameter) => ({...parameter}))}
|
|
926
|
+
return {...declaration,
|
|
927
|
+
constructor: {...declaration.constructor, effects: [...declaration.constructor.effects], failures: [...declaration.constructor.failures],
|
|
928
|
+
parameters: declaration.constructor.parameters.map((parameter) => ({...parameter}))},
|
|
929
|
+
forms: [...declaration.forms],
|
|
930
|
+
methods: declaration.methods.map((method) => ({...method, effects: [...method.effects], failures: [...method.failures],
|
|
931
|
+
forms: [...method.forms], parameters: method.parameters.map((parameter) => ({...parameter}))}))}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Detaches a local or dependency-qualified contract reference.
|
|
936
|
+
* @param {string | import("./semantic/stdlib.js").CanonicalDeclarationReference} reference - Contract reference.
|
|
937
|
+
* @returns {string | import("./semantic/types.js").CapabilityDeclarationReferenceInput} Detached reference.
|
|
938
|
+
*/
|
|
939
|
+
function detachCanonicalReference(reference) {
|
|
940
|
+
return typeof reference == "string" ? reference : {module: reference.module, name: reference.name}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Detaches a canonical resource flow for authority construction.
|
|
945
|
+
* @param {object} flow - Canonical resource flow.
|
|
946
|
+
* @returns {import("./semantic/types.js").CapabilityResourceFlowInput} Detached flow.
|
|
947
|
+
*/
|
|
948
|
+
function detachResourceFlow(flow) {
|
|
949
|
+
const candidate = /** @type {Record<string, unknown>} */ (flow)
|
|
950
|
+
|
|
951
|
+
if (candidate.kind == "none") return {kind: "none"}
|
|
952
|
+
if (candidate.kind == "acquire") return {kind: "acquire", resource: detachCanonicalReference(
|
|
953
|
+
/** @type {string | import("./semantic/stdlib.js").CanonicalDeclarationReference} */ (candidate.resource))}
|
|
954
|
+
return {
|
|
955
|
+
kind: /** @type {"borrow" | "close"} */ (candidate.kind),
|
|
956
|
+
parameterIndex: /** @type {number} */ (candidate.parameterIndex),
|
|
957
|
+
terminalFailure: detachCanonicalReference(
|
|
958
|
+
/** @type {string | import("./semantic/stdlib.js").CanonicalDeclarationReference} */ (candidate.terminalFailure))
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Maps one canonical module identity to its closed capability name.
|
|
964
|
+
* @param {string} identity - Canonical identity.
|
|
965
|
+
* @returns {string} Capability name.
|
|
966
|
+
*/
|
|
967
|
+
function canonicalCapabilityName(identity) {
|
|
968
|
+
/** @type {Readonly<Record<string, string>>} */
|
|
969
|
+
const names = {
|
|
970
|
+
"semantifold.output": "Output",
|
|
971
|
+
"semantifold.resource": "Resource",
|
|
972
|
+
"semantifold.socket-client": "SocketClient",
|
|
973
|
+
"semantifold.task034.resource-probe": "ResourceProbe",
|
|
974
|
+
"semantifold.text-stream": "TextStream"
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
return names[identity] ?? invalidFacade(`Facade requirements name unknown canonical module '${identity}'.`)
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Builds executable source and native identity spellings for one original-five language.
|
|
982
|
+
* @param {string} language - Source language.
|
|
983
|
+
* @returns {FacadeSourceNames} Facade source definitions.
|
|
984
|
+
*/
|
|
985
|
+
function facadeNames(language) {
|
|
986
|
+
if (language == "php") return {
|
|
987
|
+
extension: "php", nativeModule: "Semantifold\\Task036\\Probe", publicName: "compatibility_probe",
|
|
988
|
+
unusedName: "unused_probe", unusedNativeModule: "Semantifold\\Task036\\Unused",
|
|
989
|
+
probeSource: `<?php
|
|
990
|
+
declare(strict_types=1);
|
|
991
|
+
namespace Semantifold\\Facade\\Php\\Probe;
|
|
992
|
+
use function Semantifold\\Facade\\Php\\ProbeRunner\\run_compatibility_probe;
|
|
993
|
+
require_once __DIR__ . "/probe-runner.php";
|
|
994
|
+
function compatibility_probe(string $label): string { return run_compatibility_probe($label); }
|
|
995
|
+
`,
|
|
996
|
+
runnerSource: `<?php
|
|
997
|
+
declare(strict_types=1);
|
|
998
|
+
namespace Semantifold\\Facade\\Php\\ProbeRunner;
|
|
999
|
+
function run_compatibility_probe(string $label): string {
|
|
1000
|
+
try {
|
|
1001
|
+
/**
|
|
1002
|
+
* @var int $effect
|
|
1003
|
+
* @semantifold-immutable
|
|
1004
|
+
*/
|
|
1005
|
+
$effect = probeEffect($label, 1, false);
|
|
1006
|
+
return probeTrace();
|
|
1007
|
+
}
|
|
1008
|
+
catch (ProbeOperationFailure $error) { return $error->getMessage(); }
|
|
1009
|
+
}
|
|
1010
|
+
`,
|
|
1011
|
+
unusedSource: `<?php
|
|
1012
|
+
declare(strict_types=1);
|
|
1013
|
+
namespace Semantifold\\Facade\\Php\\Unused;
|
|
1014
|
+
function unused_probe(string $label): string { return probeTrace(); }
|
|
1015
|
+
`
|
|
1016
|
+
}
|
|
1017
|
+
if (language == "ruby") return {
|
|
1018
|
+
extension: "rb", nativeModule: "semantifold/task036/probe", publicName: "compatibility_probe",
|
|
1019
|
+
unusedName: "unused_probe", unusedNativeModule: "semantifold/task036/unused",
|
|
1020
|
+
probeSource: `require_relative "probe-runner"
|
|
1021
|
+
module SemantifoldTask036Probe
|
|
1022
|
+
module_function
|
|
1023
|
+
# @param label [String]
|
|
1024
|
+
# @return [String]
|
|
1025
|
+
def compatibility_probe(label)
|
|
1026
|
+
return SemantifoldTask036ProbeRunner.run_compatibility_probe(label)
|
|
1027
|
+
end
|
|
1028
|
+
end
|
|
1029
|
+
`,
|
|
1030
|
+
runnerSource: `module SemantifoldTask036ProbeRunner
|
|
1031
|
+
module_function
|
|
1032
|
+
# @param label [String]
|
|
1033
|
+
# @return [String]
|
|
1034
|
+
def run_compatibility_probe(label)
|
|
1035
|
+
begin
|
|
1036
|
+
# @type [Integer]
|
|
1037
|
+
# @semantifold-immutable
|
|
1038
|
+
effect = probeEffect(label, 1, false)
|
|
1039
|
+
return probeTrace
|
|
1040
|
+
rescue ProbeOperationFailure => error
|
|
1041
|
+
return error.message
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
end
|
|
1045
|
+
`,
|
|
1046
|
+
unusedSource: `module SemantifoldTask036Unused
|
|
1047
|
+
module_function
|
|
1048
|
+
# @param label [String]
|
|
1049
|
+
# @return [String]
|
|
1050
|
+
def unused_probe(label)
|
|
1051
|
+
return probeTrace
|
|
1052
|
+
end
|
|
1053
|
+
end
|
|
1054
|
+
`
|
|
1055
|
+
}
|
|
1056
|
+
if (language == "java") return {
|
|
1057
|
+
extension: "java", nativeModule: "semantifold.task036.Probe", publicName: "compatibilityProbe",
|
|
1058
|
+
unusedName: "unusedProbe", unusedNativeModule: "semantifold.task036.Unused",
|
|
1059
|
+
probeSource: `package semantifold.facade.java.probe;
|
|
1060
|
+
import semantifold.facade.java.proberunner.ProbeRunner;
|
|
1061
|
+
public final class Probe {
|
|
1062
|
+
public static String compatibilityProbe(String label) { return ProbeRunner.runCompatibilityProbe(label); }
|
|
1063
|
+
}
|
|
1064
|
+
`,
|
|
1065
|
+
runnerSource: `package semantifold.facade.java.proberunner;
|
|
1066
|
+
public final class ProbeRunner {
|
|
1067
|
+
public static String runCompatibilityProbe(String label) {
|
|
1068
|
+
try { final int effect = probeEffect(label, 1, false); return probeTrace(); }
|
|
1069
|
+
catch (ProbeOperationFailure error) { return error.getMessage(); }
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
`,
|
|
1073
|
+
unusedSource: `package semantifold.facade.java.unused;
|
|
1074
|
+
public final class Unused {
|
|
1075
|
+
public static String unusedProbe(String label) { return probeTrace(); }
|
|
1076
|
+
}
|
|
1077
|
+
`
|
|
1078
|
+
}
|
|
1079
|
+
const typed = language == "typescript"
|
|
1080
|
+
const extension = typed ? "ts" : "js"
|
|
1081
|
+
const parameter = typed ? "label: string" : "label"
|
|
1082
|
+
const result = typed ? ": string" : ""
|
|
1083
|
+
const documentation = typed ? "" : `/**
|
|
1084
|
+
* @param {string} label
|
|
1085
|
+
* @returns {string}
|
|
1086
|
+
*/
|
|
1087
|
+
`
|
|
1088
|
+
|
|
1089
|
+
return {
|
|
1090
|
+
extension, nativeModule: "semantifold:task036/probe", publicName: "compatibilityProbe",
|
|
1091
|
+
unusedName: "unusedProbe", unusedNativeModule: "semantifold:task036/unused",
|
|
1092
|
+
probeSource: `import {runCompatibilityProbe} from "./probe-runner.js"
|
|
1093
|
+
${documentation}export function compatibilityProbe(${parameter})${result} { return runCompatibilityProbe(label) }
|
|
1094
|
+
`,
|
|
1095
|
+
runnerSource: `${documentation}export function runCompatibilityProbe(${parameter})${result} {
|
|
1096
|
+
try { ${typed ? "const effect: number" : "/** @type {number} */ const effect"} = probeEffect(label, 1, false); return probeTrace() }
|
|
1097
|
+
catch (error) { if (!(error instanceof ProbeOperationFailure)) { throw error } return error.message }
|
|
1098
|
+
}
|
|
1099
|
+
`,
|
|
1100
|
+
unusedSource: `${documentation}export function unusedProbe(${parameter})${result} { return probeTrace() }
|
|
1101
|
+
`
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Requires a closed exact key set.
|
|
1107
|
+
* @param {Record<string, unknown>} value - Plain candidate object.
|
|
1108
|
+
* @param {string[]} keys - Expected keys.
|
|
1109
|
+
* @param {string} subject - Diagnostic subject.
|
|
1110
|
+
* @returns {void}
|
|
1111
|
+
*/
|
|
1112
|
+
function requireKeys(value, keys, subject) {
|
|
1113
|
+
if (Object.keys(value).sort().join(",") != [...keys].sort().join(",")) invalidFacade(`Invalid ${subject} fields.`)
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Requires one non-empty string.
|
|
1118
|
+
* @param {unknown} value - Candidate value.
|
|
1119
|
+
* @param {string} subject - Diagnostic subject.
|
|
1120
|
+
* @returns {string} Validated string.
|
|
1121
|
+
*/
|
|
1122
|
+
function requireString(value, subject) {
|
|
1123
|
+
if (typeof value != "string" || value.length == 0) invalidFacade(`${subject} must be a non-empty string.`)
|
|
1124
|
+
return /** @type {string} */ (value)
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* Checks for an ordinary object with no custom prototype.
|
|
1129
|
+
* @param {unknown} value - Candidate value.
|
|
1130
|
+
* @returns {value is Record<string, unknown>} Whether the candidate is plain.
|
|
1131
|
+
*/
|
|
1132
|
+
function isPlainObject(value) {
|
|
1133
|
+
return value !== null && typeof value == "object" && !Array.isArray(value) && Object.getPrototypeOf(value) == Object.prototype
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Recursively freezes one detached facade registry value.
|
|
1138
|
+
* @template {object} T
|
|
1139
|
+
* @param {T} value - Detached object.
|
|
1140
|
+
* @returns {Readonly<T>} Frozen value.
|
|
1141
|
+
*/
|
|
1142
|
+
function deepFreeze(value) {
|
|
1143
|
+
for (const child of Object.values(value)) if (child && typeof child == "object" && !Object.isFrozen(child)) deepFreeze(child)
|
|
1144
|
+
return Object.freeze(value)
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Throws a stable invalid-registry diagnostic.
|
|
1149
|
+
* @param {string} message - Failure detail.
|
|
1150
|
+
* @returns {never} Always throws.
|
|
1151
|
+
*/
|
|
1152
|
+
function invalidFacade(message) {
|
|
1153
|
+
throw new SemantifoldDiagnostic({code: "STDLIB_FACADE_INVALID", language: "stdlib", message})
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
/**
|
|
1157
|
+
* Throws when parser evidence does not name a registered native module.
|
|
1158
|
+
* @param {string} language - Source language.
|
|
1159
|
+
* @param {unknown} nativeModule - Unproved module identity.
|
|
1160
|
+
* @returns {never} Always throws.
|
|
1161
|
+
*/
|
|
1162
|
+
function unprovedIdentity(language, nativeModule) {
|
|
1163
|
+
throw new SemantifoldDiagnostic({
|
|
1164
|
+
code: "STDLIB_FACADE_IDENTITY_UNPROVED",
|
|
1165
|
+
language: supportedLanguages.has(language) ? language : "stdlib",
|
|
1166
|
+
message: `Native standard-library module '${String(nativeModule)}' is not a registered '${language}' facade identity.`
|
|
1167
|
+
})
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* Throws when a native module member is outside its public facade surface.
|
|
1172
|
+
* @param {string} language - Source language.
|
|
1173
|
+
* @param {string} nativeModule - Exact native module.
|
|
1174
|
+
* @param {string} symbol - Unsupported member.
|
|
1175
|
+
* @returns {never} Always throws.
|
|
1176
|
+
*/
|
|
1177
|
+
function unsupportedMember(language, nativeModule, symbol) {
|
|
1178
|
+
throw new SemantifoldDiagnostic({
|
|
1179
|
+
code: "STDLIB_FACADE_MEMBER_UNSUPPORTED",
|
|
1180
|
+
language,
|
|
1181
|
+
message: `Native standard-library symbol '${nativeModule}#${symbol}' is outside the registered facade surface.`
|
|
1182
|
+
})
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
/**
|
|
1186
|
+
* Throws for a malformed facade version range.
|
|
1187
|
+
* @param {string} language - Source language.
|
|
1188
|
+
* @param {string} range - Malformed range.
|
|
1189
|
+
* @returns {never} Always throws.
|
|
1190
|
+
*/
|
|
1191
|
+
function facadeVersionMalformed(language, range) {
|
|
1192
|
+
throw new SemantifoldDiagnostic({
|
|
1193
|
+
code: "STDLIB_FACADE_VERSION_MALFORMED", language,
|
|
1194
|
+
message: `Facade version range '${range}' is not canonical.`
|
|
1195
|
+
})
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Throws when no registered facade version satisfies a range.
|
|
1200
|
+
* @param {string} language - Source language.
|
|
1201
|
+
* @param {string} identity - Facade identity.
|
|
1202
|
+
* @returns {never} Always throws.
|
|
1203
|
+
*/
|
|
1204
|
+
function facadeVersionIncompatible(language, identity) {
|
|
1205
|
+
throw new SemantifoldDiagnostic({
|
|
1206
|
+
code: "STDLIB_FACADE_VERSION_INCOMPATIBLE", language,
|
|
1207
|
+
message: `No registered version of facade '${identity}' satisfies the required compatibility range.`
|
|
1208
|
+
})
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
export const stdlibFacadeRegistry = createStdlibFacadeRegistry()
|