semantifold 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -15
- package/build/index.d.ts +48 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +57 -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/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 +154 -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 +23 -0
- package/build/src/backends/kotlin.d.ts.map +1 -0
- package/build/src/backends/kotlin.js +136 -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 +81 -0
- package/build/src/backends/program.d.ts.map +1 -0
- package/build/src/backends/program.js +1308 -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 +2158 -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 +235 -4
- package/build/src/backends/writer.d.ts.map +1 -1
- package/build/src/backends/writer.js +468 -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 +167 -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 +2952 -202
- package/build/src/semantic/types.d.ts.map +1 -1
- package/build/src/semantic/types.js +688 -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/architecture.md +45 -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 +231 -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 +15 -7
- package/docs/standard-library-portability.md +39 -8
- package/docs/swift.md +44 -0
- package/docs/testing.md +366 -4
- package/docs/webassembly.md +52 -0
- package/index.js +63 -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/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 +160 -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 +141 -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 +1407 -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 +2304 -124
- 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 +520 -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 +172 -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 +765 -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
package/src/artifact-path.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {hasOnlyUnicodeScalars} from "./semantic/scalars.js"
|
|
4
4
|
|
|
5
5
|
const lineTerminatorPattern = /[\n\r\u2028\u2029]/u
|
|
6
|
+
const portableArtifactComponentPattern = /^[A-Za-z0-9._-]+$/u
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Validates filename metadata without imposing artifact-set path semantics.
|
|
@@ -14,11 +15,11 @@ export function isValidFilenameMetadata(value) {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* Validates a safe relative POSIX
|
|
18
|
+
* Validates a safe relative POSIX source path while retaining Unicode filename metadata.
|
|
18
19
|
* @param {unknown} value - Candidate path.
|
|
19
20
|
* @returns {value is string} Whether the value is safe.
|
|
20
21
|
*/
|
|
21
|
-
export function
|
|
22
|
+
export function isSafeSourcePath(value) {
|
|
22
23
|
if (typeof value != "string" || value.length == 0 || value.includes("\\") || value.includes("\0") ||
|
|
23
24
|
!hasOnlyUnicodeScalars(value)) return false
|
|
24
25
|
if (value.startsWith("/") || /^[A-Za-z]:/u.test(value)) return false
|
|
@@ -32,3 +33,47 @@ export function isSafeArtifactPath(value) {
|
|
|
32
33
|
return codePoint != undefined && codePoint > 31 && codePoint != 127
|
|
33
34
|
}))
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validates a safe portable artifact/resource path in the closed ASCII comparison domain.
|
|
39
|
+
* @param {unknown} value - Candidate path.
|
|
40
|
+
* @returns {value is string} Whether the value is safe and portably comparable.
|
|
41
|
+
*/
|
|
42
|
+
export function isSafeArtifactPath(value) {
|
|
43
|
+
return isSafeSourcePath(value) && value.split("/").every(part => portableArtifactComponentPattern.test(part))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Produces a conservative portable comparison key for a validated artifact path.
|
|
48
|
+
* @param {string} value - Safe relative POSIX path.
|
|
49
|
+
* @returns {string} Complete ASCII case-fold key.
|
|
50
|
+
*/
|
|
51
|
+
export function portableArtifactPathKey(value) {
|
|
52
|
+
return value.toLowerCase()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Finds the first unsafe, duplicate, portable case-fold, or file/directory-prefix conflict.
|
|
57
|
+
* @param {readonly string[]} paths - Ordered candidate artifact paths.
|
|
58
|
+
* @returns {{kind: "case-fold" | "duplicate" | "prefix" | "unsafe", path: string, other?: string} | null} First conflict.
|
|
59
|
+
*/
|
|
60
|
+
export function findPortableArtifactPathConflict(paths) {
|
|
61
|
+
/** @type {{key: string, path: string}[]} */
|
|
62
|
+
const accepted = []
|
|
63
|
+
|
|
64
|
+
for (const path of paths) {
|
|
65
|
+
if (!isSafeArtifactPath(path)) return {kind: "unsafe", path: String(path)}
|
|
66
|
+
const key = portableArtifactPathKey(path)
|
|
67
|
+
|
|
68
|
+
for (const previous of accepted) {
|
|
69
|
+
if (path == previous.path) return {kind: "duplicate", other: previous.path, path}
|
|
70
|
+
if (key == previous.key) return {kind: "case-fold", other: previous.path, path}
|
|
71
|
+
if (key.startsWith(`${previous.key}/`) || previous.key.startsWith(`${key}/`)) {
|
|
72
|
+
return {kind: "prefix", other: previous.path, path}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
accepted.push({key, path})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null
|
|
79
|
+
}
|
package/src/artifacts.js
CHANGED
|
@@ -27,6 +27,9 @@ export function createGeneratedArtifactSet(candidate) {
|
|
|
27
27
|
invalidArtifactSet("Artifact set requires a non-empty ordered artifact array.", candidate.target)
|
|
28
28
|
}
|
|
29
29
|
const target = candidate.target
|
|
30
|
+
const metadata = candidate.metadata === undefined
|
|
31
|
+
? undefined
|
|
32
|
+
: snapshotMetadataObject(candidate.metadata, target)
|
|
30
33
|
|
|
31
34
|
const paths = new Set()
|
|
32
35
|
const directoryPaths = new Set()
|
|
@@ -102,6 +105,7 @@ export function createGeneratedArtifactSet(candidate) {
|
|
|
102
105
|
return Object.freeze({
|
|
103
106
|
artifacts: Object.freeze(artifacts),
|
|
104
107
|
entry: entryPaths[0],
|
|
108
|
+
...(metadata === undefined ? {} : {metadata}),
|
|
105
109
|
schema: /** @type {const} */ ("GeneratedArtifactSet"),
|
|
106
110
|
target,
|
|
107
111
|
version: /** @type {const} */ (1)
|
|
@@ -113,6 +117,69 @@ export function createGeneratedArtifactSet(candidate) {
|
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Validates target-specific metadata as detached, immutable JSON.
|
|
122
|
+
* @param {unknown} value - Metadata candidate.
|
|
123
|
+
* @param {string} target - Artifact target.
|
|
124
|
+
* @returns {Readonly<Record<string, unknown>>} Metadata snapshot.
|
|
125
|
+
*/
|
|
126
|
+
function snapshotMetadataObject(value, target) {
|
|
127
|
+
if (!isPlainObject(value)) invalidArtifactSet("Artifact-set metadata must be a plain JSON object.", target)
|
|
128
|
+
|
|
129
|
+
return /** @type {Readonly<Record<string, unknown>>} */ (
|
|
130
|
+
deepFreeze(snapshotMetadataValue(value, target, new WeakSet())))
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Recursively snapshots a JSON metadata value without retaining caller objects.
|
|
135
|
+
* @param {unknown} value - JSON candidate.
|
|
136
|
+
* @param {string} target - Artifact target.
|
|
137
|
+
* @param {WeakSet<object>} ancestors - Active object path for cycle rejection.
|
|
138
|
+
* @returns {unknown} Detached JSON value.
|
|
139
|
+
*/
|
|
140
|
+
function snapshotMetadataValue(value, target, ancestors) {
|
|
141
|
+
if (value === null || typeof value == "boolean") return value
|
|
142
|
+
if (typeof value == "string") {
|
|
143
|
+
if (!hasOnlyUnicodeScalars(value)) invalidArtifactSet("Artifact-set metadata contains a lone Unicode surrogate.", target)
|
|
144
|
+
|
|
145
|
+
return value
|
|
146
|
+
}
|
|
147
|
+
if (typeof value == "number") {
|
|
148
|
+
if (!Number.isFinite(value)) invalidArtifactSet("Artifact-set metadata numbers must be finite.", target)
|
|
149
|
+
|
|
150
|
+
return value
|
|
151
|
+
}
|
|
152
|
+
if (typeof value != "object") invalidArtifactSet("Artifact-set metadata must contain only JSON values.", target)
|
|
153
|
+
if (ancestors.has(value)) invalidArtifactSet("Artifact-set metadata must not contain cycles.", target)
|
|
154
|
+
ancestors.add(value)
|
|
155
|
+
|
|
156
|
+
if (Array.isArray(value)) {
|
|
157
|
+
if (!isDenseArray(value)) invalidArtifactSet("Artifact-set metadata arrays must be dense.", target)
|
|
158
|
+
/** @type {unknown[]} */
|
|
159
|
+
const result = []
|
|
160
|
+
|
|
161
|
+
for (let index = 0; index < value.length; index += 1) result.push(snapshotMetadataValue(value[index], target, ancestors))
|
|
162
|
+
ancestors.delete(value)
|
|
163
|
+
|
|
164
|
+
return result
|
|
165
|
+
}
|
|
166
|
+
if (!isPlainObject(value)) invalidArtifactSet("Artifact-set metadata must contain only plain JSON objects.", target)
|
|
167
|
+
/** @type {Record<string, unknown>} */
|
|
168
|
+
const result = {}
|
|
169
|
+
|
|
170
|
+
for (const key of Object.keys(value).sort()) {
|
|
171
|
+
Object.defineProperty(result, key, {
|
|
172
|
+
configurable: true,
|
|
173
|
+
enumerable: true,
|
|
174
|
+
value: snapshotMetadataValue(value[key], target, ancestors),
|
|
175
|
+
writable: true
|
|
176
|
+
})
|
|
177
|
+
}
|
|
178
|
+
ancestors.delete(value)
|
|
179
|
+
|
|
180
|
+
return result
|
|
181
|
+
}
|
|
182
|
+
|
|
116
183
|
/**
|
|
117
184
|
* Validates artifact-level text, byte, or synthetic provenance.
|
|
118
185
|
* @param {unknown} value - Provenance candidate.
|
|
@@ -73,7 +73,12 @@ export function validateCMemory(module) {
|
|
|
73
73
|
|
|
74
74
|
for (const name of lengths.keys()) lengths.set(name, left.get(name) === right.get(name) ? left.get(name) : undefined)
|
|
75
75
|
arena.bytes = leftArena.bytes < rightArena.bytes ? leftArena.bytes : rightArena.bytes
|
|
76
|
-
} else
|
|
76
|
+
} else if (statement.kind == "ExpressionStatement" || statement.kind == "PrintStatement" ||
|
|
77
|
+
statement.kind == "ReturnStatement") {
|
|
78
|
+
const expression = statement.expression
|
|
79
|
+
|
|
80
|
+
if (expression) size(expression, lengths, arena)
|
|
81
|
+
}
|
|
77
82
|
}
|
|
78
83
|
return lengths
|
|
79
84
|
}
|
|
@@ -51,7 +51,12 @@ class CppValueValidator {
|
|
|
51
51
|
const right = statement.alternate ? this.block(statement.alternate, sizes) : sizes
|
|
52
52
|
|
|
53
53
|
for (const name of sizes.keys()) sizes.set(name, left.get(name) === right.get(name) ? left.get(name) : undefined)
|
|
54
|
-
} else
|
|
54
|
+
} else if (statement.kind == "ExpressionStatement" || statement.kind == "PrintStatement" ||
|
|
55
|
+
statement.kind == "ReturnStatement") {
|
|
56
|
+
const expression = statement.expression
|
|
57
|
+
|
|
58
|
+
if (expression) this.size(expression, sizes)
|
|
59
|
+
}
|
|
55
60
|
}
|
|
56
61
|
return sizes
|
|
57
62
|
}
|
package/src/backends/csharp.js
CHANGED
|
@@ -168,8 +168,10 @@ function emitStatement(writer, statement, indent, path) {
|
|
|
168
168
|
if (statement.kind == "LocalDeclaration" || statement.kind == "AssignmentStatement") {
|
|
169
169
|
return emitLocal(writer, statement, indent, path)
|
|
170
170
|
}
|
|
171
|
+
if (statement.kind == "ExpressionStatement") throw new TypeError("C# Task 005 expression statement reached emission.")
|
|
171
172
|
writer.synthetic(indent, "indentation", [statement], [path])
|
|
172
173
|
if (statement.kind == "ReturnStatement") {
|
|
174
|
+
if (!statement.expression) throw new TypeError("C# bare return reached emission.")
|
|
173
175
|
writer.mapped("return", {mappingKind: "anchor", node: statement, path})
|
|
174
176
|
writer.synthetic(" ", "return spacing", [statement], [path])
|
|
175
177
|
emitExpression(writer, statement.expression, `${path}/expression`, "csharp", identity)
|
|
@@ -185,6 +187,7 @@ function emitStatement(writer, statement, indent, path) {
|
|
|
185
187
|
writer.synthetic("\n", "line break", [statement], [path])
|
|
186
188
|
return
|
|
187
189
|
}
|
|
190
|
+
if (statement.kind != "IfStatement") throw new TypeError("Unsupported C# statement reached emission.")
|
|
188
191
|
writer.mapped("if", {mappingKind: "anchor", node: statement, path})
|
|
189
192
|
writer.synthetic(" ", "conditional spacing", [statement], [path])
|
|
190
193
|
writer.mapped("(", {mappingKind: "anchor", node: statement, path})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
export const dartRuntime = `final BigInt _semantifoldMaxSafeInteger = BigInt.from(9007199254740991);
|
|
4
|
+
final BigInt _semantifoldMinSafeInteger = BigInt.from(-9007199254740991);
|
|
5
|
+
|
|
6
|
+
int _semantifoldInteger(BigInt value) {
|
|
7
|
+
final _ = _semantifoldIntegerAdd;
|
|
8
|
+
final _ = _semantifoldIntegerSubtract;
|
|
9
|
+
final _ = _semantifoldIntegerMultiply;
|
|
10
|
+
final _ = _semantifoldIntegerNegate;
|
|
11
|
+
final _ = _semantifoldBoolean;
|
|
12
|
+
final _ = _semantifoldUse;
|
|
13
|
+
if (value < _semantifoldMinSafeInteger ||
|
|
14
|
+
value > _semantifoldMaxSafeInteger) {
|
|
15
|
+
throw RangeError('Semantifold safe integer overflow');
|
|
16
|
+
}
|
|
17
|
+
return value.toInt();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
bool _semantifoldBoolean(bool value) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
void _semantifoldUse(Object _) {}
|
|
25
|
+
|
|
26
|
+
int _semantifoldIntegerAdd(int left, int right) {
|
|
27
|
+
return _semantifoldInteger(BigInt.from(left) + BigInt.from(right));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
int _semantifoldIntegerSubtract(int left, int right) {
|
|
31
|
+
return _semantifoldInteger(BigInt.from(left) - BigInt.from(right));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
int _semantifoldIntegerMultiply(int left, int right) {
|
|
35
|
+
return _semantifoldInteger(BigInt.from(left) * BigInt.from(right));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
int _semantifoldIntegerNegate(int value) {
|
|
39
|
+
return _semantifoldInteger(-BigInt.from(value));
|
|
40
|
+
}
|
|
41
|
+
`
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import {unsupportedCapability} from "../diagnostic.js"
|
|
4
|
+
import {finalizeMapping, toSourceMapV3} from "../mapping.js"
|
|
5
|
+
import {emitExpression, validateBackendModule} from "./shared.js"
|
|
6
|
+
import {dartRuntime} from "./dart-runtime.js"
|
|
7
|
+
import {emitScalarType} from "./scalars.js"
|
|
8
|
+
import {SourceWriter} from "./writer.js"
|
|
9
|
+
|
|
10
|
+
const pubspec = "name: semantifold_generated\npublish_to: none\nenvironment:\n sdk: 3.13.3\n"
|
|
11
|
+
const lockfile = "# Generated by pub\n# See https://dart.dev/tools/pub/glossary#lockfile\npackages: {}\nsdks:\n dart: \"3.13.3\"\n"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Emits one deterministic dependency-free Dart package candidate.
|
|
15
|
+
* @param {{filename?: string, mapDirective?: unknown, module: import("../semantic/types.js").SemanticModule, sourceMapFilename?: unknown, sources?: {filename: string, content: string, language?: import("../semantic/types.js").SemanticLanguage}[]}} input Backend request.
|
|
16
|
+
* @returns {{artifacts: import("../semantic/types.js").GeneratedSetArtifact[], target: string}} Candidate artifact set.
|
|
17
|
+
*/
|
|
18
|
+
export function generateDartPackage({filename, mapDirective, module, sourceMapFilename, sources}) {
|
|
19
|
+
validateBackendModule(module, "dart")
|
|
20
|
+
if (filename !== undefined && filename != "bin/program.dart") {
|
|
21
|
+
unsupportedCapability("dart", "artifact filename other than bin/program.dart", module.location)
|
|
22
|
+
}
|
|
23
|
+
if (mapDirective !== undefined || sourceMapFilename !== undefined) {
|
|
24
|
+
unsupportedCapability("dart", "source-map filename or directive option", module.location)
|
|
25
|
+
}
|
|
26
|
+
const unreadLocals = findUnreadLocals(module)
|
|
27
|
+
const writer = new SourceWriter({filename: "bin/program.dart", language: "dart", module, sources})
|
|
28
|
+
|
|
29
|
+
emitProgram(module, writer, unreadLocals)
|
|
30
|
+
const mapping = finalizeMapping(writer.finish())
|
|
31
|
+
const root = mapping.nodes.find(({path}) => path == "")
|
|
32
|
+
|
|
33
|
+
if (!root) throw new Error("Validated Dart module omitted its canonical root provenance.")
|
|
34
|
+
const relatedOrigins = relatedRootOrigins(root)
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
artifacts: [{
|
|
38
|
+
content: pubspec,
|
|
39
|
+
contentKind: "text",
|
|
40
|
+
mediaType: "application/yaml",
|
|
41
|
+
ownership: "generated",
|
|
42
|
+
path: "pubspec.yaml",
|
|
43
|
+
provenance: {
|
|
44
|
+
kind: "synthetic",
|
|
45
|
+
reason: "Fixed dependency-free Dart 3.13.3 package configuration.",
|
|
46
|
+
relatedOrigins
|
|
47
|
+
},
|
|
48
|
+
role: "manifest"
|
|
49
|
+
}, {
|
|
50
|
+
content: lockfile,
|
|
51
|
+
contentKind: "text",
|
|
52
|
+
mediaType: "application/yaml",
|
|
53
|
+
ownership: "generated",
|
|
54
|
+
path: "pubspec.lock",
|
|
55
|
+
provenance: {
|
|
56
|
+
kind: "synthetic",
|
|
57
|
+
reason: "Deterministic Dart pub lockfile for a package with no dependencies.",
|
|
58
|
+
relatedOrigins
|
|
59
|
+
},
|
|
60
|
+
role: "manifest"
|
|
61
|
+
}, {
|
|
62
|
+
content: mapping.generated.content,
|
|
63
|
+
contentKind: "text",
|
|
64
|
+
mediaType: "text/x-dart",
|
|
65
|
+
ownership: "generated",
|
|
66
|
+
path: "bin/program.dart",
|
|
67
|
+
provenance: {kind: "text", mapping, sourceMap: toSourceMapV3(mapping)},
|
|
68
|
+
role: "entry"
|
|
69
|
+
}],
|
|
70
|
+
target: "dart"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Emits the compiler-owned prefix and one complete program.
|
|
76
|
+
* @param {import("../semantic/types.js").SemanticModule} module Semantic module.
|
|
77
|
+
* @param {SourceWriter} writer Source-aware writer.
|
|
78
|
+
* @param {Set<import("../semantic/types.js").LocalDeclaration>} unreadLocals Locals requiring an analyzer-only read.
|
|
79
|
+
* @returns {void}
|
|
80
|
+
*/
|
|
81
|
+
function emitProgram(module, writer, unreadLocals) {
|
|
82
|
+
writer.synthetic(dartRuntime, "Checked Dart safe-integer support", [module], [""])
|
|
83
|
+
for (let index = 0; index < module.functions.length; index += 1) {
|
|
84
|
+
const declaration = module.functions[index]
|
|
85
|
+
const path = `/functions/${index}`
|
|
86
|
+
|
|
87
|
+
writer.synthetic("\n", "declaration separator", [declaration], [path])
|
|
88
|
+
writer.mapped(emitScalarType("dart", declaration.returnType), {
|
|
89
|
+
mappingKind: "exact", node: declaration.returnType, path: `${path}/returnType`, role: "type"
|
|
90
|
+
})
|
|
91
|
+
writer.synthetic(" ", "declaration spacing", [declaration], [path])
|
|
92
|
+
writer.mapped(declaration.name, {mappingKind: "exact", node: declaration, path, role: "name"})
|
|
93
|
+
const flatParameters = declaration.parameters.map((parameter) =>
|
|
94
|
+
`${emitScalarType("dart", parameter.type)} ${parameter.name}`).join(", ")
|
|
95
|
+
const multilineParameters = declaration.parameters.length > 0 &&
|
|
96
|
+
writer.column - 1 + `(${flatParameters}) {`.length > 80
|
|
97
|
+
|
|
98
|
+
writer.mapped("(", {mappingKind: "anchor", node: declaration, path})
|
|
99
|
+
declaration.parameters.forEach((parameter, parameterIndex) => {
|
|
100
|
+
const parameterPath = `${path}/parameters/${parameterIndex}`
|
|
101
|
+
|
|
102
|
+
if (multilineParameters) {
|
|
103
|
+
writer.synthetic(`${parameterIndex ? "" : "\n"} `, "Dart parameter indentation", [parameter], [parameterPath])
|
|
104
|
+
} else if (parameterIndex) writer.synthetic(", ", "parameter separator", [parameter], [parameterPath])
|
|
105
|
+
writer.mapped(emitScalarType("dart", parameter.type), {
|
|
106
|
+
mappingKind: "exact", node: parameter.type, path: `${parameterPath}/type`, role: "type"
|
|
107
|
+
})
|
|
108
|
+
writer.synthetic(" ", "parameter spacing", [parameter], [parameterPath])
|
|
109
|
+
writer.mapped(parameter.name, {mappingKind: "exact", node: parameter, path: parameterPath, role: "name"})
|
|
110
|
+
if (multilineParameters) writer.synthetic(",\n", "Dart formatter parameter separator", [parameter], [parameterPath])
|
|
111
|
+
})
|
|
112
|
+
writer.mapped(")", {mappingKind: "anchor", node: declaration, path})
|
|
113
|
+
writer.synthetic(" ", "body spacing", [declaration], [path])
|
|
114
|
+
writer.mapped("{", {mappingKind: "anchor", node: declaration.body, path: `${path}/body`})
|
|
115
|
+
writer.synthetic("\n", "line break", [declaration], [path])
|
|
116
|
+
emitBlock(writer, declaration.body, " ", `${path}/body`, unreadLocals)
|
|
117
|
+
writer.mapped("}", {mappingKind: "anchor", node: declaration.body, path: `${path}/body`})
|
|
118
|
+
writer.synthetic("\n", "line break", [declaration], [path])
|
|
119
|
+
}
|
|
120
|
+
writer.synthetic("\nvoid main() {\n", "Dart generated main scaffold", [module.entryPoint], ["/entryPoint"])
|
|
121
|
+
emitBlock(writer, module.entryPoint.body, " ", "/entryPoint/body", unreadLocals)
|
|
122
|
+
writer.synthetic("}\n", "Dart generated main scaffold", [module.entryPoint], ["/entryPoint"])
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Emits one ordered semantic block.
|
|
127
|
+
* @param {SourceWriter} writer Source-aware writer.
|
|
128
|
+
* @param {import("../semantic/types.js").Block} block Semantic block.
|
|
129
|
+
* @param {string} indent Current indentation.
|
|
130
|
+
* @param {string} path Exact semantic path.
|
|
131
|
+
* @param {Set<import("../semantic/types.js").LocalDeclaration>} unreadLocals Locals requiring an analyzer-only read.
|
|
132
|
+
* @returns {void}
|
|
133
|
+
*/
|
|
134
|
+
function emitBlock(writer, block, indent, path, unreadLocals) {
|
|
135
|
+
block.statements.forEach((statement, index) =>
|
|
136
|
+
emitStatement(writer, statement, indent, `${path}/statements/${index}`, unreadLocals))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Emits one Tasks 001-005 statement.
|
|
141
|
+
* @param {SourceWriter} writer Source-aware writer.
|
|
142
|
+
* @param {import("../semantic/types.js").Statement} statement Semantic statement.
|
|
143
|
+
* @param {string} indent Current indentation.
|
|
144
|
+
* @param {string} path Exact semantic path.
|
|
145
|
+
* @param {Set<import("../semantic/types.js").LocalDeclaration>} unreadLocals Locals requiring an analyzer-only read.
|
|
146
|
+
* @returns {void}
|
|
147
|
+
*/
|
|
148
|
+
function emitStatement(writer, statement, indent, path, unreadLocals) {
|
|
149
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
150
|
+
if (statement.kind == "LocalDeclaration") {
|
|
151
|
+
if (!statement.mutable) writer.mapped("final", {mappingKind: "anchor", node: statement, path})
|
|
152
|
+
else writer.mapped(emitScalarType("dart", statement.type), {
|
|
153
|
+
mappingKind: "exact", node: statement.type, path: `${path}/type`, role: "type"
|
|
154
|
+
})
|
|
155
|
+
writer.synthetic(" ", "local spacing", [statement], [path])
|
|
156
|
+
if (!statement.mutable) {
|
|
157
|
+
writer.mapped(emitScalarType("dart", statement.type), {
|
|
158
|
+
mappingKind: "exact", node: statement.type, path: `${path}/type`, role: "type"
|
|
159
|
+
})
|
|
160
|
+
writer.synthetic(" ", "local spacing", [statement], [path])
|
|
161
|
+
}
|
|
162
|
+
writer.mapped(statement.name, {mappingKind: "exact", node: statement, path, role: "name"})
|
|
163
|
+
writer.synthetic(" ", "assignment spacing", [statement], [path])
|
|
164
|
+
writer.mapped("=", {mappingKind: "exact", node: statement, path, role: "operator"})
|
|
165
|
+
writer.synthetic(" ", "assignment spacing", [statement], [path])
|
|
166
|
+
emitExpression(writer, statement.initializer, `${path}/initializer`, "dart", identity)
|
|
167
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
168
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
169
|
+
if (unreadLocals.has(statement)) {
|
|
170
|
+
writer.synthetic(`${indent}_semantifoldUse(${statement.name});\n`, "Dart analyzer unread-local use", [statement], [path])
|
|
171
|
+
}
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
if (statement.kind == "AssignmentStatement") {
|
|
175
|
+
writer.mapped(statement.target.name, {mappingKind: "exact", node: statement.target, path: `${path}/target`, role: "name"})
|
|
176
|
+
writer.synthetic(" ", "assignment spacing", [statement], [path])
|
|
177
|
+
writer.mapped("=", {mappingKind: "exact", node: statement, path, role: "operator"})
|
|
178
|
+
writer.synthetic(" ", "assignment spacing", [statement], [path])
|
|
179
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "dart", identity)
|
|
180
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
181
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
182
|
+
return
|
|
183
|
+
}
|
|
184
|
+
if (statement.kind == "IfStatement") return emitIf(writer, statement, indent, path, unreadLocals)
|
|
185
|
+
if (statement.kind == "ReturnStatement") {
|
|
186
|
+
writer.mapped("return", {mappingKind: "anchor", node: statement, path})
|
|
187
|
+
if (statement.expression) {
|
|
188
|
+
writer.synthetic(" ", "return spacing", [statement], [path])
|
|
189
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "dart", identity)
|
|
190
|
+
}
|
|
191
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
192
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
if (statement.kind == "PrintStatement") {
|
|
196
|
+
writer.mapped("print", {mappingKind: "anchor", node: statement, path})
|
|
197
|
+
writer.mapped("(", {mappingKind: "anchor", node: statement, path})
|
|
198
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "dart", identity)
|
|
199
|
+
writer.mapped(");", {mappingKind: "anchor", node: statement, path})
|
|
200
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
if (statement.kind == "ExpressionStatement") {
|
|
204
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "dart", identity)
|
|
205
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
206
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
throw new TypeError("Unsupported Dart statement reached emission after preflight.")
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Emits one strict Boolean conditional.
|
|
214
|
+
* @param {SourceWriter} writer Source-aware writer.
|
|
215
|
+
* @param {import("../semantic/types.js").IfStatement} statement Conditional.
|
|
216
|
+
* @param {string} indent Current indentation.
|
|
217
|
+
* @param {string} path Exact semantic path.
|
|
218
|
+
* @param {Set<import("../semantic/types.js").LocalDeclaration>} unreadLocals Locals requiring an analyzer-only read.
|
|
219
|
+
* @returns {void}
|
|
220
|
+
*/
|
|
221
|
+
function emitIf(writer, statement, indent, path, unreadLocals) {
|
|
222
|
+
writer.mapped("if", {mappingKind: "anchor", node: statement, path})
|
|
223
|
+
writer.synthetic(" (", "Dart conditional scaffold", [statement], [path])
|
|
224
|
+
emitExpression(writer, statement.condition, `${path}/condition`, "dart", identity)
|
|
225
|
+
writer.synthetic(") ", "Dart conditional scaffold", [statement], [path])
|
|
226
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.consequent, path: `${path}/consequent`})
|
|
227
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
228
|
+
emitBlock(writer, statement.consequent, `${indent} `, `${path}/consequent`, unreadLocals)
|
|
229
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
230
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.consequent, path: `${path}/consequent`})
|
|
231
|
+
if (statement.alternate) {
|
|
232
|
+
writer.synthetic(" else ", "Dart alternate scaffold", [statement], [path])
|
|
233
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.alternate, path: `${path}/alternate`})
|
|
234
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
235
|
+
emitBlock(writer, statement.alternate, `${indent} `, `${path}/alternate`, unreadLocals)
|
|
236
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
237
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.alternate, path: `${path}/alternate`})
|
|
238
|
+
}
|
|
239
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Finds scalar locals that Dart would diagnose because no semantic expression reads them.
|
|
244
|
+
* @param {import("../semantic/types.js").SemanticModule} module Validated semantic module.
|
|
245
|
+
* @returns {Set<import("../semantic/types.js").LocalDeclaration>} Unread declaration identities.
|
|
246
|
+
*/
|
|
247
|
+
function findUnreadLocals(module) {
|
|
248
|
+
/** @type {Set<import("../semantic/types.js").LocalDeclaration>} */
|
|
249
|
+
const unread = new Set()
|
|
250
|
+
|
|
251
|
+
for (const root of [...module.functions.map(({body}) => body), module.entryPoint.body]) {
|
|
252
|
+
/** @type {import("../semantic/types.js").LocalDeclaration[]} */
|
|
253
|
+
const declarations = []
|
|
254
|
+
/** @type {Set<string>} */
|
|
255
|
+
const reads = new Set()
|
|
256
|
+
|
|
257
|
+
visitStatements(root, (statement) => {
|
|
258
|
+
if (statement.kind == "LocalDeclaration") {
|
|
259
|
+
declarations.push(statement)
|
|
260
|
+
collectIdentifierReads(statement.initializer, reads)
|
|
261
|
+
} else if (statement.kind == "IfStatement") collectIdentifierReads(statement.condition, reads)
|
|
262
|
+
else if (statement.kind == "AssignmentStatement" || statement.kind == "ExpressionStatement" ||
|
|
263
|
+
statement.kind == "PrintStatement" || statement.kind == "ReturnStatement") {
|
|
264
|
+
if (statement.expression) collectIdentifierReads(statement.expression, reads)
|
|
265
|
+
}
|
|
266
|
+
})
|
|
267
|
+
for (const declaration of declarations) if (!reads.has(declaration.name)) unread.add(declaration)
|
|
268
|
+
}
|
|
269
|
+
return unread
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Visits every Tasks 001-005 statement in one semantic body.
|
|
274
|
+
* @param {import("../semantic/types.js").Block} block Semantic block.
|
|
275
|
+
* @param {(statement: import("../semantic/types.js").Statement) => void} callback Statement visitor.
|
|
276
|
+
* @returns {void}
|
|
277
|
+
*/
|
|
278
|
+
function visitStatements(block, callback) {
|
|
279
|
+
for (const statement of block.statements) {
|
|
280
|
+
callback(statement)
|
|
281
|
+
if (statement.kind == "IfStatement") {
|
|
282
|
+
visitStatements(statement.consequent, callback)
|
|
283
|
+
if (statement.alternate) visitStatements(statement.alternate, callback)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Collects identifier reads without treating assignment targets as reads.
|
|
290
|
+
* @param {import("../semantic/types.js").Expression} expression Semantic expression.
|
|
291
|
+
* @param {Set<string>} reads Collected binding names.
|
|
292
|
+
* @returns {void}
|
|
293
|
+
*/
|
|
294
|
+
function collectIdentifierReads(expression, reads) {
|
|
295
|
+
if (expression.kind == "IdentifierExpression") reads.add(expression.name)
|
|
296
|
+
else if (expression.kind == "CallExpression") {
|
|
297
|
+
for (const argument of expression.arguments) collectIdentifierReads(argument, reads)
|
|
298
|
+
} else if (expression.kind == "UnaryExpression") collectIdentifierReads(expression.operand, reads)
|
|
299
|
+
else if (expression.kind == "BinaryExpression") {
|
|
300
|
+
collectIdentifierReads(expression.left, reads)
|
|
301
|
+
collectIdentifierReads(expression.right, reads)
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Converts root provenance to artifact-level related origins.
|
|
307
|
+
* @param {import("../semantic/types.js").SemanticNodeProvenance} root Root provenance.
|
|
308
|
+
* @returns {import("../semantic/types.js").RelatedOrigin[]} Related roots.
|
|
309
|
+
*/
|
|
310
|
+
function relatedRootOrigins(root) {
|
|
311
|
+
if (root.origin.kind == "source") {
|
|
312
|
+
return [{location: root.origin.location, nodeId: root.id, role: "module", sourceId: root.origin.sourceId}]
|
|
313
|
+
}
|
|
314
|
+
const origins = root.origin.kind == "derived" ? root.origin.origins : root.origin.relatedOrigins
|
|
315
|
+
|
|
316
|
+
return origins.map((origin) => ({...origin, nodeId: origin.nodeId ?? root.id, role: origin.role ?? "module"}))
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Returns one prevalidated Dart identifier unchanged.
|
|
321
|
+
* @param {string} name Validated identifier.
|
|
322
|
+
* @returns {string} Same identifier.
|
|
323
|
+
*/
|
|
324
|
+
function identity(name) {
|
|
325
|
+
return name
|
|
326
|
+
}
|