stone-lang 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/README.md +52 -0
- package/StoneEngine.js +879 -0
- package/StoneEngineService.js +1727 -0
- package/adapters/FileSystemAdapter.js +230 -0
- package/adapters/OutputAdapter.js +208 -0
- package/adapters/index.js +6 -0
- package/cli/CLIOutputAdapter.js +196 -0
- package/cli/DaemonClient.js +349 -0
- package/cli/JSONOutputAdapter.js +135 -0
- package/cli/ReplSession.js +567 -0
- package/cli/ViewerServer.js +590 -0
- package/cli/commands/check.js +84 -0
- package/cli/commands/daemon.js +189 -0
- package/cli/commands/kill.js +66 -0
- package/cli/commands/package.js +713 -0
- package/cli/commands/ps.js +65 -0
- package/cli/commands/run.js +537 -0
- package/cli/entry.js +169 -0
- package/cli/index.js +14 -0
- package/cli/stonec.js +358 -0
- package/cli/test-compiler.js +181 -0
- package/cli/viewer/index.html +495 -0
- package/daemon/IPCServer.js +455 -0
- package/daemon/ProcessManager.js +327 -0
- package/daemon/ProcessRunner.js +307 -0
- package/daemon/daemon.js +398 -0
- package/daemon/index.js +16 -0
- package/frontend/analysis/index.js +5 -0
- package/frontend/analysis/livenessAnalyzer.js +568 -0
- package/frontend/analysis/treeShaker.js +265 -0
- package/frontend/index.js +20 -0
- package/frontend/parsing/astBuilder.js +2196 -0
- package/frontend/parsing/index.js +7 -0
- package/frontend/parsing/sonParser.js +592 -0
- package/frontend/parsing/stoneAstTypes.js +703 -0
- package/frontend/parsing/terminal-registry.js +435 -0
- package/frontend/parsing/tokenizer.js +692 -0
- package/frontend/type-checker/OverloadedFunctionType.js +43 -0
- package/frontend/type-checker/TypeEnvironment.js +165 -0
- package/frontend/type-checker/bidirectionalInference.js +149 -0
- package/frontend/type-checker/index.js +10 -0
- package/frontend/type-checker/moduleAnalysis.js +248 -0
- package/frontend/type-checker/operatorMappings.js +35 -0
- package/frontend/type-checker/overloadResolution.js +605 -0
- package/frontend/type-checker/typeChecker.js +452 -0
- package/frontend/type-checker/typeCompatibility.js +389 -0
- package/frontend/type-checker/visitors/controlFlow.js +483 -0
- package/frontend/type-checker/visitors/functions.js +604 -0
- package/frontend/type-checker/visitors/index.js +38 -0
- package/frontend/type-checker/visitors/literals.js +341 -0
- package/frontend/type-checker/visitors/modules.js +159 -0
- package/frontend/type-checker/visitors/operators.js +109 -0
- package/frontend/type-checker/visitors/statements.js +768 -0
- package/frontend/types/index.js +5 -0
- package/frontend/types/operatorMap.js +134 -0
- package/frontend/types/types.js +2046 -0
- package/frontend/utils/errorCollector.js +244 -0
- package/frontend/utils/index.js +5 -0
- package/frontend/utils/moduleResolver.js +479 -0
- package/package.json +50 -0
- package/packages/browserCache.js +359 -0
- package/packages/fetcher.js +236 -0
- package/packages/index.js +130 -0
- package/packages/lockfile.js +271 -0
- package/packages/manifest.js +291 -0
- package/packages/packageResolver.js +356 -0
- package/packages/resolver.js +310 -0
- package/packages/semver.js +635 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Compatibility Methods - mixin for TypeChecker
|
|
3
|
+
*
|
|
4
|
+
* Methods for type comparison, promotion, unification, and conversion
|
|
5
|
+
* between class-based and structured type representations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
PrimitiveType,
|
|
10
|
+
FunctionType,
|
|
11
|
+
RecordType,
|
|
12
|
+
ArrayType,
|
|
13
|
+
TypeVariable,
|
|
14
|
+
PromotedType,
|
|
15
|
+
NUM,
|
|
16
|
+
BOOL,
|
|
17
|
+
STRING,
|
|
18
|
+
UNIT,
|
|
19
|
+
freshTypeVar,
|
|
20
|
+
typeEquals,
|
|
21
|
+
} from "../types/types.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Type compatibility methods to be mixed into TypeChecker.prototype
|
|
25
|
+
*/
|
|
26
|
+
export const typeCompatibilityMethods = {
|
|
27
|
+
/**
|
|
28
|
+
* Check if a class-based type contains unresolved type variables
|
|
29
|
+
*/
|
|
30
|
+
containsUnresolvedTypeVar(type) {
|
|
31
|
+
if (!type) return false;
|
|
32
|
+
if (type instanceof TypeVariable) {
|
|
33
|
+
const resolved = type.resolve();
|
|
34
|
+
if (resolved instanceof TypeVariable) return true;
|
|
35
|
+
return this.containsUnresolvedTypeVar(resolved);
|
|
36
|
+
}
|
|
37
|
+
if (type instanceof ArrayType) {
|
|
38
|
+
return this.containsUnresolvedTypeVar(type.elementType);
|
|
39
|
+
}
|
|
40
|
+
if (type instanceof FunctionType) {
|
|
41
|
+
if (type.paramTypes.some(p => this.containsUnresolvedTypeVar(p))) return true;
|
|
42
|
+
return this.containsUnresolvedTypeVar(type.returnType);
|
|
43
|
+
}
|
|
44
|
+
if (type instanceof RecordType) {
|
|
45
|
+
for (const fieldType of type.fields.values()) {
|
|
46
|
+
if (this.containsUnresolvedTypeVar(fieldType)) return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if a type is "incomplete" - contains unresolved TypeVariables
|
|
54
|
+
* Incomplete types need to be inferred from context (e.g., empty arrays)
|
|
55
|
+
*/
|
|
56
|
+
isIncompleteType(type) {
|
|
57
|
+
if (type instanceof TypeVariable) {
|
|
58
|
+
const resolved = type.resolve();
|
|
59
|
+
return resolved instanceof TypeVariable;
|
|
60
|
+
}
|
|
61
|
+
if (type instanceof ArrayType) {
|
|
62
|
+
return this.isIncompleteType(type.elementType);
|
|
63
|
+
}
|
|
64
|
+
if (type instanceof RecordType) {
|
|
65
|
+
for (const fieldType of type.fields.values()) {
|
|
66
|
+
if (this.isIncompleteType(fieldType)) return true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Convert a class-based type to a structured type object for matching
|
|
74
|
+
* @param {Object} type - Class-based type (PrimitiveType, ArrayType, etc.)
|
|
75
|
+
* @returns {Object} Structured type object
|
|
76
|
+
*/
|
|
77
|
+
toStructuredType(type) {
|
|
78
|
+
if (!type) return { kind: "unknown" };
|
|
79
|
+
|
|
80
|
+
// Already a plain structured object (not a class instance)
|
|
81
|
+
// Check for constructor being Object to distinguish from class instances
|
|
82
|
+
if (type.kind && type.constructor === Object) {
|
|
83
|
+
return type;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (type instanceof PrimitiveType) {
|
|
87
|
+
return { kind: "primitive", name: type.name };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (type instanceof ArrayType) {
|
|
91
|
+
return {
|
|
92
|
+
kind: "array",
|
|
93
|
+
elem: this.toStructuredType(type.elementType), // Use 'elem' to match parseTypeString format
|
|
94
|
+
rank: type.rank,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (type instanceof RecordType) {
|
|
99
|
+
const fields = new Map();
|
|
100
|
+
for (const [name, fieldType] of type.fields) {
|
|
101
|
+
fields.set(name, this.toStructuredType(fieldType));
|
|
102
|
+
}
|
|
103
|
+
return { kind: "record", fields, open: type.open };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (type instanceof FunctionType) {
|
|
107
|
+
return {
|
|
108
|
+
kind: "function",
|
|
109
|
+
params: type.paramTypes.map(t => this.toStructuredType(t)),
|
|
110
|
+
ret: this.toStructuredType(type.returnType),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (type instanceof TypeVariable) {
|
|
115
|
+
const resolved = type.resolve();
|
|
116
|
+
if (resolved !== type) {
|
|
117
|
+
return this.toStructuredType(resolved);
|
|
118
|
+
}
|
|
119
|
+
// Track the TypeVariable object for later unification
|
|
120
|
+
this.typeVarMap.set(type.id, type);
|
|
121
|
+
return { kind: "typevar", id: type.id, resolved: null };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return { kind: "unknown" };
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if a structured type contains unresolved type variables
|
|
129
|
+
*/
|
|
130
|
+
hasUnresolvedTypeVars(type) {
|
|
131
|
+
if (!type) return false;
|
|
132
|
+
if (type.kind === "typevar" && !type.resolved) return true;
|
|
133
|
+
if (type.kind === "unknown") return true;
|
|
134
|
+
if (type.kind === "array") return this.hasUnresolvedTypeVars(type.elem);
|
|
135
|
+
if (type.kind === "list") return this.hasUnresolvedTypeVars(type.elem);
|
|
136
|
+
if (type.kind === "function") {
|
|
137
|
+
if (type.params?.some(p => this.hasUnresolvedTypeVars(p))) return true;
|
|
138
|
+
return this.hasUnresolvedTypeVars(type.ret);
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Check if two function types can unify, treating type variables as wildcards.
|
|
145
|
+
* This is used for matching function arguments with type variables against
|
|
146
|
+
* expected function parameter types.
|
|
147
|
+
* E.g., (T1, T2) -> array<num,1> can unify with (num, array<num,1>) -> array<num,1>
|
|
148
|
+
*/
|
|
149
|
+
canUnifyFunctionTypes(expected, actual) {
|
|
150
|
+
if (!(expected instanceof FunctionType) || !(actual instanceof FunctionType)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Must have same arity
|
|
155
|
+
if (expected.paramTypes.length !== actual.paramTypes.length) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check each parameter type
|
|
160
|
+
for (let i = 0; i < expected.paramTypes.length; i++) {
|
|
161
|
+
const expParam = expected.paramTypes[i];
|
|
162
|
+
const actParam = actual.paramTypes[i];
|
|
163
|
+
|
|
164
|
+
// Type variable can match anything
|
|
165
|
+
if (expParam instanceof TypeVariable || actParam instanceof TypeVariable) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Both must be the same type or unifiable
|
|
170
|
+
if (!this.typesEqual(expParam, actParam) && !this.canUnifyTypes(expParam, actParam)) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check return type (type variable in return is also allowed)
|
|
176
|
+
const expRet = expected.returnType;
|
|
177
|
+
const actRet = actual.returnType;
|
|
178
|
+
|
|
179
|
+
if (expRet instanceof TypeVariable || actRet instanceof TypeVariable) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return this.typesEqual(expRet, actRet) || this.canUnifyTypes(expRet, actRet);
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if two types can unify (type variables match anything)
|
|
188
|
+
*/
|
|
189
|
+
canUnifyTypes(a, b) {
|
|
190
|
+
if (a instanceof TypeVariable || b instanceof TypeVariable) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (a instanceof ArrayType && b instanceof ArrayType) {
|
|
194
|
+
return this.canUnifyTypes(a.elementType, b.elementType);
|
|
195
|
+
}
|
|
196
|
+
if (a instanceof FunctionType && b instanceof FunctionType) {
|
|
197
|
+
return this.canUnifyFunctionTypes(a, b);
|
|
198
|
+
}
|
|
199
|
+
return this.typesEqual(a, b);
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Check if two types are equal
|
|
204
|
+
* For PromotedType, compares against the target type or source type
|
|
205
|
+
*/
|
|
206
|
+
typesEqual(a, b) {
|
|
207
|
+
if (a === b) return true;
|
|
208
|
+
if (!a || !b) return false;
|
|
209
|
+
|
|
210
|
+
// Handle PromotedType: compare against target type or source type
|
|
211
|
+
if (a instanceof PromotedType) {
|
|
212
|
+
// If b matches target type, it's equal (no promotion needed)
|
|
213
|
+
if (this.typesEqual(a.targetType, b)) return true;
|
|
214
|
+
// If b matches source type, it's also considered equal for overload matching
|
|
215
|
+
// (the actual promotion will be handled by canPromote)
|
|
216
|
+
if (a.sourceType && this.typesEqual(a.sourceType, b)) return true;
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
if (b instanceof PromotedType) {
|
|
220
|
+
// Symmetric case
|
|
221
|
+
if (this.typesEqual(a, b.targetType)) return true;
|
|
222
|
+
if (b.sourceType && this.typesEqual(a, b.sourceType)) return true;
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (a.constructor !== b.constructor) return false;
|
|
227
|
+
|
|
228
|
+
if (a instanceof ArrayType) {
|
|
229
|
+
return this.typesEqual(a.elementType, b.elementType) && a.rank === b.rank;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (a instanceof FunctionType) {
|
|
233
|
+
if (a.paramTypes.length !== b.paramTypes.length) return false;
|
|
234
|
+
for (let i = 0; i < a.paramTypes.length; i++) {
|
|
235
|
+
if (!this.typesEqual(a.paramTypes[i], b.paramTypes[i])) return false;
|
|
236
|
+
}
|
|
237
|
+
return this.typesEqual(a.returnType, b.returnType);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (a instanceof RecordType) {
|
|
241
|
+
if (a.fields.size !== b.fields.size) return false;
|
|
242
|
+
for (const [name, type] of a.fields) {
|
|
243
|
+
if (!b.fields.has(name) || !this.typesEqual(type, b.fields.get(name))) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Primitive types - compare by reference (NUM, BOOL, etc.)
|
|
251
|
+
return a === b;
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Check if a type is the complex record type {re: num, im: num}
|
|
256
|
+
*/
|
|
257
|
+
isComplexRecordType(type) {
|
|
258
|
+
if (!(type instanceof RecordType)) return false;
|
|
259
|
+
if (type.fields.size !== 2) return false;
|
|
260
|
+
const reType = type.fields.get("re");
|
|
261
|
+
const imType = type.fields.get("im");
|
|
262
|
+
if (!reType || !imType) return false;
|
|
263
|
+
return reType === NUM && imType === NUM;
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Check if argType can be promoted to paramType.
|
|
268
|
+
* Supports both built-in promotions (num → complex) and user-defined
|
|
269
|
+
* promotions via PromotedType.
|
|
270
|
+
*
|
|
271
|
+
* @param {Object} argType - Argument type (class-based)
|
|
272
|
+
* @param {Object} paramType - Parameter type (may be PromotedType)
|
|
273
|
+
* @returns {{can: boolean, converter: string|null}} Promotion result
|
|
274
|
+
*/
|
|
275
|
+
canPromote(argType, paramType) {
|
|
276
|
+
// Handle PromotedType: check if argType matches the sourceType
|
|
277
|
+
if (paramType instanceof PromotedType) {
|
|
278
|
+
// If sourceType is set (validated), check if argType matches it
|
|
279
|
+
if (paramType.sourceType && typeEquals(argType, paramType.sourceType)) {
|
|
280
|
+
return { can: true, converter: paramType.converterFunc };
|
|
281
|
+
}
|
|
282
|
+
// Also check if argType matches the target type (no conversion needed)
|
|
283
|
+
if (typeEquals(argType, paramType.targetType)) {
|
|
284
|
+
return { can: false, converter: null }; // No promotion needed - exact match
|
|
285
|
+
}
|
|
286
|
+
return { can: false, converter: null };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Built-in: num -> complex (complex is now {re: num, im: num} record)
|
|
290
|
+
if (argType === NUM && this.isComplexRecordType(paramType)) {
|
|
291
|
+
return { can: true, converter: "to_complex" };
|
|
292
|
+
}
|
|
293
|
+
// Built-in: array<num> -> array<complex> promotion
|
|
294
|
+
if (argType instanceof ArrayType && paramType instanceof ArrayType) {
|
|
295
|
+
if (argType.rank === paramType.rank) {
|
|
296
|
+
const elemResult = this.canPromote(argType.elementType, paramType.elementType);
|
|
297
|
+
return elemResult;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return { can: false, converter: null };
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check if types are compatible (looser than equal)
|
|
305
|
+
*/
|
|
306
|
+
typesCompatible(paramType, argType) {
|
|
307
|
+
// Arrays with same element type but different ranks might be compatible
|
|
308
|
+
// depending on context - be lenient here
|
|
309
|
+
if (paramType instanceof ArrayType && argType instanceof ArrayType) {
|
|
310
|
+
return this.typesEqual(paramType.elementType, argType.elementType) ||
|
|
311
|
+
this.typesCompatible(paramType.elementType, argType.elementType);
|
|
312
|
+
}
|
|
313
|
+
// Records with subset of fields
|
|
314
|
+
if (paramType instanceof RecordType && argType instanceof RecordType) {
|
|
315
|
+
for (const [name, type] of paramType.fields) {
|
|
316
|
+
if (!argType.fields.has(name)) return false;
|
|
317
|
+
if (!this.typesCompatible(type, argType.fields.get(name))) return false;
|
|
318
|
+
}
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Check if types are compatible or can unify (for Phase 1.5 filtering)
|
|
326
|
+
*/
|
|
327
|
+
typesCompatibleOrUnifiable(actual, expected) {
|
|
328
|
+
if (actual instanceof TypeVariable || expected instanceof TypeVariable) {
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
if (this.typesEqual(actual, expected)) {
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
if (this.canPromote(actual, expected).can) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
if (this.typesCompatible(expected, actual)) {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
if (actual instanceof ArrayType && expected instanceof ArrayType) {
|
|
341
|
+
return this.typesCompatibleOrUnifiable(actual.elementType, expected.elementType);
|
|
342
|
+
}
|
|
343
|
+
return false;
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Convert structured type back to class-based type
|
|
348
|
+
* @param {Object} type - Structured type object
|
|
349
|
+
* @returns {Object} Class-based type
|
|
350
|
+
*/
|
|
351
|
+
fromStructuredType(type) {
|
|
352
|
+
if (!type) return freshTypeVar();
|
|
353
|
+
|
|
354
|
+
if (type.kind === "primitive") {
|
|
355
|
+
switch (type.name) {
|
|
356
|
+
case "num": return NUM;
|
|
357
|
+
case "bool": return BOOL;
|
|
358
|
+
case "string": return STRING;
|
|
359
|
+
case "unit": return UNIT;
|
|
360
|
+
// Note: "complex" is no longer a primitive - it's a record {re: num, im: num}
|
|
361
|
+
// The "record" case below will handle it
|
|
362
|
+
default: return freshTypeVar();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (type.kind === "array") {
|
|
367
|
+
const elemType = this.fromStructuredType(type.elem);
|
|
368
|
+
return new ArrayType(elemType, type.rank);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// list<T> is deprecated - treat as array<T,1> for backwards compatibility
|
|
372
|
+
if (type.kind === "list") {
|
|
373
|
+
const elemType = this.fromStructuredType(type.elem);
|
|
374
|
+
return new ArrayType(elemType, 1);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (type.kind === "record") {
|
|
378
|
+
const fields = new Map();
|
|
379
|
+
if (type.fields instanceof Map) {
|
|
380
|
+
for (const [name, fieldType] of type.fields) {
|
|
381
|
+
fields.set(name, this.fromStructuredType(fieldType));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return new RecordType(fields, type.open || false);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return freshTypeVar();
|
|
388
|
+
},
|
|
389
|
+
};
|