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