@tsplc/compiler 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +16 -2
- package/backends/codesys/config.ts +54 -0
- package/backends/codesys/emit.ts +1063 -0
- package/backends/codesys/engineering.ts +88 -0
- package/backends/codesys/http.ts +598 -0
- package/backends/codesys/index.ts +12 -0
- package/backends/codesys/io-paths.ts +103 -0
- package/backends/codesys/names.ts +76 -0
- package/backends/codesys/numeric.ts +356 -0
- package/backends/codesys/plan.ts +512 -0
- package/backends/codesys/publication.ts +59 -0
- package/backends/codesys/storage.ts +63 -0
- package/backends/codesys/task-access.ts +118 -0
- package/backends/codesys/types.ts +178 -0
- package/backends/codesys/vendor.ts +108 -0
- package/dist/cli.js +740 -0
- package/dist/cli.js.map +13 -0
- package/dist/clock.js +8 -0
- package/dist/clock.js.map +10 -0
- package/dist/codesys.js +2587 -0
- package/dist/codesys.js.map +22 -0
- package/dist/elaborate-capture.js +118 -0
- package/dist/elaborate-capture.js.map +10 -0
- package/dist/index.js +6859 -0
- package/dist/index.js.map +25 -0
- package/dist/ir.js +1888 -0
- package/dist/ir.js.map +22 -0
- package/dist/math.js +24 -0
- package/dist/math.js.map +10 -0
- package/dist/project.js +423 -0
- package/dist/project.js.map +11 -0
- package/ir/aggregates.ts +333 -0
- package/ir/allocation.ts +74 -0
- package/ir/core-model.ts +116 -0
- package/ir/core.ts +63 -0
- package/ir/declarations.ts +201 -0
- package/ir/diagnostics.ts +43 -0
- package/ir/domains.ts +96 -0
- package/ir/index.ts +7 -0
- package/ir/link.ts +176 -0
- package/ir/model.ts +268 -0
- package/ir/normalization-error.ts +10 -0
- package/ir/routine.ts +826 -0
- package/ir/scalars.ts +675 -0
- package/ir/types.ts +70 -0
- package/package.json +105 -4
- package/project/artifacts.ts +277 -0
- package/project/cli.ts +282 -0
- package/project/index.ts +1 -0
- package/project/project.ts +298 -0
- package/project/server.ts +83 -0
- package/src/frontend/async.ts +1060 -0
- package/src/frontend/blocks.ts +419 -0
- package/src/frontend/configuration.ts +167 -0
- package/src/frontend/const-functions.ts +153 -0
- package/src/frontend/cooperative.ts +75 -0
- package/src/frontend/elaborate/capture.ts +138 -0
- package/src/frontend/elaborate/graph.ts +94 -0
- package/src/frontend/elaborate/index.ts +302 -0
- package/src/frontend/elaborate/layouts.ts +390 -0
- package/src/frontend/elaborate/model.ts +177 -0
- package/src/frontend/elaborate/specialize.ts +2280 -0
- package/src/frontend/exposure.ts +147 -0
- package/src/frontend/module-graph.ts +63 -0
- package/src/frontend/promises.ts +751 -0
- package/src/frontend/services.ts +435 -0
- package/src/frontend/types.ts +578 -0
- package/src/frontend/typescript.ts +2442 -0
- package/src/index.ts +7 -0
- package/stdlib/clock.ts +2 -0
- package/stdlib/math.ts +19 -0
- package/types/async.d.ts +81 -0
- package/types/clock.d.ts +4 -0
- package/types/config.d.ts +2 -0
- package/types/data-types.d.ts +31 -0
- package/types/globals.d.ts +40 -0
- package/types/index.d.ts +111 -0
- package/types/plc.d.ts +5 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import type { CapturedGraph, CapturedNode, CapturedValue } from "./graph.ts";
|
|
3
|
+
|
|
4
|
+
/** One step from an owner to the object it holds. */
|
|
5
|
+
export type Step = { kind: "field"; name: string } | { kind: "index"; index: number };
|
|
6
|
+
|
|
7
|
+
/** Where a captured object is stored: a root binding and the steps to it. */
|
|
8
|
+
export interface Owner {
|
|
9
|
+
root: Root;
|
|
10
|
+
steps: readonly Step[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Root {
|
|
14
|
+
file: string;
|
|
15
|
+
name: string;
|
|
16
|
+
declaration: ts.VariableDeclaration;
|
|
17
|
+
exported: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ModelNode {
|
|
21
|
+
id: number;
|
|
22
|
+
captured: CapturedNode;
|
|
23
|
+
/** The declared type where the object is stored; undefined for functions and services. */
|
|
24
|
+
type?: ts.Type;
|
|
25
|
+
/** The first place setup reached it. Every other place holding it refers to this one. */
|
|
26
|
+
owner?: Owner;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The captured setup graph with each object's owner and declared type. */
|
|
30
|
+
export class Model {
|
|
31
|
+
readonly nodes: ModelNode[];
|
|
32
|
+
readonly roots: Root[] = [];
|
|
33
|
+
readonly rootValues = new Map<Root, CapturedValue>();
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
readonly graph: CapturedGraph,
|
|
37
|
+
readonly checker: ts.TypeChecker,
|
|
38
|
+
readonly program: ts.Program,
|
|
39
|
+
entry: string,
|
|
40
|
+
) {
|
|
41
|
+
this.nodes = graph.nodes.map((captured, id) => ({ id, captured }));
|
|
42
|
+
// Dependencies own what they build before the entry module's instances refer to it.
|
|
43
|
+
const ordered = [
|
|
44
|
+
...graph.bindings.filter((binding) => binding.file !== entry),
|
|
45
|
+
...graph.bindings.filter((binding) => binding.file === entry),
|
|
46
|
+
];
|
|
47
|
+
for (const binding of ordered) {
|
|
48
|
+
const declaration = this.binding(binding.file, binding.name);
|
|
49
|
+
const root: Root = {
|
|
50
|
+
file: binding.file,
|
|
51
|
+
name: binding.name,
|
|
52
|
+
declaration,
|
|
53
|
+
exported: Boolean(ts.getCombinedModifierFlags(declaration) & ts.ModifierFlags.Export),
|
|
54
|
+
};
|
|
55
|
+
this.roots.push(root);
|
|
56
|
+
this.rootValues.set(root, binding.value);
|
|
57
|
+
this.own(binding.value, { root, steps: [] }, checker.getTypeAtLocation(declaration.name));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
node(value: CapturedValue): ModelNode | undefined {
|
|
62
|
+
return value.kind === "node" ? this.nodes[value.id] : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private binding(file: string, name: string): ts.VariableDeclaration {
|
|
66
|
+
const source = this.program.getSourceFile(file);
|
|
67
|
+
for (const statement of source?.statements ?? [])
|
|
68
|
+
if (ts.isVariableStatement(statement))
|
|
69
|
+
for (const declaration of statement.declarationList.declarations)
|
|
70
|
+
if (ts.isIdentifier(declaration.name) && declaration.name.text === name)
|
|
71
|
+
return declaration;
|
|
72
|
+
throw new Error(`${file}: no module binding ${name}.`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The class a captured instance belongs to. */
|
|
76
|
+
classOf(node: ModelNode): ts.ClassDeclaration {
|
|
77
|
+
const captured = node.captured;
|
|
78
|
+
if (captured.kind !== "instance") throw new Error("Not a class instance.");
|
|
79
|
+
const source = this.program.getSourceFile(captured.file);
|
|
80
|
+
const found = source?.statements.find(
|
|
81
|
+
(statement): statement is ts.ClassDeclaration =>
|
|
82
|
+
ts.isClassDeclaration(statement) && statement.name?.text === captured.name,
|
|
83
|
+
);
|
|
84
|
+
if (!found) throw new Error(`${captured.file}: no class ${captured.name}.`);
|
|
85
|
+
return found;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** A class field's declaration: a property, or a constructor parameter property. */
|
|
89
|
+
member(
|
|
90
|
+
declaration: ts.ClassDeclaration,
|
|
91
|
+
name: string,
|
|
92
|
+
): ts.PropertyDeclaration | ts.ParameterDeclaration | undefined {
|
|
93
|
+
for (const member of declaration.members) {
|
|
94
|
+
if (ts.isPropertyDeclaration(member) && member.name.getText() === name) return member;
|
|
95
|
+
if (ts.isConstructorDeclaration(member))
|
|
96
|
+
for (const parameter of member.parameters)
|
|
97
|
+
if (
|
|
98
|
+
ts.isParameterPropertyDeclaration(parameter, member) &&
|
|
99
|
+
parameter.name.getText() === name
|
|
100
|
+
)
|
|
101
|
+
return parameter;
|
|
102
|
+
}
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The declared type of a field of `type` holding `value`, choosing the union member it matches. */
|
|
107
|
+
fieldType(type: ts.Type, name: string, holder: CapturedNode): ts.Type | undefined {
|
|
108
|
+
const variant = this.variant(type, holder);
|
|
109
|
+
const property = variant.getProperty(name) ?? this.checker.getPropertyOfType(variant, name);
|
|
110
|
+
return property && this.checker.getTypeOfSymbol(property);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** The member of a union of object types that a captured object is, by its literal fields. */
|
|
114
|
+
variant(type: ts.Type, value: CapturedNode): ts.Type {
|
|
115
|
+
const candidates = (type.isUnion() ? type.types : [type]).filter(
|
|
116
|
+
(member) => !(member.flags & ts.TypeFlags.Undefined),
|
|
117
|
+
);
|
|
118
|
+
if (candidates.length === 1 || value.kind !== "object") return candidates[0] ?? type;
|
|
119
|
+
return (
|
|
120
|
+
candidates.find((candidate) =>
|
|
121
|
+
Object.entries(value.fields).every(([name, field]) => {
|
|
122
|
+
const property = candidate.getProperty(name);
|
|
123
|
+
if (!property) return false;
|
|
124
|
+
const fieldType = this.checker.getTypeOfSymbol(property);
|
|
125
|
+
return (
|
|
126
|
+
!fieldType.isLiteral() || field.kind !== "string" || fieldType.value === field.value
|
|
127
|
+
);
|
|
128
|
+
}),
|
|
129
|
+
) ?? candidates[0]!
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
elementType(type: ts.Type): ts.Type | undefined {
|
|
134
|
+
const target = this.checker.getNonNullableType(type);
|
|
135
|
+
return (
|
|
136
|
+
this.checker.getIndexTypeOfType(target, ts.IndexKind.Number) ??
|
|
137
|
+
(this.checker.isTupleType(target)
|
|
138
|
+
? this.checker.getTypeArguments(target as ts.TypeReference)[0]
|
|
139
|
+
: undefined)
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private own(value: CapturedValue, owner: Owner, type: ts.Type | undefined): void {
|
|
144
|
+
const node = this.node(value);
|
|
145
|
+
if (!node || node.owner) return;
|
|
146
|
+
node.owner = owner;
|
|
147
|
+
node.type = type;
|
|
148
|
+
const captured = node.captured;
|
|
149
|
+
if (captured.kind === "array") {
|
|
150
|
+
const element = type && this.elementType(type);
|
|
151
|
+
captured.items.forEach((item, index) =>
|
|
152
|
+
this.own(
|
|
153
|
+
item,
|
|
154
|
+
{ root: owner.root, steps: [...owner.steps, { kind: "index", index }] },
|
|
155
|
+
element,
|
|
156
|
+
),
|
|
157
|
+
);
|
|
158
|
+
} else if (captured.kind === "object") {
|
|
159
|
+
for (const [name, field] of Object.entries(captured.fields))
|
|
160
|
+
this.own(
|
|
161
|
+
field,
|
|
162
|
+
{ root: owner.root, steps: [...owner.steps, { kind: "field", name }] },
|
|
163
|
+
type && this.fieldType(type, name, captured),
|
|
164
|
+
);
|
|
165
|
+
} else if (captured.kind === "instance") {
|
|
166
|
+
const declaration = this.classOf(node);
|
|
167
|
+
for (const [name, field] of Object.entries(captured.fields)) {
|
|
168
|
+
const member = this.member(declaration, name);
|
|
169
|
+
this.own(
|
|
170
|
+
field,
|
|
171
|
+
{ root: owner.root, steps: [...owner.steps, { kind: "field", name }] },
|
|
172
|
+
member && this.checker.getTypeAtLocation(member.name),
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|