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/backends/php.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import {emitExpression} from "./shared.js"
|
|
4
|
-
import {
|
|
3
|
+
import {emitExpression, emitType} from "./shared.js"
|
|
4
|
+
import {emitEffectPrefixes, emitEffectSupport} from "./effects.js"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Emits an independently executable PHP program through the source-aware writer.
|
|
@@ -10,11 +10,108 @@ import {emitScalarType} from "./scalars.js"
|
|
|
10
10
|
* @returns {void}
|
|
11
11
|
*/
|
|
12
12
|
export function generatePhp(module, writer) {
|
|
13
|
-
writer.
|
|
13
|
+
if (writer.program) emitProgramHeader(module, writer)
|
|
14
|
+
else writer.synthetic("<?php\ndeclare(strict_types=1);\n\n", "PHP program scaffolding", [module])
|
|
15
|
+
emitEffectSupport(writer, module, "php")
|
|
16
|
+
const records = module.records ?? []
|
|
17
|
+
const classes = module.classes ?? []
|
|
18
|
+
const errors = module.errors ?? []
|
|
19
|
+
|
|
20
|
+
errors.forEach((error, index) => {
|
|
21
|
+
const path = `/errors/${index}`
|
|
22
|
+
|
|
23
|
+
if (index > 0) writer.synthetic("\n\n", "error declaration separator", [error], [path])
|
|
24
|
+
writer.mapped("final class", {mappingKind: "anchor", node: error, path})
|
|
25
|
+
writer.synthetic(" ", "error declaration spacing", [error], [path])
|
|
26
|
+
writer.mapped(error.name, {mappingKind: "exact", node: error, path, role: "name"})
|
|
27
|
+
writer.synthetic(writer.program ? " extends \\RuntimeException {}" : " extends RuntimeException {}",
|
|
28
|
+
"PHP unchecked error scaffolding", [error], [path])
|
|
29
|
+
})
|
|
30
|
+
if (errors.length > 0) writer.synthetic("\n\n", "error/declaration separator", [module])
|
|
31
|
+
|
|
32
|
+
records.forEach((record, recordIndex) => {
|
|
33
|
+
const recordPath = `/records/${recordIndex}`
|
|
34
|
+
|
|
35
|
+
if (recordIndex > 0) writer.synthetic("\n\n", "record declaration separator", [record], [recordPath])
|
|
36
|
+
emitTemplateDocumentation(writer, record.typeParameters ?? [], `${recordPath}/typeParameters`)
|
|
37
|
+
if ((record.typeParameters?.length ?? 0) > 0) {
|
|
38
|
+
emitDocumentedGenericRecord(writer, record, recordPath)
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
writer.mapped("final readonly class", {mappingKind: "anchor", node: record, path: recordPath})
|
|
42
|
+
writer.synthetic(" ", "record declaration spacing", [record], [recordPath])
|
|
43
|
+
writer.mapped(record.name, {mappingKind: "exact", node: record, path: recordPath, role: "name"})
|
|
44
|
+
writer.synthetic(" {\n", "record class scaffolding", [record], [recordPath])
|
|
45
|
+
const documented = record.fields.filter((field) => phpTypeNeedsDocumentation(field.type))
|
|
46
|
+
|
|
47
|
+
if (documented.length > 0) {
|
|
48
|
+
writer.synthetic(" /**\n", "PHP record type scaffolding", [record], [recordPath])
|
|
49
|
+
for (const field of documented) {
|
|
50
|
+
const fieldIndex = record.fields.indexOf(field)
|
|
51
|
+
const fieldPath = `${recordPath}/fields/${fieldIndex}`
|
|
52
|
+
|
|
53
|
+
writer.synthetic(" * @param ", "PHP record type scaffolding", [field], [fieldPath])
|
|
54
|
+
emitType(writer, field.type, `${fieldPath}/type`, "php")
|
|
55
|
+
writer.synthetic(" ", "PHP record type scaffolding", [field], [fieldPath])
|
|
56
|
+
writer.mapped(`$${field.name}`, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
57
|
+
writer.synthetic("\n", "PHP record type scaffolding", [field], [fieldPath])
|
|
58
|
+
}
|
|
59
|
+
writer.synthetic(" */\n", "PHP record type scaffolding", [record], [recordPath])
|
|
60
|
+
}
|
|
61
|
+
writer.synthetic(" public function __construct(\n", "PHP record constructor scaffolding", [record], [recordPath])
|
|
62
|
+
record.fields.forEach((field, fieldIndex) => {
|
|
63
|
+
const fieldPath = `${recordPath}/fields/${fieldIndex}`
|
|
64
|
+
|
|
65
|
+
writer.synthetic(" public ", "PHP promoted field scaffolding", [field], [fieldPath])
|
|
66
|
+
emitNativePhpType(writer, field.type, `${fieldPath}/type`)
|
|
67
|
+
if (hasNativePhpType(field.type)) writer.synthetic(" ", "PHP promoted field spacing", [field], [fieldPath])
|
|
68
|
+
writer.mapped(`$${field.name}`, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
69
|
+
writer.synthetic(fieldIndex + 1 == record.fields.length ? "\n" : ",\n", "PHP promoted field separator", [field], [fieldPath])
|
|
70
|
+
})
|
|
71
|
+
writer.synthetic(" ) {}\n}", "PHP record constructor scaffolding", [record], [recordPath])
|
|
72
|
+
})
|
|
73
|
+
if (records.length > 0) writer.synthetic("\n\n", "record/function separator", [module])
|
|
74
|
+
|
|
75
|
+
classes.forEach((declaration, classIndex) => {
|
|
76
|
+
if (classIndex > 0) writer.synthetic("\n\n", "reference class separator", [declaration], [`/classes/${classIndex}`])
|
|
77
|
+
emitReferenceClass(writer, declaration, classIndex)
|
|
78
|
+
})
|
|
79
|
+
if (classes.length > 0) writer.synthetic("\n\n", "reference class/function separator", [module])
|
|
14
80
|
|
|
15
81
|
module.functions.forEach((declaration, functionIndex) => {
|
|
16
82
|
if (functionIndex > 0) writer.synthetic("\n\n", "declaration separator", [declaration])
|
|
17
83
|
|
|
84
|
+
const documentedParameters = declaration.parameters.map((parameter, index) => [parameter, index])
|
|
85
|
+
.filter(([parameter]) => phpTypeNeedsDocumentation(/** @type {import("../semantic/types.js").Parameter} */ (parameter).type))
|
|
86
|
+
const documentedReturn = phpTypeNeedsDocumentation(declaration.returnType)
|
|
87
|
+
|
|
88
|
+
if ((declaration.typeParameters?.length ?? 0) > 0 || documentedParameters.length > 0 || documentedReturn) {
|
|
89
|
+
writer.synthetic("/**\n", "PHP collection type scaffolding", [declaration])
|
|
90
|
+
for (const [parameterIndex, parameter] of (declaration.typeParameters ?? []).entries()) {
|
|
91
|
+
writer.synthetic(" * @template ", "PHP type parameter scaffolding", [parameter], [`/functions/${functionIndex}/typeParameters/${parameterIndex}`])
|
|
92
|
+
writer.mapped(parameter.name, {
|
|
93
|
+
mappingKind: "exact", node: parameter, path: `/functions/${functionIndex}/typeParameters/${parameterIndex}`, role: "name"
|
|
94
|
+
})
|
|
95
|
+
writer.synthetic("\n", "line break", [parameter])
|
|
96
|
+
}
|
|
97
|
+
for (const [candidate, index] of documentedParameters) {
|
|
98
|
+
const parameter = /** @type {import("../semantic/types.js").Parameter} */ (candidate)
|
|
99
|
+
const parameterIndex = /** @type {number} */ (index)
|
|
100
|
+
const parameterPath = `/functions/${functionIndex}/parameters/${parameterIndex}`
|
|
101
|
+
|
|
102
|
+
writer.synthetic(" * @param ", "PHP collection type scaffolding", [parameter], [parameterPath])
|
|
103
|
+
emitType(writer, parameter.type, `${parameterPath}/type`, "php")
|
|
104
|
+
writer.synthetic(" ", "PHP collection type scaffolding", [parameter], [parameterPath])
|
|
105
|
+
writer.mapped(`$${parameter.name}`, {mappingKind: "exact", node: parameter, path: parameterPath, role: "name"})
|
|
106
|
+
writer.synthetic("\n", "PHP collection type scaffolding", [parameter], [parameterPath])
|
|
107
|
+
}
|
|
108
|
+
if (documentedReturn) {
|
|
109
|
+
writer.synthetic(" * @return ", "PHP collection type scaffolding", [declaration])
|
|
110
|
+
emitType(writer, declaration.returnType, `/functions/${functionIndex}/returnType`, "php")
|
|
111
|
+
writer.synthetic("\n", "PHP collection type scaffolding", [declaration])
|
|
112
|
+
}
|
|
113
|
+
writer.synthetic(" */\n", "PHP collection type scaffolding", [declaration])
|
|
114
|
+
}
|
|
18
115
|
writer.mapped("function", {mappingKind: "anchor", node: declaration})
|
|
19
116
|
writer.synthetic(" ", "function spacing", [declaration])
|
|
20
117
|
writer.mapped(declaration.name, {mappingKind: "exact", node: declaration, role: "name"})
|
|
@@ -23,23 +120,15 @@ export function generatePhp(module, writer) {
|
|
|
23
120
|
const parameterPath = `/functions/${functionIndex}/parameters/${index}`
|
|
24
121
|
|
|
25
122
|
if (index > 0) writer.synthetic(", ", "parameter separator", [declaration])
|
|
26
|
-
writer
|
|
27
|
-
|
|
28
|
-
node: parameter.type,
|
|
29
|
-
path: `${parameterPath}/type`,
|
|
30
|
-
role: "type"
|
|
31
|
-
})
|
|
32
|
-
writer.synthetic(" ", "parameter spacing", [parameter], [parameterPath])
|
|
123
|
+
emitNativePhpType(writer, parameter.type, `${parameterPath}/type`)
|
|
124
|
+
if (hasNativePhpType(parameter.type)) writer.synthetic(" ", "parameter spacing", [parameter], [parameterPath])
|
|
33
125
|
writer.mapped(`$${parameter.name}`, {mappingKind: "exact", node: parameter, path: parameterPath, role: "name"})
|
|
34
126
|
})
|
|
35
127
|
writer.mapped(")", {mappingKind: "anchor", node: declaration})
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
path: `/functions/${functionIndex}/returnType`,
|
|
41
|
-
role: "type"
|
|
42
|
-
})
|
|
128
|
+
if (hasNativePhpType(declaration.returnType)) {
|
|
129
|
+
writer.synthetic(": ", "return type separator", [declaration])
|
|
130
|
+
emitNativePhpType(writer, declaration.returnType, `/functions/${functionIndex}/returnType`)
|
|
131
|
+
}
|
|
43
132
|
writer.synthetic("\n", "line break", [declaration])
|
|
44
133
|
writer.mapped("{", {mappingKind: "anchor", node: declaration})
|
|
45
134
|
writer.synthetic("\n", "line break", [declaration])
|
|
@@ -48,8 +137,251 @@ export function generatePhp(module, writer) {
|
|
|
48
137
|
writer.mapped("}", {mappingKind: "anchor", node: declaration})
|
|
49
138
|
})
|
|
50
139
|
|
|
51
|
-
writer.
|
|
52
|
-
|
|
140
|
+
if (!writer.program || writer.isProgramEntry()) {
|
|
141
|
+
writer.synthetic("\n\n", "entry-point separator", [module.entryPoint])
|
|
142
|
+
emitBlock(writer, module.entryPoint.body, "", "/entryPoint/body")
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Emits one native PHP reference class.
|
|
148
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
149
|
+
* @param {import("../semantic/types.js").ClassDeclaration} declaration - Reference class.
|
|
150
|
+
* @param {number} classIndex - Module class index.
|
|
151
|
+
* @returns {void}
|
|
152
|
+
*/
|
|
153
|
+
function emitReferenceClass(writer, declaration, classIndex) {
|
|
154
|
+
const path = `/classes/${classIndex}`
|
|
155
|
+
|
|
156
|
+
writer.mapped("final class", {mappingKind: "anchor", node: declaration, path})
|
|
157
|
+
writer.synthetic(" ", "reference class spacing", [declaration], [path])
|
|
158
|
+
writer.mapped(declaration.name, {mappingKind: "exact", node: declaration, path, role: "name"})
|
|
159
|
+
writer.synthetic(" {\n", "reference class open", [declaration], [path])
|
|
160
|
+
declaration.fields.forEach((field, index) => {
|
|
161
|
+
const fieldPath = `${path}/fields/${index}`
|
|
162
|
+
|
|
163
|
+
writer.synthetic(" private ", "private field scaffolding", [field], [fieldPath])
|
|
164
|
+
emitNativePhpType(writer, field.type, `${fieldPath}/type`)
|
|
165
|
+
writer.synthetic(" $", "private field spacing", [field], [fieldPath])
|
|
166
|
+
writer.mapped(field.name, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
167
|
+
writer.synthetic(";\n", "line break", [field], [fieldPath])
|
|
168
|
+
})
|
|
169
|
+
const constructor = declaration.constructor
|
|
170
|
+
const constructorPath = `${path}/constructor`
|
|
171
|
+
|
|
172
|
+
writer.synthetic("\n public function ", "constructor scaffolding", [constructor], [constructorPath])
|
|
173
|
+
writer.mapped("__construct", {mappingKind: "exact", node: constructor, path: constructorPath, role: "constructor"})
|
|
174
|
+
emitPhpParameters(writer, constructor.parameters, `${constructorPath}/parameters`)
|
|
175
|
+
writer.synthetic(" {\n", "constructor open", [constructor], [constructorPath])
|
|
176
|
+
emitBlock(writer, constructor.body, " ", `${constructorPath}/body`)
|
|
177
|
+
writer.synthetic(" }", "constructor close", [constructor], [constructorPath])
|
|
178
|
+
declaration.methods.forEach((method, index) => {
|
|
179
|
+
const methodPath = `${path}/methods/${index}`
|
|
180
|
+
|
|
181
|
+
writer.synthetic("\n\n public function ", "method scaffolding", [method], [methodPath])
|
|
182
|
+
writer.mapped(method.name, {mappingKind: "exact", node: method, path: methodPath, role: "name"})
|
|
183
|
+
emitPhpParameters(writer, method.parameters, `${methodPath}/parameters`)
|
|
184
|
+
writer.synthetic(": ", "method return separator", [method], [methodPath])
|
|
185
|
+
emitNativePhpType(writer, method.returnType, `${methodPath}/returnType`)
|
|
186
|
+
writer.synthetic(" {\n", "method open", [method], [methodPath])
|
|
187
|
+
emitBlock(writer, method.body, " ", `${methodPath}/body`)
|
|
188
|
+
writer.synthetic(" }", "method close", [method], [methodPath])
|
|
189
|
+
})
|
|
190
|
+
writer.synthetic("\n", "line break", [declaration], [path])
|
|
191
|
+
writer.mapped("}", {mappingKind: "anchor", node: declaration, path})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Emits one PHP parameter list.
|
|
196
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
197
|
+
* @param {import("../semantic/types.js").Parameter[]} parameters - Ordered parameters.
|
|
198
|
+
* @param {string} path - Parameter collection path.
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
function emitPhpParameters(writer, parameters, path) {
|
|
202
|
+
writer.synthetic("(", "parameter list open", parameters)
|
|
203
|
+
parameters.forEach((parameter, index) => {
|
|
204
|
+
const parameterPath = `${path}/${index}`
|
|
205
|
+
|
|
206
|
+
if (index) writer.synthetic(", ", "parameter separator", parameters)
|
|
207
|
+
emitNativePhpType(writer, parameter.type, `${parameterPath}/type`)
|
|
208
|
+
writer.synthetic(" $", "parameter spacing", [parameter], [parameterPath])
|
|
209
|
+
writer.mapped(parameter.name, {mappingKind: "exact", node: parameter, path: parameterPath, role: "name"})
|
|
210
|
+
})
|
|
211
|
+
writer.synthetic(")", "parameter list close", parameters)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Emits PHP's exact documented generic-record profile. Private promoted storage
|
|
216
|
+
* plus public getters preserves record immutability when a type variable has no
|
|
217
|
+
* faithful native property type.
|
|
218
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
219
|
+
* @param {import("../semantic/types.js").RecordDeclaration} record - Generic semantic record.
|
|
220
|
+
* @param {string} recordPath - Exact record path.
|
|
221
|
+
*/
|
|
222
|
+
function emitDocumentedGenericRecord(writer, record, recordPath) {
|
|
223
|
+
writer.mapped("final class", {mappingKind: "anchor", node: record, path: recordPath})
|
|
224
|
+
writer.synthetic(" ", "record declaration spacing", [record], [recordPath])
|
|
225
|
+
writer.mapped(record.name, {mappingKind: "exact", node: record, path: recordPath, role: "name"})
|
|
226
|
+
writer.synthetic(" {\n /**\n", "PHP documented generic record scaffolding", [record], [recordPath])
|
|
227
|
+
record.fields.forEach((field, fieldIndex) => {
|
|
228
|
+
const fieldPath = `${recordPath}/fields/${fieldIndex}`
|
|
229
|
+
|
|
230
|
+
writer.synthetic(" * @param ", "PHP documented generic record scaffolding", [field], [fieldPath])
|
|
231
|
+
emitType(writer, field.type, `${fieldPath}/type`, "php")
|
|
232
|
+
writer.synthetic(" ", "PHP documented generic record scaffolding", [field], [fieldPath])
|
|
233
|
+
writer.mapped(`$${field.name}`, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
234
|
+
writer.synthetic("\n", "PHP documented generic record scaffolding", [field], [fieldPath])
|
|
235
|
+
})
|
|
236
|
+
writer.synthetic(" */\n public function __construct(\n", "PHP documented generic record scaffolding", [record], [recordPath])
|
|
237
|
+
record.fields.forEach((field, fieldIndex) => {
|
|
238
|
+
const fieldPath = `${recordPath}/fields/${fieldIndex}`
|
|
239
|
+
|
|
240
|
+
writer.synthetic(" private ", "PHP private promoted field scaffolding", [field], [fieldPath])
|
|
241
|
+
emitNativePhpType(writer, field.type, `${fieldPath}/type`)
|
|
242
|
+
if (hasNativePhpType(field.type)) writer.synthetic(" ", "PHP promoted field spacing", [field], [fieldPath])
|
|
243
|
+
writer.mapped(`$${field.name}`, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
244
|
+
writer.synthetic(fieldIndex + 1 == record.fields.length ? "\n" : ",\n", "PHP promoted field separator", [field], [fieldPath])
|
|
245
|
+
})
|
|
246
|
+
writer.synthetic(" ) {}", "PHP documented generic record scaffolding", [record], [recordPath])
|
|
247
|
+
record.fields.forEach((field, fieldIndex) => {
|
|
248
|
+
const fieldPath = `${recordPath}/fields/${fieldIndex}`
|
|
249
|
+
|
|
250
|
+
writer.synthetic("\n\n /**\n * @return ", "PHP documented generic getter scaffolding", [field], [fieldPath])
|
|
251
|
+
emitType(writer, field.type, `${fieldPath}/type`, "php")
|
|
252
|
+
writer.synthetic("\n */\n public function ", "PHP documented generic getter scaffolding", [field], [fieldPath])
|
|
253
|
+
writer.mapped(field.name, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
254
|
+
writer.synthetic("()", "PHP documented generic getter scaffolding", [field], [fieldPath])
|
|
255
|
+
if (hasNativePhpType(field.type)) {
|
|
256
|
+
writer.synthetic(": ", "PHP getter return type spacing", [field], [fieldPath])
|
|
257
|
+
emitNativePhpType(writer, field.type, `${fieldPath}/type`)
|
|
258
|
+
}
|
|
259
|
+
writer.synthetic(" {\n return $this->", "PHP documented generic getter scaffolding", [field], [fieldPath])
|
|
260
|
+
writer.mapped(field.name, {mappingKind: "exact", node: field, path: fieldPath, role: "name"})
|
|
261
|
+
writer.synthetic(";\n }", "PHP documented generic getter scaffolding", [field], [fieldPath])
|
|
262
|
+
})
|
|
263
|
+
writer.synthetic("\n}", "PHP documented generic record scaffolding", [record], [recordPath])
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Emits a standalone PHPDoc template block.
|
|
268
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
269
|
+
* @param {import("../semantic/types.js").TypeParameter[]} parameters - Ordered type parameters.
|
|
270
|
+
* @param {string} path - Type-parameter collection path.
|
|
271
|
+
*/
|
|
272
|
+
function emitTemplateDocumentation(writer, parameters, path) {
|
|
273
|
+
if (parameters.length == 0) return
|
|
274
|
+
writer.synthetic("/**\n", "PHP type parameter scaffolding", parameters)
|
|
275
|
+
parameters.forEach((parameter, index) => {
|
|
276
|
+
writer.synthetic(" * @template ", "PHP type parameter scaffolding", [parameter], [`${path}/${index}`])
|
|
277
|
+
writer.mapped(parameter.name, {mappingKind: "exact", node: parameter, path: `${path}/${index}`, role: "name"})
|
|
278
|
+
writer.synthetic("\n", "line break", [parameter])
|
|
279
|
+
})
|
|
280
|
+
writer.synthetic(" */\n", "PHP type parameter scaffolding", parameters)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Emits one canonical namespace, explicit imports, and matching literal load edges.
|
|
285
|
+
* @param {import("../semantic/types.js").SemanticModule} module - Current program module.
|
|
286
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
287
|
+
*/
|
|
288
|
+
function emitProgramHeader(module, writer) {
|
|
289
|
+
const programModule = /** @type {import("../semantic/types.js").SemanticProgramModule} */ (/** @type {unknown} */ (module))
|
|
290
|
+
|
|
291
|
+
writer.synthetic(`<?php\ndeclare(strict_types=1);\nnamespace Semantifold\\Generated\\${writer.programModuleName(programModule.id)};\n`,
|
|
292
|
+
"PHP semantic namespace", [module])
|
|
293
|
+
for (const imported of programModule.imports) {
|
|
294
|
+
const dependency = writer.programModuleName(imported.moduleId)
|
|
295
|
+
const prefix = imported.symbolKind == "function" ? "use function" : "use"
|
|
296
|
+
const importPath = `/imports/${programModule.imports.indexOf(imported)}`
|
|
297
|
+
const localName = writer.importNameFor(imported)
|
|
298
|
+
|
|
299
|
+
writer.synthetic(`${prefix} Semantifold\\Generated\\${dependency}\\`, "PHP semantic import", [imported], [importPath])
|
|
300
|
+
writer.mapped(imported.importedName, {mappingKind: "exact", node: imported, path: importPath, role: "importedName"})
|
|
301
|
+
if (localName != imported.importedName) {
|
|
302
|
+
writer.synthetic(" as ", "PHP semantic import alias", [imported], [importPath])
|
|
303
|
+
writer.mapped(localName, {mappingKind: "exact", node: imported, path: importPath, role: "localName"})
|
|
304
|
+
}
|
|
305
|
+
writer.synthetic(";\n", "PHP semantic import terminator", [imported], [importPath])
|
|
306
|
+
}
|
|
307
|
+
for (const moduleId of [...new Set(programModule.imports.map((item) => item.moduleId))]) {
|
|
308
|
+
const relative = writer.relativeModuleSpecifier(moduleId).replace(/^\.\//u, "")
|
|
309
|
+
const imported = /** @type {import("../semantic/types.js").SemanticImport} */ (
|
|
310
|
+
programModule.imports.find((item) => item.moduleId == moduleId))
|
|
311
|
+
const importPath = `/imports/${programModule.imports.indexOf(imported)}`
|
|
312
|
+
|
|
313
|
+
writer.synthetic("require_once __DIR__ . ", "PHP require-once edge", [imported], [importPath])
|
|
314
|
+
writer.mapped(JSON.stringify(`/${relative}`), {mappingKind: "anchor", node: imported, path: importPath, role: "path"})
|
|
315
|
+
writer.synthetic(";\n", "PHP require-once terminator", [imported], [importPath])
|
|
316
|
+
}
|
|
317
|
+
if (writer.stdlibProviderEntries) {
|
|
318
|
+
for (const providerPath of writer.stdlibProviderPaths ?? []) {
|
|
319
|
+
const relative = writer.stdlibProviderSpecifier(undefined, providerPath).replace(/^\.\//u, "")
|
|
320
|
+
|
|
321
|
+
writer.synthetic("require_once __DIR__ . ", "PHP stdlib provider require-once edge", [module])
|
|
322
|
+
writer.synthetic(JSON.stringify(`/${relative}`), "PHP stdlib provider require-once path", [module])
|
|
323
|
+
writer.synthetic(";\n", "PHP stdlib provider require-once terminator", [module])
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
writer.synthetic("\n", "PHP namespace/declaration separator", [module])
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Returns whether a PHP native type needs an accompanying recursive PHPDoc type.
|
|
331
|
+
* @param {import("../semantic/types.js").SemanticFunctionReturnType} type - Semantic type.
|
|
332
|
+
* @returns {boolean} Whether the type contains a collection.
|
|
333
|
+
*/
|
|
334
|
+
function phpTypeNeedsDocumentation(type) {
|
|
335
|
+
return type.kind == "TypeVariableReference" || type.kind == "ListType" || type.kind == "MapType" ||
|
|
336
|
+
type.kind == "OrderedMapType" ||
|
|
337
|
+
type.kind == "RecordType" && (type.arguments?.length ?? 0) > 0 ||
|
|
338
|
+
type.kind == "OptionalType" && phpTypeNeedsDocumentation(type.valueType)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Emits the exact native PHP carrier while retaining recursive type mappings.
|
|
343
|
+
* @param {import("./writer.js").SourceWriter} writer - Source-aware writer.
|
|
344
|
+
* @param {import("../semantic/types.js").SemanticFunctionReturnType} type - Semantic type.
|
|
345
|
+
* @param {string} path - Exact type occurrence path.
|
|
346
|
+
* @returns {void}
|
|
347
|
+
*/
|
|
348
|
+
function emitNativePhpType(writer, type, path) {
|
|
349
|
+
if (type.kind == "TypeVariableReference" || type.kind == "OptionalType" && type.valueType.kind == "TypeVariableReference") return
|
|
350
|
+
if (type.kind == "RecordType") {
|
|
351
|
+
const record = writer.recordForId(type.declarationId)
|
|
352
|
+
|
|
353
|
+
writer.mapped(writer.recordNameForId(type.declarationId), {
|
|
354
|
+
mappingKind: "exact", name: record.name, node: type, path, role: "type"
|
|
355
|
+
})
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
if (type.kind == "ReferenceType" || type.kind == "OwnedResourceType" || type.kind == "OwnedReferenceType") {
|
|
359
|
+
emitType(writer, type, path, "php")
|
|
360
|
+
return
|
|
361
|
+
}
|
|
362
|
+
if (type.kind == "TypeReference") {
|
|
363
|
+
emitType(writer, type, path, "php")
|
|
364
|
+
return
|
|
365
|
+
}
|
|
366
|
+
if (type.kind == "OptionalType") {
|
|
367
|
+
writer.mapped("?", {mappingKind: "exact", node: type, path, role: "type"})
|
|
368
|
+
if (type.valueType.kind == "RecordType") emitNativePhpType(writer, type.valueType, `${path}/valueType`)
|
|
369
|
+
else if (type.valueType.kind == "TypeReference") emitType(writer, type.valueType, `${path}/valueType`, "php")
|
|
370
|
+
else writer.mapped("array", {mappingKind: "anchor", node: type, path})
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
writer.mapped("array", {mappingKind: "exact", node: type, path, role: "type"})
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Returns whether PHP has a faithful native carrier for one exact semantic type.
|
|
379
|
+
* @param {import("../semantic/types.js").SemanticFunctionReturnType} type - Semantic type.
|
|
380
|
+
* @returns {boolean} Whether a native annotation can be emitted.
|
|
381
|
+
*/
|
|
382
|
+
function hasNativePhpType(type) {
|
|
383
|
+
return type.kind != "TypeVariableReference" &&
|
|
384
|
+
!(type.kind == "OptionalType" && type.valueType.kind == "TypeVariableReference")
|
|
53
385
|
}
|
|
54
386
|
|
|
55
387
|
/**
|
|
@@ -73,11 +405,126 @@ function emitBlock(writer, block, indent, path) {
|
|
|
73
405
|
* @returns {void}
|
|
74
406
|
*/
|
|
75
407
|
function emitStatement(writer, statement, indent, path) {
|
|
408
|
+
emitEffectPrefixes(writer, statement, indent, path, "php",
|
|
409
|
+
(expression, expressionPath) => emitExpression(writer, expression, expressionPath, "php", phpIdentifier))
|
|
76
410
|
if (statement.kind == "LocalDeclaration" || statement.kind == "AssignmentStatement") return emitLocal(writer, statement, indent, path)
|
|
77
411
|
writer.synthetic(indent, "indentation", [statement], [path])
|
|
412
|
+
if (statement.kind == "PrivateFieldWriteStatement") {
|
|
413
|
+
emitExpression(writer, statement.receiver, `${path}/receiver`, "php", phpIdentifier)
|
|
414
|
+
const field = writer.privateFieldForId(statement.field)
|
|
415
|
+
|
|
416
|
+
writer.mapped(`->${field.name}`, {mappingKind: "exact", name: field.name, node: statement, path, role: "member"})
|
|
417
|
+
writer.synthetic(" = ", "private field assignment", [statement], [path])
|
|
418
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "php", phpIdentifier)
|
|
419
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
420
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
421
|
+
return
|
|
422
|
+
}
|
|
423
|
+
if (statement.kind == "BreakStatement" || statement.kind == "ContinueStatement") {
|
|
424
|
+
writer.mapped(statement.kind == "BreakStatement" ? "break" : "continue", {mappingKind: "exact", node: statement, path})
|
|
425
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
426
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
427
|
+
return
|
|
428
|
+
}
|
|
429
|
+
if (statement.kind == "WhileStatement") {
|
|
430
|
+
writer.mapped("while", {mappingKind: "exact", node: statement, path})
|
|
431
|
+
writer.synthetic(" (", "condition-controlled loop spacing", [statement], [path])
|
|
432
|
+
emitExpression(writer, statement.condition, `${path}/condition`, "php", phpIdentifier)
|
|
433
|
+
writer.synthetic(") ", "condition-controlled loop spacing", [statement], [path])
|
|
434
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
435
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
436
|
+
emitBlock(writer, statement.body, `${indent} `, `${path}/body`)
|
|
437
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
438
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
439
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
440
|
+
return
|
|
441
|
+
}
|
|
442
|
+
if (statement.kind == "ForEachStatement") {
|
|
443
|
+
writer.mapped("foreach", {mappingKind: "anchor", node: statement, path})
|
|
444
|
+
writer.synthetic(" (", "loop scaffolding", [statement], [path])
|
|
445
|
+
emitExpression(writer, statement.list, `${path}/list`, "php", phpIdentifier)
|
|
446
|
+
writer.synthetic(" as ", "loop scaffolding", [statement], [path])
|
|
447
|
+
writer.mapped(`$${statement.valueBinding.name}`, {
|
|
448
|
+
mappingKind: "exact", node: statement.valueBinding, path: `${path}/valueBinding`, role: "name"
|
|
449
|
+
})
|
|
450
|
+
writer.synthetic(") ", "loop scaffolding", [statement], [path])
|
|
451
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
452
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
453
|
+
emitBlock(writer, statement.body, `${indent} `, `${path}/body`)
|
|
454
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
455
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
456
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
if (statement.kind == "ForEachMapStatement") {
|
|
460
|
+
writer.mapped("foreach", {mappingKind: "anchor", node: statement, path})
|
|
461
|
+
writer.synthetic(" (", "map loop scaffolding", [statement], [path])
|
|
462
|
+
emitExpression(writer, statement.map, `${path}/map`, "php", phpIdentifier)
|
|
463
|
+
writer.synthetic(" as ", "map loop scaffolding", [statement], [path])
|
|
464
|
+
writer.mapped(`$${statement.keyBinding.name}`, {
|
|
465
|
+
mappingKind: "exact", node: statement.keyBinding, path: `${path}/keyBinding`, role: "name"
|
|
466
|
+
})
|
|
467
|
+
writer.synthetic(" => ", "map iteration binding separator", [statement], [path])
|
|
468
|
+
writer.mapped(`$${statement.valueBinding.name}`, {
|
|
469
|
+
mappingKind: "exact", node: statement.valueBinding, path: `${path}/valueBinding`, role: "name"
|
|
470
|
+
})
|
|
471
|
+
writer.synthetic(") ", "map loop scaffolding", [statement], [path])
|
|
472
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
473
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
474
|
+
emitBlock(writer, statement.body, `${indent} `, `${path}/body`)
|
|
475
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
476
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
477
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
478
|
+
return
|
|
479
|
+
}
|
|
480
|
+
if (statement.kind == "RaiseStatement") {
|
|
481
|
+
const type = statement.error.error
|
|
482
|
+
const error = writer.errorForId(type.declarationId)
|
|
483
|
+
|
|
484
|
+
writer.mapped("throw", {mappingKind: "anchor", node: statement, path})
|
|
485
|
+
writer.synthetic(" new ", "error construction scaffolding", [statement.error], [`${path}/error`])
|
|
486
|
+
writer.mapped(writer.errorNameForId(type.declarationId), {mappingKind: "exact", name: error.name, node: statement.error, path: `${path}/error`, role: "type"})
|
|
487
|
+
writer.synthetic("(", "error construction open", [statement.error], [`${path}/error`])
|
|
488
|
+
emitExpression(writer, statement.error.message, `${path}/error/message`, "php", phpIdentifier)
|
|
489
|
+
writer.synthetic(");\n", "error construction close", [statement.error], [`${path}/error`])
|
|
490
|
+
return
|
|
491
|
+
}
|
|
492
|
+
if (statement.kind == "TryStatement") {
|
|
493
|
+
const caught = writer.errorForId(statement.catchType.declarationId)
|
|
494
|
+
|
|
495
|
+
writer.mapped("try", {mappingKind: "anchor", node: statement, path})
|
|
496
|
+
writer.synthetic(" ", "try spacing", [statement], [path])
|
|
497
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
498
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
499
|
+
emitBlock(writer, statement.body, `${indent} `, `${path}/body`)
|
|
500
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
501
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.body, path: `${path}/body`})
|
|
502
|
+
writer.synthetic(" ", "catch spacing", [statement], [path])
|
|
503
|
+
writer.mapped("catch", {mappingKind: "anchor", node: statement, path, role: "catch"})
|
|
504
|
+
writer.synthetic(" (", "catch binding scaffolding", [statement.catchBinding], [`${path}/catchBinding`])
|
|
505
|
+
writer.mapped(writer.errorNameForId(statement.catchType.declarationId), {mappingKind: "exact", name: caught.name, node: statement.catchType, path: `${path}/catchType`, role: "type"})
|
|
506
|
+
writer.synthetic(" ", "catch binding spacing", [statement.catchBinding], [`${path}/catchBinding`])
|
|
507
|
+
writer.mapped(`$${statement.catchBinding.name}`, {mappingKind: "exact", node: statement.catchBinding, path: `${path}/catchBinding`, role: "name"})
|
|
508
|
+
writer.synthetic(") ", "catch binding scaffolding", [statement.catchBinding], [`${path}/catchBinding`])
|
|
509
|
+
writer.mapped("{", {mappingKind: "anchor", node: statement.catchBody, path: `${path}/catchBody`})
|
|
510
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
511
|
+
emitBlock(writer, statement.catchBody, `${indent} `, `${path}/catchBody`)
|
|
512
|
+
writer.synthetic(indent, "indentation", [statement], [path])
|
|
513
|
+
writer.mapped("}", {mappingKind: "anchor", node: statement.catchBody, path: `${path}/catchBody`})
|
|
514
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
515
|
+
return
|
|
516
|
+
}
|
|
78
517
|
if (statement.kind == "ReturnStatement") {
|
|
79
518
|
writer.mapped("return", {mappingKind: "anchor", node: statement, path})
|
|
80
|
-
|
|
519
|
+
if (statement.expression) {
|
|
520
|
+
writer.synthetic(" ", "return spacing", [statement], [path])
|
|
521
|
+
emitExpression(writer, statement.expression, `${path}/expression`, "php", phpIdentifier)
|
|
522
|
+
}
|
|
523
|
+
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
524
|
+
writer.synthetic("\n", "line break", [statement], [path])
|
|
525
|
+
return
|
|
526
|
+
}
|
|
527
|
+
if (statement.kind == "ExpressionStatement") {
|
|
81
528
|
emitExpression(writer, statement.expression, `${path}/expression`, "php", phpIdentifier)
|
|
82
529
|
writer.mapped(";", {mappingKind: "anchor", node: statement, path})
|
|
83
530
|
writer.synthetic("\n", "line break", [statement], [path])
|
|
@@ -141,24 +588,14 @@ function emitLocal(writer, statement, indent, statementPath) {
|
|
|
141
588
|
|
|
142
589
|
if (statement.mutable) {
|
|
143
590
|
writer.synthetic("/** @var ", "PHP local type scaffolding", [statement], [statementPath])
|
|
144
|
-
writer
|
|
145
|
-
mappingKind: "exact",
|
|
146
|
-
node: statement.type,
|
|
147
|
-
path: `${statementPath}/type`,
|
|
148
|
-
role: "type"
|
|
149
|
-
})
|
|
591
|
+
emitType(writer, statement.type, `${statementPath}/type`, "php")
|
|
150
592
|
writer.synthetic(" ", "PHP local type scaffolding", [statement], [statementPath])
|
|
151
593
|
writer.mapped(`$${statement.name}`, {mappingKind: "exact", node: statement, path: statementPath, role: "name"})
|
|
152
594
|
writer.synthetic(" */\n", "PHP local type scaffolding", [statement], [statementPath])
|
|
153
595
|
} else {
|
|
154
596
|
writer.synthetic("/**\n", "PHP local type scaffolding", [statement], [statementPath])
|
|
155
597
|
writer.synthetic(`${indent} * @var `, "PHP local type scaffolding", [statement], [statementPath])
|
|
156
|
-
writer
|
|
157
|
-
mappingKind: "exact",
|
|
158
|
-
node: statement.type,
|
|
159
|
-
path: `${statementPath}/type`,
|
|
160
|
-
role: "type"
|
|
161
|
-
})
|
|
598
|
+
emitType(writer, statement.type, `${statementPath}/type`, "php")
|
|
162
599
|
writer.synthetic(" ", "PHP local type scaffolding", [statement], [statementPath])
|
|
163
600
|
writer.mapped(`$${statement.name}`, {mappingKind: "exact", node: statement, path: statementPath, role: "name"})
|
|
164
601
|
writer.synthetic(`\n${indent} * @semantifold-immutable\n${indent} */\n`, "PHP local type scaffolding", [statement], [statementPath])
|