@hatchingpoint/point 0.0.6 → 0.0.7
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 -21
- package/README.md +34 -34
- package/package.json +34 -30
- package/src/cli.ts +7 -7
- package/src/core/ast.ts +162 -162
- package/src/core/check.ts +412 -412
- package/src/core/cli.ts +497 -497
- package/src/core/context.ts +181 -181
- package/src/core/emit-javascript.ts +124 -124
- package/src/core/emit-typescript.ts +166 -166
- package/src/core/format.ts +6 -6
- package/src/core/incremental.ts +53 -53
- package/src/core/index.ts +12 -12
- package/src/core/lexer.ts +234 -234
- package/src/core/semantic-source.ts +26 -26
- package/src/core/serialize.ts +18 -18
- package/src/core/test-only/core-text-parser.ts +400 -400
- package/src/core/test-only/format-core.ts +120 -120
- package/src/core/test-only/index.ts +3 -3
- package/src/core/test-only/legacy-lowering.ts +1030 -1030
- package/src/index.ts +1 -1
- package/src/semantic/ast.ts +230 -230
- package/src/semantic/callables.ts +51 -51
- package/src/semantic/context.ts +347 -347
- package/src/semantic/desugar.ts +665 -665
- package/src/semantic/expressions.ts +347 -347
- package/src/semantic/format.ts +222 -222
- package/src/semantic/index.ts +10 -10
- package/src/semantic/metadata.ts +37 -37
- package/src/semantic/naming.ts +33 -33
- package/src/semantic/parse.ts +945 -945
- package/src/semantic/serialize.ts +18 -18
package/src/core/context.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PointCoreDeclaration,
|
|
3
|
-
PointCoreFunctionDeclaration,
|
|
4
|
-
PointCoreProgram,
|
|
5
|
-
PointCoreTypeDeclaration,
|
|
6
|
-
PointCoreTypeExpression,
|
|
7
|
-
PointCoreValueDeclaration,
|
|
8
|
-
PointSourceSpan,
|
|
9
|
-
} from "./ast.ts";
|
|
10
|
-
import type {
|
|
11
|
-
PointCoreDiagnostic,
|
|
12
|
-
} from "./check.ts";
|
|
13
|
-
|
|
1
|
+
import type {
|
|
2
|
+
PointCoreDeclaration,
|
|
3
|
+
PointCoreFunctionDeclaration,
|
|
4
|
+
PointCoreProgram,
|
|
5
|
+
PointCoreTypeDeclaration,
|
|
6
|
+
PointCoreTypeExpression,
|
|
7
|
+
PointCoreValueDeclaration,
|
|
8
|
+
PointSourceSpan,
|
|
9
|
+
} from "./ast.ts";
|
|
10
|
+
import type {
|
|
11
|
+
PointCoreDiagnostic,
|
|
12
|
+
} from "./check.ts";
|
|
13
|
+
|
|
14
14
|
export type PointCoreSymbolKind =
|
|
15
15
|
| "module"
|
|
16
16
|
| "import"
|
|
@@ -30,62 +30,62 @@ export type PointCoreSymbolKind =
|
|
|
30
30
|
| "route"
|
|
31
31
|
| "workflow"
|
|
32
32
|
| "command";
|
|
33
|
-
|
|
34
|
-
export interface PointCoreSymbol {
|
|
35
|
-
ref: string;
|
|
36
|
-
path: string;
|
|
37
|
-
kind: PointCoreSymbolKind;
|
|
38
|
-
name: string;
|
|
39
|
-
module: string;
|
|
40
|
-
type?: string;
|
|
41
|
-
mutable?: boolean;
|
|
33
|
+
|
|
34
|
+
export interface PointCoreSymbol {
|
|
35
|
+
ref: string;
|
|
36
|
+
path: string;
|
|
37
|
+
kind: PointCoreSymbolKind;
|
|
38
|
+
name: string;
|
|
39
|
+
module: string;
|
|
40
|
+
type?: string;
|
|
41
|
+
mutable?: boolean;
|
|
42
42
|
from?: string;
|
|
43
43
|
effects?: string[];
|
|
44
44
|
span: PointSourceSpan | null;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface PointCoreIndex {
|
|
48
|
-
schemaVersion: "point.core.index.v1";
|
|
49
|
-
module: string;
|
|
50
|
-
refs: PointCoreSymbol[];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface PointCoreExplanation {
|
|
54
|
-
schemaVersion: "point.core.explain.v1";
|
|
55
|
-
ref: string;
|
|
56
|
-
found: boolean;
|
|
57
|
-
symbol?: PointCoreSymbol;
|
|
58
|
-
relatedRefs: string[];
|
|
59
|
-
summary: string;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface PointCoreRepairPlan {
|
|
63
|
-
schemaVersion: "point.core.repair-plan.v1";
|
|
64
|
-
ok: boolean;
|
|
65
|
-
steps: PointCoreRepairStep[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface PointCoreRepairStep {
|
|
69
|
-
ref: string;
|
|
70
|
-
code: string;
|
|
71
|
-
message: string;
|
|
72
|
-
repair: string;
|
|
73
|
-
expected?: string | string[];
|
|
74
|
-
actual?: string;
|
|
75
|
-
relatedRefs: string[];
|
|
76
|
-
}
|
|
77
|
-
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface PointCoreIndex {
|
|
48
|
+
schemaVersion: "point.core.index.v1";
|
|
49
|
+
module: string;
|
|
50
|
+
refs: PointCoreSymbol[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PointCoreExplanation {
|
|
54
|
+
schemaVersion: "point.core.explain.v1";
|
|
55
|
+
ref: string;
|
|
56
|
+
found: boolean;
|
|
57
|
+
symbol?: PointCoreSymbol;
|
|
58
|
+
relatedRefs: string[];
|
|
59
|
+
summary: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface PointCoreRepairPlan {
|
|
63
|
+
schemaVersion: "point.core.repair-plan.v1";
|
|
64
|
+
ok: boolean;
|
|
65
|
+
steps: PointCoreRepairStep[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface PointCoreRepairStep {
|
|
69
|
+
ref: string;
|
|
70
|
+
code: string;
|
|
71
|
+
message: string;
|
|
72
|
+
repair: string;
|
|
73
|
+
expected?: string | string[];
|
|
74
|
+
actual?: string;
|
|
75
|
+
relatedRefs: string[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
78
|
export function createPointCoreIndex(program: PointCoreProgram): PointCoreIndex {
|
|
79
79
|
const moduleName = program.module ?? "anonymous";
|
|
80
|
-
const refs: PointCoreSymbol[] = [
|
|
81
|
-
{
|
|
82
|
-
ref: refFor(moduleName, "module"),
|
|
83
|
-
path: "module",
|
|
84
|
-
kind: "module",
|
|
85
|
-
name: moduleName,
|
|
86
|
-
module: moduleName,
|
|
87
|
-
span: program.span ?? null,
|
|
88
|
-
},
|
|
80
|
+
const refs: PointCoreSymbol[] = [
|
|
81
|
+
{
|
|
82
|
+
ref: refFor(moduleName, "module"),
|
|
83
|
+
path: "module",
|
|
84
|
+
kind: "module",
|
|
85
|
+
name: moduleName,
|
|
86
|
+
module: moduleName,
|
|
87
|
+
span: program.span ?? null,
|
|
88
|
+
},
|
|
89
89
|
];
|
|
90
90
|
for (const declaration of program.declarations) {
|
|
91
91
|
refs.push(...symbolsForDeclaration(moduleName, declaration));
|
|
@@ -93,44 +93,44 @@ export function createPointCoreIndex(program: PointCoreProgram): PointCoreIndex
|
|
|
93
93
|
}
|
|
94
94
|
return { schemaVersion: "point.core.index.v1", module: moduleName, refs };
|
|
95
95
|
}
|
|
96
|
-
|
|
97
|
-
export function explainPointCoreRef(program: PointCoreProgram, ref: string): PointCoreExplanation {
|
|
98
|
-
const index = createPointCoreIndex(program);
|
|
99
|
-
const symbol = index.refs.find((candidate) => candidate.ref === ref);
|
|
100
|
-
if (!symbol) {
|
|
101
|
-
return {
|
|
102
|
-
schemaVersion: "point.core.explain.v1",
|
|
103
|
-
ref,
|
|
104
|
-
found: false,
|
|
105
|
-
relatedRefs: [],
|
|
106
|
-
summary: `No Point symbol found for ${ref}.`,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
const relatedRefs = relatedRefsFor(symbol, index);
|
|
110
|
-
return {
|
|
111
|
-
schemaVersion: "point.core.explain.v1",
|
|
112
|
-
ref,
|
|
113
|
-
found: true,
|
|
114
|
-
symbol,
|
|
115
|
-
relatedRefs,
|
|
116
|
-
summary: summaryFor(symbol),
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
96
|
+
|
|
97
|
+
export function explainPointCoreRef(program: PointCoreProgram, ref: string): PointCoreExplanation {
|
|
98
|
+
const index = createPointCoreIndex(program);
|
|
99
|
+
const symbol = index.refs.find((candidate) => candidate.ref === ref);
|
|
100
|
+
if (!symbol) {
|
|
101
|
+
return {
|
|
102
|
+
schemaVersion: "point.core.explain.v1",
|
|
103
|
+
ref,
|
|
104
|
+
found: false,
|
|
105
|
+
relatedRefs: [],
|
|
106
|
+
summary: `No Point symbol found for ${ref}.`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const relatedRefs = relatedRefsFor(symbol, index);
|
|
110
|
+
return {
|
|
111
|
+
schemaVersion: "point.core.explain.v1",
|
|
112
|
+
ref,
|
|
113
|
+
found: true,
|
|
114
|
+
symbol,
|
|
115
|
+
relatedRefs,
|
|
116
|
+
summary: summaryFor(symbol),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
120
|
export function createPointCoreRepairPlan(diagnostics: PointCoreDiagnostic[]): PointCoreRepairPlan {
|
|
121
|
-
return {
|
|
122
|
-
schemaVersion: "point.core.repair-plan.v1",
|
|
123
|
-
ok: diagnostics.length === 0,
|
|
124
|
-
steps: diagnostics.map((diagnostic) => ({
|
|
125
|
-
ref: diagnostic.ref,
|
|
126
|
-
code: diagnostic.code,
|
|
127
|
-
message: diagnostic.message,
|
|
128
|
-
repair: diagnostic.repair ?? "Inspect this ref and update the Point source.",
|
|
129
|
-
expected: diagnostic.expected,
|
|
130
|
-
actual: diagnostic.actual,
|
|
131
|
-
relatedRefs: diagnostic.relatedRefs ?? [],
|
|
132
|
-
})),
|
|
133
|
-
};
|
|
121
|
+
return {
|
|
122
|
+
schemaVersion: "point.core.repair-plan.v1",
|
|
123
|
+
ok: diagnostics.length === 0,
|
|
124
|
+
steps: diagnostics.map((diagnostic) => ({
|
|
125
|
+
ref: diagnostic.ref,
|
|
126
|
+
code: diagnostic.code,
|
|
127
|
+
message: diagnostic.message,
|
|
128
|
+
repair: diagnostic.repair ?? "Inspect this ref and update the Point source.",
|
|
129
|
+
expected: diagnostic.expected,
|
|
130
|
+
actual: diagnostic.actual,
|
|
131
|
+
relatedRefs: diagnostic.relatedRefs ?? [],
|
|
132
|
+
})),
|
|
133
|
+
};
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
export function mapDiagnosticsToSemanticRefs(program: PointCoreProgram, diagnostics: PointCoreDiagnostic[]): PointCoreDiagnostic[] {
|
|
@@ -140,16 +140,16 @@ export function mapDiagnosticsToSemanticRefs(program: PointCoreProgram, diagnost
|
|
|
140
140
|
relatedRefs: diagnostic.relatedRefs?.map((ref) => semanticRefForCoreRef(program, ref) ?? ref),
|
|
141
141
|
}));
|
|
142
142
|
}
|
|
143
|
-
|
|
144
|
-
function symbolsForDeclaration(moduleName: string, declaration: PointCoreDeclaration): PointCoreSymbol[] {
|
|
143
|
+
|
|
144
|
+
function symbolsForDeclaration(moduleName: string, declaration: PointCoreDeclaration): PointCoreSymbol[] {
|
|
145
145
|
if (declaration.kind === "import") {
|
|
146
146
|
return declaration.names.map((name) => ({
|
|
147
|
-
ref: refFor(moduleName, `import.${name}`),
|
|
148
|
-
path: `import.${name}`,
|
|
149
|
-
kind: "import",
|
|
150
|
-
name,
|
|
151
|
-
module: moduleName,
|
|
152
|
-
from: declaration.from,
|
|
147
|
+
ref: refFor(moduleName, `import.${name}`),
|
|
148
|
+
path: `import.${name}`,
|
|
149
|
+
kind: "import",
|
|
150
|
+
name,
|
|
151
|
+
module: moduleName,
|
|
152
|
+
from: declaration.from,
|
|
153
153
|
span: declaration.span ?? null,
|
|
154
154
|
}));
|
|
155
155
|
}
|
|
@@ -170,65 +170,65 @@ function symbolsForDeclaration(moduleName: string, declaration: PointCoreDeclara
|
|
|
170
170
|
if (declaration.kind === "value") return [valueSymbol(moduleName, declaration, `value.${declaration.name}`)];
|
|
171
171
|
if (declaration.kind === "type") return typeSymbols(moduleName, declaration);
|
|
172
172
|
return functionSymbols(moduleName, declaration);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function valueSymbol(moduleName: string, declaration: PointCoreValueDeclaration, path: string): PointCoreSymbol {
|
|
176
|
-
return {
|
|
177
|
-
ref: refFor(moduleName, path),
|
|
178
|
-
path,
|
|
179
|
-
kind: "value",
|
|
180
|
-
name: declaration.name,
|
|
181
|
-
module: moduleName,
|
|
182
|
-
type: formatType(declaration.type),
|
|
183
|
-
mutable: declaration.mutable,
|
|
184
|
-
span: declaration.span ?? null,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function typeSymbols(moduleName: string, declaration: PointCoreTypeDeclaration): PointCoreSymbol[] {
|
|
189
|
-
return [
|
|
190
|
-
{
|
|
191
|
-
ref: refFor(moduleName, `type.${declaration.name}`),
|
|
192
|
-
path: `type.${declaration.name}`,
|
|
193
|
-
kind: "type",
|
|
194
|
-
name: declaration.name,
|
|
195
|
-
module: moduleName,
|
|
196
|
-
span: declaration.span ?? null,
|
|
197
|
-
},
|
|
198
|
-
...declaration.fields.map((field) => ({
|
|
199
|
-
ref: refFor(moduleName, `type.${declaration.name}.${field.name}`),
|
|
200
|
-
path: `type.${declaration.name}.${field.name}`,
|
|
201
|
-
kind: "field" as const,
|
|
202
|
-
name: field.name,
|
|
203
|
-
module: moduleName,
|
|
204
|
-
type: formatType(field.type),
|
|
205
|
-
span: field.span ?? null,
|
|
206
|
-
})),
|
|
207
|
-
];
|
|
208
|
-
}
|
|
209
|
-
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function valueSymbol(moduleName: string, declaration: PointCoreValueDeclaration, path: string): PointCoreSymbol {
|
|
176
|
+
return {
|
|
177
|
+
ref: refFor(moduleName, path),
|
|
178
|
+
path,
|
|
179
|
+
kind: "value",
|
|
180
|
+
name: declaration.name,
|
|
181
|
+
module: moduleName,
|
|
182
|
+
type: formatType(declaration.type),
|
|
183
|
+
mutable: declaration.mutable,
|
|
184
|
+
span: declaration.span ?? null,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function typeSymbols(moduleName: string, declaration: PointCoreTypeDeclaration): PointCoreSymbol[] {
|
|
189
|
+
return [
|
|
190
|
+
{
|
|
191
|
+
ref: refFor(moduleName, `type.${declaration.name}`),
|
|
192
|
+
path: `type.${declaration.name}`,
|
|
193
|
+
kind: "type",
|
|
194
|
+
name: declaration.name,
|
|
195
|
+
module: moduleName,
|
|
196
|
+
span: declaration.span ?? null,
|
|
197
|
+
},
|
|
198
|
+
...declaration.fields.map((field) => ({
|
|
199
|
+
ref: refFor(moduleName, `type.${declaration.name}.${field.name}`),
|
|
200
|
+
path: `type.${declaration.name}.${field.name}`,
|
|
201
|
+
kind: "field" as const,
|
|
202
|
+
name: field.name,
|
|
203
|
+
module: moduleName,
|
|
204
|
+
type: formatType(field.type),
|
|
205
|
+
span: field.span ?? null,
|
|
206
|
+
})),
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
210
|
function functionSymbols(moduleName: string, declaration: PointCoreFunctionDeclaration): PointCoreSymbol[] {
|
|
211
|
-
return [
|
|
212
|
-
{
|
|
213
|
-
ref: refFor(moduleName, `fn.${declaration.name}`),
|
|
214
|
-
path: `fn.${declaration.name}`,
|
|
215
|
-
kind: "function",
|
|
216
|
-
name: declaration.name,
|
|
217
|
-
module: moduleName,
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
ref: refFor(moduleName, `fn.${declaration.name}`),
|
|
214
|
+
path: `fn.${declaration.name}`,
|
|
215
|
+
kind: "function",
|
|
216
|
+
name: declaration.name,
|
|
217
|
+
module: moduleName,
|
|
218
218
|
type: formatType(declaration.returnType),
|
|
219
219
|
effects: declaration.semantic?.effects,
|
|
220
220
|
span: declaration.span ?? null,
|
|
221
221
|
},
|
|
222
|
-
...declaration.params.map((param) => ({
|
|
223
|
-
ref: refFor(moduleName, `fn.${declaration.name}.param.${param.name}`),
|
|
224
|
-
path: `fn.${declaration.name}.param.${param.name}`,
|
|
225
|
-
kind: "param" as const,
|
|
226
|
-
name: param.name,
|
|
227
|
-
module: moduleName,
|
|
228
|
-
type: formatType(param.type),
|
|
229
|
-
span: param.span ?? null,
|
|
230
|
-
})),
|
|
231
|
-
];
|
|
222
|
+
...declaration.params.map((param) => ({
|
|
223
|
+
ref: refFor(moduleName, `fn.${declaration.name}.param.${param.name}`),
|
|
224
|
+
path: `fn.${declaration.name}.param.${param.name}`,
|
|
225
|
+
kind: "param" as const,
|
|
226
|
+
name: param.name,
|
|
227
|
+
module: moduleName,
|
|
228
|
+
type: formatType(param.type),
|
|
229
|
+
span: param.span ?? null,
|
|
230
|
+
})),
|
|
231
|
+
];
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
function semanticSymbolsForDeclaration(moduleName: string, declaration: PointCoreDeclaration): PointCoreSymbol[] {
|
|
@@ -311,12 +311,12 @@ function refFor(moduleName: string, path: string): string {
|
|
|
311
311
|
function semanticRefFor(moduleName: string, path: string): string {
|
|
312
312
|
return `point://semantic/${moduleName}/${path}`;
|
|
313
313
|
}
|
|
314
|
-
|
|
315
|
-
function relatedRefsFor(symbol: PointCoreSymbol, index: PointCoreIndex): string[] {
|
|
316
|
-
if (symbol.kind === "field") {
|
|
317
|
-
const ownerPath = symbol.path.split(".").slice(0, 2).join(".");
|
|
318
|
-
return index.refs.filter((candidate) => candidate.path.startsWith(`${ownerPath}.`) && candidate.ref !== symbol.ref).map((candidate) => candidate.ref);
|
|
319
|
-
}
|
|
314
|
+
|
|
315
|
+
function relatedRefsFor(symbol: PointCoreSymbol, index: PointCoreIndex): string[] {
|
|
316
|
+
if (symbol.kind === "field") {
|
|
317
|
+
const ownerPath = symbol.path.split(".").slice(0, 2).join(".");
|
|
318
|
+
return index.refs.filter((candidate) => candidate.path.startsWith(`${ownerPath}.`) && candidate.ref !== symbol.ref).map((candidate) => candidate.ref);
|
|
319
|
+
}
|
|
320
320
|
if (
|
|
321
321
|
symbol.kind === "function" ||
|
|
322
322
|
symbol.kind === "calculation" ||
|
|
@@ -333,16 +333,16 @@ function relatedRefsFor(symbol: PointCoreSymbol, index: PointCoreIndex): string[
|
|
|
333
333
|
.filter((candidate) => candidate.path.startsWith(`${symbol.path}.param.`) || candidate.path.startsWith(`${symbol.path}.input.`))
|
|
334
334
|
.map((candidate) => candidate.ref);
|
|
335
335
|
}
|
|
336
|
-
return [];
|
|
337
|
-
}
|
|
338
|
-
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
339
|
function summaryFor(symbol: PointCoreSymbol): string {
|
|
340
|
-
if (symbol.kind === "module") return `Module ${symbol.name}.`;
|
|
341
|
-
if (symbol.kind === "import") return `Import ${symbol.name} from ${symbol.from}.`;
|
|
342
|
-
if (symbol.kind === "value") return `${symbol.mutable ? "Mutable" : "Immutable"} value ${symbol.name}: ${symbol.type}.`;
|
|
340
|
+
if (symbol.kind === "module") return `Module ${symbol.name}.`;
|
|
341
|
+
if (symbol.kind === "import") return `Import ${symbol.name} from ${symbol.from}.`;
|
|
342
|
+
if (symbol.kind === "value") return `${symbol.mutable ? "Mutable" : "Immutable"} value ${symbol.name}: ${symbol.type}.`;
|
|
343
343
|
if (symbol.kind === "function") return `Function ${symbol.name} returns ${symbol.type}.`;
|
|
344
344
|
if (symbol.kind === "external") return `External function ${symbol.name} from ${symbol.from} returns ${symbol.type}.`;
|
|
345
|
-
if (symbol.kind === "param") return `Parameter ${symbol.name}: ${symbol.type}.`;
|
|
345
|
+
if (symbol.kind === "param") return `Parameter ${symbol.name}: ${symbol.type}.`;
|
|
346
346
|
if (symbol.kind === "type") return `Named type ${symbol.name}.`;
|
|
347
347
|
if (symbol.kind === "record") return `Semantic record ${symbol.name}.`;
|
|
348
348
|
if (symbol.kind === "calculation") return `Semantic calculation ${symbol.name} returns ${symbol.type}.`;
|
|
@@ -387,8 +387,8 @@ function semanticRefForDiagnosticPath(program: PointCoreProgram, path: string):
|
|
|
387
387
|
}
|
|
388
388
|
return null;
|
|
389
389
|
}
|
|
390
|
-
|
|
391
|
-
function formatType(type: PointCoreTypeExpression): string {
|
|
392
|
-
if (type.args.length === 0) return String(type.name);
|
|
393
|
-
return `${type.name}<${type.args.map(formatType).join(", ")}>`;
|
|
394
|
-
}
|
|
390
|
+
|
|
391
|
+
function formatType(type: PointCoreTypeExpression): string {
|
|
392
|
+
if (type.args.length === 0) return String(type.name);
|
|
393
|
+
return `${type.name}<${type.args.map(formatType).join(", ")}>`;
|
|
394
|
+
}
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
PointCoreDeclaration,
|
|
3
|
-
PointCoreExpression,
|
|
4
|
-
PointCoreFunctionDeclaration,
|
|
5
|
-
PointCoreParameter,
|
|
6
|
-
PointCoreProgram,
|
|
7
|
-
PointCoreStatement,
|
|
8
|
-
PointCoreTypeDeclaration,
|
|
9
|
-
PointCoreValueDeclaration,
|
|
10
|
-
} from "./ast.ts";
|
|
11
|
-
|
|
12
|
-
const BINARY_OPERATORS: Record<string, string> = {
|
|
13
|
-
and: "&&",
|
|
14
|
-
or: "||",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/** Emit JavaScript from a core AST program (no type syntax). Production path: parsePointSource → check → emit. */
|
|
18
|
-
export function emitPointCoreJavaScript(program: PointCoreProgram): string {
|
|
19
|
-
const lines: string[] = [];
|
|
20
|
-
lines.push("// Generated by Point. Do not edit directly.");
|
|
21
|
-
if (program.module) lines.push(`// Point module: ${program.module}`);
|
|
22
|
-
lines.push("");
|
|
23
|
-
for (const declaration of program.declarations) {
|
|
24
|
-
lines.push(...emitDeclaration(declaration), "");
|
|
25
|
-
}
|
|
26
|
-
return `${trimTrailingBlankLines(lines).join("\n")}\n`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function emitDeclaration(declaration: PointCoreDeclaration): string[] {
|
|
30
|
-
if (declaration.kind === "import") {
|
|
31
|
-
return [`import { ${declaration.names.join(", ")} } from ${JSON.stringify(declaration.from)};`];
|
|
32
|
-
}
|
|
33
|
-
if (declaration.kind === "external") {
|
|
34
|
-
const imported = declaration.importName ? `${declaration.importName} as ${declaration.name}` : declaration.name;
|
|
35
|
-
return [`import { ${imported} } from ${JSON.stringify(declaration.from)};`];
|
|
36
|
-
}
|
|
37
|
-
if (declaration.kind === "type") return [];
|
|
38
|
-
if (declaration.kind === "value") return [emitValue(declaration, true)];
|
|
39
|
-
return emitFunction(declaration);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function emitFunction(declaration: PointCoreFunctionDeclaration): string[] {
|
|
43
|
-
const asyncPrefix = declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command" ? "async " : "";
|
|
44
|
-
return [
|
|
45
|
-
`export ${asyncPrefix}function ${declaration.name}(${declaration.params.map(emitParam).join(", ")}) {`,
|
|
46
|
-
...indentLines(declaration.body.flatMap((statement) => emitStatement(statement, declaration.semantic?.kind))),
|
|
47
|
-
"}",
|
|
48
|
-
];
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function emitStatement(statement: PointCoreStatement, semanticKind?: string): string[] {
|
|
52
|
-
if (statement.kind === "return") {
|
|
53
|
-
if (semanticKind === "view" && statement.value?.kind === "literal" && typeof statement.value.value === "string") {
|
|
54
|
-
return [`return ${JSON.stringify(statement.value.value)};`];
|
|
55
|
-
}
|
|
56
|
-
return [statement.value ? `return ${emitExpression(statement.value)};` : "return;"];
|
|
57
|
-
}
|
|
58
|
-
if (statement.kind === "value") return [emitValue(statement, false)];
|
|
59
|
-
if (statement.kind === "assignment") return [`${statement.name} ${statement.operator} ${emitExpression(statement.value)};`];
|
|
60
|
-
if (statement.kind === "if") {
|
|
61
|
-
const lines = [
|
|
62
|
-
`if (${emitCondition(statement.condition)}) {`,
|
|
63
|
-
...indentLines(statement.thenBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
64
|
-
"}",
|
|
65
|
-
];
|
|
66
|
-
if (statement.elseBody.length > 0) {
|
|
67
|
-
lines.push(
|
|
68
|
-
"else {",
|
|
69
|
-
...indentLines(statement.elseBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
70
|
-
"}",
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
return lines;
|
|
74
|
-
}
|
|
75
|
-
if (statement.kind === "for") {
|
|
76
|
-
return [
|
|
77
|
-
`for (const ${statement.itemName} of ${emitExpression(statement.iterable)}) {`,
|
|
78
|
-
...indentLines(statement.body.flatMap((child) => emitStatement(child, semanticKind))),
|
|
79
|
-
"}",
|
|
80
|
-
];
|
|
81
|
-
}
|
|
82
|
-
return [`${emitExpression(statement.value)};`];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function emitValue(declaration: PointCoreValueDeclaration, exported: boolean): string {
|
|
86
|
-
const prefix = exported ? "export " : "";
|
|
87
|
-
const keyword = declaration.mutable ? "let" : "const";
|
|
88
|
-
return `${prefix}${keyword} ${declaration.name} = ${emitExpression(declaration.value)};`;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function emitParam(param: PointCoreParameter): string {
|
|
92
|
-
return param.name;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function emitExpression(expression: PointCoreExpression): string {
|
|
96
|
-
if (expression.kind === "literal") return JSON.stringify(expression.value);
|
|
97
|
-
if (expression.kind === "identifier") return expression.name;
|
|
98
|
-
if (expression.kind === "list") return `[${expression.items.map(emitExpression).join(", ")}]`;
|
|
99
|
-
if (expression.kind === "record") {
|
|
100
|
-
return `{ ${expression.fields.map((field) => `${field.name}: ${emitExpression(field.value)}`).join(", ")} }`;
|
|
101
|
-
}
|
|
102
|
-
if (expression.kind === "await") return `await ${emitExpression(expression.value)}`;
|
|
103
|
-
if (expression.kind === "property") return `${emitExpression(expression.target)}.${expression.name}`;
|
|
104
|
-
if (expression.kind === "call") {
|
|
105
|
-
if (expression.callee === "Error") return `{ message: ${expression.args[0] ? emitExpression(expression.args[0]) : JSON.stringify("")} }`;
|
|
106
|
-
return `${expression.callee}(${expression.args.map(emitExpression).join(", ")})`;
|
|
107
|
-
}
|
|
108
|
-
const operator = BINARY_OPERATORS[expression.operator] ?? expression.operator;
|
|
109
|
-
return `(${emitExpression(expression.left)} ${operator} ${emitExpression(expression.right)})`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function emitCondition(expression: PointCoreExpression): string {
|
|
113
|
-
const emitted = emitExpression(expression);
|
|
114
|
-
return emitted.startsWith("(") && emitted.endsWith(")") ? emitted.slice(1, -1) : emitted;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function indentLines(lines: string[]): string[] {
|
|
118
|
-
return lines.map((line) => ` ${line}`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function trimTrailingBlankLines(lines: string[]): string[] {
|
|
122
|
-
while (lines.at(-1) === "") lines.pop();
|
|
123
|
-
return lines;
|
|
124
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
PointCoreDeclaration,
|
|
3
|
+
PointCoreExpression,
|
|
4
|
+
PointCoreFunctionDeclaration,
|
|
5
|
+
PointCoreParameter,
|
|
6
|
+
PointCoreProgram,
|
|
7
|
+
PointCoreStatement,
|
|
8
|
+
PointCoreTypeDeclaration,
|
|
9
|
+
PointCoreValueDeclaration,
|
|
10
|
+
} from "./ast.ts";
|
|
11
|
+
|
|
12
|
+
const BINARY_OPERATORS: Record<string, string> = {
|
|
13
|
+
and: "&&",
|
|
14
|
+
or: "||",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Emit JavaScript from a core AST program (no type syntax). Production path: parsePointSource → check → emit. */
|
|
18
|
+
export function emitPointCoreJavaScript(program: PointCoreProgram): string {
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
lines.push("// Generated by Point. Do not edit directly.");
|
|
21
|
+
if (program.module) lines.push(`// Point module: ${program.module}`);
|
|
22
|
+
lines.push("");
|
|
23
|
+
for (const declaration of program.declarations) {
|
|
24
|
+
lines.push(...emitDeclaration(declaration), "");
|
|
25
|
+
}
|
|
26
|
+
return `${trimTrailingBlankLines(lines).join("\n")}\n`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function emitDeclaration(declaration: PointCoreDeclaration): string[] {
|
|
30
|
+
if (declaration.kind === "import") {
|
|
31
|
+
return [`import { ${declaration.names.join(", ")} } from ${JSON.stringify(declaration.from)};`];
|
|
32
|
+
}
|
|
33
|
+
if (declaration.kind === "external") {
|
|
34
|
+
const imported = declaration.importName ? `${declaration.importName} as ${declaration.name}` : declaration.name;
|
|
35
|
+
return [`import { ${imported} } from ${JSON.stringify(declaration.from)};`];
|
|
36
|
+
}
|
|
37
|
+
if (declaration.kind === "type") return [];
|
|
38
|
+
if (declaration.kind === "value") return [emitValue(declaration, true)];
|
|
39
|
+
return emitFunction(declaration);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function emitFunction(declaration: PointCoreFunctionDeclaration): string[] {
|
|
43
|
+
const asyncPrefix = declaration.semantic?.kind === "action" || declaration.semantic?.kind === "workflow" || declaration.semantic?.kind === "command" ? "async " : "";
|
|
44
|
+
return [
|
|
45
|
+
`export ${asyncPrefix}function ${declaration.name}(${declaration.params.map(emitParam).join(", ")}) {`,
|
|
46
|
+
...indentLines(declaration.body.flatMap((statement) => emitStatement(statement, declaration.semantic?.kind))),
|
|
47
|
+
"}",
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function emitStatement(statement: PointCoreStatement, semanticKind?: string): string[] {
|
|
52
|
+
if (statement.kind === "return") {
|
|
53
|
+
if (semanticKind === "view" && statement.value?.kind === "literal" && typeof statement.value.value === "string") {
|
|
54
|
+
return [`return ${JSON.stringify(statement.value.value)};`];
|
|
55
|
+
}
|
|
56
|
+
return [statement.value ? `return ${emitExpression(statement.value)};` : "return;"];
|
|
57
|
+
}
|
|
58
|
+
if (statement.kind === "value") return [emitValue(statement, false)];
|
|
59
|
+
if (statement.kind === "assignment") return [`${statement.name} ${statement.operator} ${emitExpression(statement.value)};`];
|
|
60
|
+
if (statement.kind === "if") {
|
|
61
|
+
const lines = [
|
|
62
|
+
`if (${emitCondition(statement.condition)}) {`,
|
|
63
|
+
...indentLines(statement.thenBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
64
|
+
"}",
|
|
65
|
+
];
|
|
66
|
+
if (statement.elseBody.length > 0) {
|
|
67
|
+
lines.push(
|
|
68
|
+
"else {",
|
|
69
|
+
...indentLines(statement.elseBody.flatMap((child) => emitStatement(child, semanticKind))),
|
|
70
|
+
"}",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return lines;
|
|
74
|
+
}
|
|
75
|
+
if (statement.kind === "for") {
|
|
76
|
+
return [
|
|
77
|
+
`for (const ${statement.itemName} of ${emitExpression(statement.iterable)}) {`,
|
|
78
|
+
...indentLines(statement.body.flatMap((child) => emitStatement(child, semanticKind))),
|
|
79
|
+
"}",
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
return [`${emitExpression(statement.value)};`];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function emitValue(declaration: PointCoreValueDeclaration, exported: boolean): string {
|
|
86
|
+
const prefix = exported ? "export " : "";
|
|
87
|
+
const keyword = declaration.mutable ? "let" : "const";
|
|
88
|
+
return `${prefix}${keyword} ${declaration.name} = ${emitExpression(declaration.value)};`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function emitParam(param: PointCoreParameter): string {
|
|
92
|
+
return param.name;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function emitExpression(expression: PointCoreExpression): string {
|
|
96
|
+
if (expression.kind === "literal") return JSON.stringify(expression.value);
|
|
97
|
+
if (expression.kind === "identifier") return expression.name;
|
|
98
|
+
if (expression.kind === "list") return `[${expression.items.map(emitExpression).join(", ")}]`;
|
|
99
|
+
if (expression.kind === "record") {
|
|
100
|
+
return `{ ${expression.fields.map((field) => `${field.name}: ${emitExpression(field.value)}`).join(", ")} }`;
|
|
101
|
+
}
|
|
102
|
+
if (expression.kind === "await") return `await ${emitExpression(expression.value)}`;
|
|
103
|
+
if (expression.kind === "property") return `${emitExpression(expression.target)}.${expression.name}`;
|
|
104
|
+
if (expression.kind === "call") {
|
|
105
|
+
if (expression.callee === "Error") return `{ message: ${expression.args[0] ? emitExpression(expression.args[0]) : JSON.stringify("")} }`;
|
|
106
|
+
return `${expression.callee}(${expression.args.map(emitExpression).join(", ")})`;
|
|
107
|
+
}
|
|
108
|
+
const operator = BINARY_OPERATORS[expression.operator] ?? expression.operator;
|
|
109
|
+
return `(${emitExpression(expression.left)} ${operator} ${emitExpression(expression.right)})`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function emitCondition(expression: PointCoreExpression): string {
|
|
113
|
+
const emitted = emitExpression(expression);
|
|
114
|
+
return emitted.startsWith("(") && emitted.endsWith(")") ? emitted.slice(1, -1) : emitted;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function indentLines(lines: string[]): string[] {
|
|
118
|
+
return lines.map((line) => ` ${line}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function trimTrailingBlankLines(lines: string[]): string[] {
|
|
122
|
+
while (lines.at(-1) === "") lines.pop();
|
|
123
|
+
return lines;
|
|
124
|
+
}
|