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,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stone Type Checker
|
|
3
|
+
*
|
|
4
|
+
* Performs compile-time type checking on Stone AST.
|
|
5
|
+
*
|
|
6
|
+
* Design principles:
|
|
7
|
+
* - Types are ALWAYS optional (no errors for missing annotations)
|
|
8
|
+
* - Compile-time errors when annotated types don't match inferred types
|
|
9
|
+
* - Infers types from usage context
|
|
10
|
+
* - Stores inferred types on AST nodes for IDE tooling
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
FunctionType,
|
|
15
|
+
RecordType,
|
|
16
|
+
ArrayType,
|
|
17
|
+
TypeVariable,
|
|
18
|
+
INT,
|
|
19
|
+
FLOAT,
|
|
20
|
+
BOOL,
|
|
21
|
+
STRING,
|
|
22
|
+
UNIT,
|
|
23
|
+
NUM,
|
|
24
|
+
freshTypeVar,
|
|
25
|
+
flattenNestedArrayType,
|
|
26
|
+
} from "../types/types.js";
|
|
27
|
+
import { OVERLOADS } from "../../backends/js-vm/primitives/overloads.js";
|
|
28
|
+
|
|
29
|
+
// Import modular components
|
|
30
|
+
import { TypeEnvironment } from "./TypeEnvironment.js";
|
|
31
|
+
import { OverloadedFunctionType } from "./OverloadedFunctionType.js";
|
|
32
|
+
import { typeCompatibilityMethods } from "./typeCompatibility.js";
|
|
33
|
+
import { bidirectionalInferenceMethods } from "./bidirectionalInference.js";
|
|
34
|
+
import { overloadResolutionMethods } from "./overloadResolution.js";
|
|
35
|
+
import { moduleAnalysisMethods } from "./moduleAnalysis.js";
|
|
36
|
+
import { registerVisitors } from "./visitors/index.js";
|
|
37
|
+
|
|
38
|
+
// Re-export for external consumers
|
|
39
|
+
export { OverloadedFunctionType };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Stone Type Checker
|
|
43
|
+
*
|
|
44
|
+
* Performs compile-time type checking on Stone AST using Hindley-Milner style
|
|
45
|
+
* type inference with structural typing.
|
|
46
|
+
*
|
|
47
|
+
* Design principles:
|
|
48
|
+
* - Types are always optional (no errors for missing annotations)
|
|
49
|
+
* - Compile-time errors when annotated types don't match inferred types
|
|
50
|
+
* - Infers types from usage context
|
|
51
|
+
* - Stores inferred types on AST nodes (node.inferredType) for tooling and optimization
|
|
52
|
+
*
|
|
53
|
+
* Type system features:
|
|
54
|
+
* - Primitive types: num, bool, string, unit, complex
|
|
55
|
+
* - Compound types: arrays (with rank), records, functions
|
|
56
|
+
* - Type variables for polymorphism
|
|
57
|
+
* - Overloaded functions with signature matching
|
|
58
|
+
* - Module import type analysis
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const checker = new TypeChecker({ moduleResolver, parser });
|
|
62
|
+
* const result = checker.check(ast);
|
|
63
|
+
* if (!result.success) {
|
|
64
|
+
* console.error(result.errors);
|
|
65
|
+
* }
|
|
66
|
+
*/
|
|
67
|
+
export class TypeChecker {
|
|
68
|
+
/**
|
|
69
|
+
* Create a new TypeChecker instance
|
|
70
|
+
*
|
|
71
|
+
* @param {Object} [options={}] - Configuration options
|
|
72
|
+
* @param {ModuleResolver} [options.moduleResolver] - Module resolver for import type analysis
|
|
73
|
+
* @param {Function} [options.parser] - Parser function for analyzing module source
|
|
74
|
+
*/
|
|
75
|
+
constructor(options = {}) {
|
|
76
|
+
/**
|
|
77
|
+
* Collected type errors
|
|
78
|
+
* @type {Array<{message: string, location: Object|null}>}
|
|
79
|
+
*/
|
|
80
|
+
this.errors = [];
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Collected warnings
|
|
84
|
+
* @type {Array<{message: string, location: Object|null}>}
|
|
85
|
+
*/
|
|
86
|
+
this.warnings = [];
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Map from AST node to inferred type
|
|
90
|
+
* @type {Map<Object, Object>}
|
|
91
|
+
*/
|
|
92
|
+
this.typeMap = new Map();
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Configuration options
|
|
96
|
+
* @type {Object}
|
|
97
|
+
*/
|
|
98
|
+
this.options = options;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Overload registry for static resolution.
|
|
102
|
+
* Creates a shallow copy to avoid modifying the global OVERLOADS object
|
|
103
|
+
* when adding type-checking-only overloads.
|
|
104
|
+
* @type {Object}
|
|
105
|
+
*/
|
|
106
|
+
this.overloads = {};
|
|
107
|
+
for (const name of Object.keys(OVERLOADS)) {
|
|
108
|
+
this.overloads[name] = [...OVERLOADS[name]];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Module resolver for import type analysis (optional)
|
|
113
|
+
* @type {ModuleResolver|null}
|
|
114
|
+
*/
|
|
115
|
+
this.moduleResolver = options.moduleResolver || null;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Parser function for analyzing module source (optional)
|
|
119
|
+
* @type {Function|null}
|
|
120
|
+
*/
|
|
121
|
+
this.parser = options.parser || null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Cache of module export types (modulePath -> Map<exportName, Type>)
|
|
125
|
+
* @type {Map<string, Map<string, Object>>}
|
|
126
|
+
*/
|
|
127
|
+
this.moduleTypeCache = new Map();
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Map of TypeVariable id to TypeVariable object for bidirectional inference
|
|
131
|
+
* @type {Map<number, TypeVariable>}
|
|
132
|
+
*/
|
|
133
|
+
this.typeVarMap = new Map();
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Stack of deferred constraint collections for nested function definitions.
|
|
137
|
+
* Each entry is an array of constraints for the currently-being-analyzed function.
|
|
138
|
+
* @type {Array<Array>}
|
|
139
|
+
*/
|
|
140
|
+
this.constraintStack = [];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Record a deferred constraint for the currently-being-analyzed function.
|
|
145
|
+
* Called when scoreOverload encounters a variable rank that must match a concrete rank.
|
|
146
|
+
*
|
|
147
|
+
* @param {Object} constraint - The deferred constraint
|
|
148
|
+
*/
|
|
149
|
+
recordDeferredConstraint(constraint) {
|
|
150
|
+
if (this.constraintStack.length > 0) {
|
|
151
|
+
this.constraintStack[this.constraintStack.length - 1].push(constraint);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Start tracking constraints for a new function definition.
|
|
157
|
+
*/
|
|
158
|
+
pushConstraintContext() {
|
|
159
|
+
this.constraintStack.push([]);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Finish tracking constraints and return collected constraints.
|
|
164
|
+
* @returns {Array} The deferred constraints collected for this function
|
|
165
|
+
*/
|
|
166
|
+
popConstraintContext() {
|
|
167
|
+
return this.constraintStack.pop() || [];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Register complex module arithmetic overloads for type checking.
|
|
172
|
+
* Called when any import from 'complex' module is seen.
|
|
173
|
+
* This allows operators like + - * / to work with complex numbers.
|
|
174
|
+
*/
|
|
175
|
+
_registerComplexOverloads() {
|
|
176
|
+
// Don't register twice
|
|
177
|
+
if (this._complexOverloadsRegistered) return;
|
|
178
|
+
this._complexOverloadsRegistered = true;
|
|
179
|
+
|
|
180
|
+
// Create mock "primitive" functions with complex signatures for type checking
|
|
181
|
+
// These signatures match what the Stone complex module provides
|
|
182
|
+
// Register under both function names (for import) and operator names (for +, -, etc.)
|
|
183
|
+
const complexOps = [
|
|
184
|
+
{ name: 'add', opName: '__op_add', sig: { in: ['complex', 'complex'], out: 'complex' } },
|
|
185
|
+
{ name: 'sub', opName: '__op_sub', sig: { in: ['complex', 'complex'], out: 'complex' } },
|
|
186
|
+
{ name: 'mul', opName: '__op_mul', sig: { in: ['complex', 'complex'], out: 'complex' } },
|
|
187
|
+
{ name: 'div', opName: '__op_div', sig: { in: ['complex', 'complex'], out: 'complex' } },
|
|
188
|
+
{ name: 'neg', opName: '__op_neg', sig: { in: ['complex'], out: 'complex' } },
|
|
189
|
+
{ name: 'pow', opName: '__op_pow', sig: { in: ['complex', 'complex'], out: 'complex' } },
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
for (const { name, opName, sig } of complexOps) {
|
|
193
|
+
// Create a mock function with the .stone signature
|
|
194
|
+
const mockFn = { stone: sig };
|
|
195
|
+
|
|
196
|
+
// Add to overloads under function name (for import from complex module)
|
|
197
|
+
if (!this.overloads[name]) {
|
|
198
|
+
this.overloads[name] = [];
|
|
199
|
+
}
|
|
200
|
+
this.overloads[name].push(mockFn);
|
|
201
|
+
|
|
202
|
+
// Also add under operator name (for +, -, *, /, ^ operators)
|
|
203
|
+
if (!this.overloads[opName]) {
|
|
204
|
+
this.overloads[opName] = [];
|
|
205
|
+
}
|
|
206
|
+
this.overloads[opName].push({ stone: sig });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Check deferred constraints from a function definition against actual argument types.
|
|
212
|
+
* Called at function call sites to verify that inferred rank constraints are satisfied.
|
|
213
|
+
*
|
|
214
|
+
* @param {string} funcName - The function name (for error messages)
|
|
215
|
+
* @param {FunctionType} funcType - The function type with constraints
|
|
216
|
+
* @param {Array} argTypes - The actual argument types at the call site
|
|
217
|
+
* @param {Object} node - The call site node (for error location)
|
|
218
|
+
*/
|
|
219
|
+
checkDeferredConstraints(funcName, funcType, argTypes, node) {
|
|
220
|
+
if (!funcType.constraints || funcType.constraints.length === 0) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const constraint of funcType.constraints) {
|
|
225
|
+
if (constraint.type === 'rank') {
|
|
226
|
+
const paramIndex = constraint.paramIndex;
|
|
227
|
+
if (paramIndex >= argTypes.length) {
|
|
228
|
+
continue; // Arity mismatch handled elsewhere
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let argType = argTypes[paramIndex];
|
|
232
|
+
let actualRank = null;
|
|
233
|
+
|
|
234
|
+
// Flatten nested array types before extracting rank
|
|
235
|
+
// e.g., array<array<num, 1>, 1> should have effective rank 2
|
|
236
|
+
if (argType instanceof ArrayType || (argType && argType.kind === 'array')) {
|
|
237
|
+
argType = flattenNestedArrayType(argType);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Extract the rank from the argument type
|
|
241
|
+
if (argType instanceof ArrayType) {
|
|
242
|
+
actualRank = argType.rank;
|
|
243
|
+
} else if (argType && argType.kind === 'array') {
|
|
244
|
+
actualRank = argType.rank;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (actualRank === null) {
|
|
248
|
+
// Argument isn't an array - type mismatch error handled elsewhere
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Check if rank is concrete and matches
|
|
253
|
+
if (typeof actualRank === 'number') {
|
|
254
|
+
if (actualRank !== constraint.requiredRank) {
|
|
255
|
+
this.addError(
|
|
256
|
+
`Argument ${paramIndex + 1} to '${funcName}' requires array of rank ${constraint.requiredRank}, but got rank ${actualRank}`,
|
|
257
|
+
node.location
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
} else if (typeof actualRank === 'object' && actualRank.var) {
|
|
261
|
+
// Argument also has variable rank - propagate the constraint
|
|
262
|
+
// This means we're calling a constrained function from another function with variable rank
|
|
263
|
+
this.recordDeferredConstraint({
|
|
264
|
+
type: 'rank',
|
|
265
|
+
paramIndex: paramIndex,
|
|
266
|
+
rankVar: actualRank.var,
|
|
267
|
+
requiredRank: constraint.requiredRank
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
// If rank is neither number nor variable object, it's a type we don't handle
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Type check an AST and return type information
|
|
277
|
+
*
|
|
278
|
+
* This is the main entry point for type checking. It:
|
|
279
|
+
* 1. Creates a fresh type environment
|
|
280
|
+
* 2. Registers built-in types and functions
|
|
281
|
+
* 3. Visits all AST nodes, inferring and checking types
|
|
282
|
+
* 4. Returns collected errors, warnings, and type map
|
|
283
|
+
*
|
|
284
|
+
* @param {Object} ast - The parsed AST (Program node)
|
|
285
|
+
* @returns {Object} Type checking result
|
|
286
|
+
* @returns {Array} returns.errors - Array of type errors
|
|
287
|
+
* @returns {Array} returns.warnings - Array of type warnings
|
|
288
|
+
* @returns {Map} returns.types - Map from AST nodes to their inferred types
|
|
289
|
+
* @returns {boolean} returns.success - True if no errors were found
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* const result = checker.check(ast);
|
|
293
|
+
* if (result.success) {
|
|
294
|
+
* // Access inferred types via result.types or node.inferredType
|
|
295
|
+
* const funcType = result.types.get(functionNode);
|
|
296
|
+
* }
|
|
297
|
+
*/
|
|
298
|
+
check(ast) {
|
|
299
|
+
this.errors = [];
|
|
300
|
+
this.warnings = [];
|
|
301
|
+
this.typeMap = new Map();
|
|
302
|
+
|
|
303
|
+
const env = new TypeEnvironment();
|
|
304
|
+
this.registerBuiltins(env);
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
this.visitProgram(ast, env);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
this.errors.push({
|
|
310
|
+
message: error.message,
|
|
311
|
+
location: null,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Collect extension names from the type environment
|
|
316
|
+
// This includes both locally defined extensions and imported ones
|
|
317
|
+
const extensions = new Set();
|
|
318
|
+
this._collectExtensions(env, extensions);
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
errors: this.errors,
|
|
322
|
+
warnings: this.warnings,
|
|
323
|
+
types: this.typeMap,
|
|
324
|
+
success: this.errors.length === 0,
|
|
325
|
+
extensions, // Set of extension function names for the compiler
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Recursively collect extension names from environment chain
|
|
331
|
+
* @private
|
|
332
|
+
*/
|
|
333
|
+
_collectExtensions(env, extensions) {
|
|
334
|
+
if (!env) return;
|
|
335
|
+
for (const name of env.extensions.keys()) {
|
|
336
|
+
extensions.add(name);
|
|
337
|
+
}
|
|
338
|
+
// Note: extensions are typically only defined in the current env,
|
|
339
|
+
// not inherited, but we recurse for completeness
|
|
340
|
+
if (env.parent) {
|
|
341
|
+
this._collectExtensions(env.parent, extensions);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Register built-in functions and types.
|
|
347
|
+
* Note: Functions that have proper overload definitions in OVERLOADS are NOT registered here,
|
|
348
|
+
* as they will be handled by overload resolution which provides better type checking.
|
|
349
|
+
*/
|
|
350
|
+
registerBuiltins(env) {
|
|
351
|
+
// Only register functions that are NOT in OVERLOADS or have no overloaded variants.
|
|
352
|
+
// Functions like abs, sqrt, pow, sin, cos, min, max etc. are in OVERLOADS and
|
|
353
|
+
// will be resolved through the overload system for proper type handling.
|
|
354
|
+
|
|
355
|
+
// Array functions (len has overloads, sum is simple)
|
|
356
|
+
env.define("len", new FunctionType([freshTypeVar()], INT));
|
|
357
|
+
env.define("sum", new FunctionType([new ArrayType(NUM, 1)], NUM));
|
|
358
|
+
|
|
359
|
+
// Type conversion (these are not overloaded)
|
|
360
|
+
env.define("int", new FunctionType([freshTypeVar()], INT));
|
|
361
|
+
env.define("float", new FunctionType([freshTypeVar()], FLOAT));
|
|
362
|
+
env.define("str", new FunctionType([freshTypeVar()], STRING));
|
|
363
|
+
env.define("bool", new FunctionType([freshTypeVar()], BOOL));
|
|
364
|
+
|
|
365
|
+
// I/O
|
|
366
|
+
env.define("print", new FunctionType([freshTypeVar()], UNIT));
|
|
367
|
+
|
|
368
|
+
// Terminal constructors
|
|
369
|
+
// Note: graph2d/graph3d are now in the 'plots' module (import graph2d from plots)
|
|
370
|
+
const terminalType = new RecordType(new Map(), true);
|
|
371
|
+
env.define("console_terminal", new FunctionType([terminalType], terminalType));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Check if a name is defined in the scope chain (not just via overload resolution)
|
|
376
|
+
*/
|
|
377
|
+
isDefinedInScope(env, name) {
|
|
378
|
+
let current = env;
|
|
379
|
+
while (current) {
|
|
380
|
+
if (current.bindings.has(name)) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
current = current.parent;
|
|
384
|
+
}
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Add an error with stage information
|
|
390
|
+
*/
|
|
391
|
+
addError(message, location) {
|
|
392
|
+
this.errors.push({
|
|
393
|
+
stage: 'type_check',
|
|
394
|
+
type: 'type',
|
|
395
|
+
message,
|
|
396
|
+
location
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Add a warning with stage information
|
|
402
|
+
*/
|
|
403
|
+
addWarning(message, location) {
|
|
404
|
+
this.warnings.push({
|
|
405
|
+
stage: 'type_check',
|
|
406
|
+
type: 'warning',
|
|
407
|
+
message,
|
|
408
|
+
location
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Set the inferred type for an AST node
|
|
414
|
+
*/
|
|
415
|
+
setType(node, type) {
|
|
416
|
+
this.typeMap.set(node, type);
|
|
417
|
+
node.inferredType = type;
|
|
418
|
+
return type;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Get the inferred type for an AST node
|
|
423
|
+
*/
|
|
424
|
+
getType(node) {
|
|
425
|
+
return this.typeMap.get(node);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Mix in all method groups from extracted modules
|
|
430
|
+
Object.assign(TypeChecker.prototype,
|
|
431
|
+
typeCompatibilityMethods,
|
|
432
|
+
bidirectionalInferenceMethods,
|
|
433
|
+
overloadResolutionMethods,
|
|
434
|
+
moduleAnalysisMethods
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
// Register all visitor methods
|
|
438
|
+
registerVisitors(TypeChecker);
|
|
439
|
+
|
|
440
|
+
// ============================================================================
|
|
441
|
+
// EXPORTS
|
|
442
|
+
// ============================================================================
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Type check an AST
|
|
446
|
+
*/
|
|
447
|
+
export function typeCheck(ast, options = {}) {
|
|
448
|
+
const checker = new TypeChecker(options);
|
|
449
|
+
return checker.check(ast);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export { TypeEnvironment };
|