@xnoxs/flux-lang 3.5.2 → 4.0.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.
@@ -1,1114 +1 @@
1
- // ── Flux stdlib ──
2
-
3
- function map(arr, fn) { return arr.map(fn); }
4
-
5
- function filter(arr, fn) { return arr.filter(fn); }
6
-
7
- function reduce(arr, fn, init) { return arguments.length >= 3 ? arr.reduce(fn, init) : arr.reduce(fn); }
8
-
9
- function find(arr, fn) { return arr.find(fn); }
10
-
11
- function some(arr, fn) { return arr.some(fn); }
12
-
13
- function every(arr, fn) { return arr.every(fn); }
14
-
15
- function join(arr, sep) { return arr.join(sep != null ? sep : ','); }
16
-
17
- function includes(arr, val) { return arr.includes(val); }
18
-
19
- function entries(obj) { return Object.entries(obj); }
20
-
21
- function trim(s) { return String(s).trim(); }
22
-
23
- function startsWith(s, prefix) { return String(s).startsWith(prefix); }
24
-
25
- function endsWith(s, suffix) { return String(s).endsWith(suffix); }
26
- // ── end stdlib ──
27
-
28
- // Generated by Flux Transpiler v3.2.0
29
- "use strict";
30
-
31
- const T_ANY = Object.freeze({ kind: "any" });
32
- module.exports.T_ANY = T_ANY;
33
- const T_UNKNOWN = Object.freeze({ kind: "unknown" });
34
- module.exports.T_UNKNOWN = T_UNKNOWN;
35
- const T_NEVER = Object.freeze({ kind: "never" });
36
- module.exports.T_NEVER = T_NEVER;
37
- const T_VOID = Object.freeze({ kind: "void" });
38
- module.exports.T_VOID = T_VOID;
39
- const T_NULL = Object.freeze({ kind: "null" });
40
- module.exports.T_NULL = T_NULL;
41
- const T_STRING = Object.freeze({ kind: "primitive", name: "String" });
42
- module.exports.T_STRING = T_STRING;
43
- const T_INT = Object.freeze({ kind: "primitive", name: "Int" });
44
- module.exports.T_INT = T_INT;
45
- const T_FLOAT = Object.freeze({ kind: "primitive", name: "Float" });
46
- module.exports.T_FLOAT = T_FLOAT;
47
- const T_NUMBER = Object.freeze({ kind: "primitive", name: "Number" });
48
- module.exports.T_NUMBER = T_NUMBER;
49
- const T_BOOL = Object.freeze({ kind: "primitive", name: "Bool" });
50
- module.exports.T_BOOL = T_BOOL;
51
- function T_UNION(...members) {
52
- const flat = [];
53
- for (const m of members) {
54
- if ((m && (m.kind == "union"))) {
55
- for (const sub of m.members) {
56
- flat.push(sub);
57
- }
58
- }
59
- else if (m) {
60
- flat.push(m);
61
- }
62
- }
63
- const seen = new Set();
64
- const deduped = [];
65
- for (const m of flat) {
66
- const k = typeStr(m);
67
- if (!seen.has(k)) {
68
- seen.add(k);
69
- deduped.push(m);
70
- }
71
- }
72
- if ((deduped.length == 0)) {
73
- return T_NEVER;
74
- }
75
- if ((deduped.length == 1)) {
76
- return deduped[0];
77
- }
78
- return { kind: "union", members: deduped };
79
- }
80
- module.exports.T_UNION = T_UNION;
81
- function T_INTERSECTION(...members) {
82
- const flat = [];
83
- for (const m of members) {
84
- if ((m && (m.kind == "intersection"))) {
85
- for (const sub of m.members) {
86
- flat.push(sub);
87
- }
88
- }
89
- else if (m) {
90
- flat.push(m);
91
- }
92
- }
93
- if ((flat.length == 1)) {
94
- return flat[0];
95
- }
96
- return { kind: "intersection", members: flat };
97
- }
98
- module.exports.T_INTERSECTION = T_INTERSECTION;
99
- function T_ARRAY(elem) {
100
- return { kind: "generic", name: "Array", args: [(elem ?? T_UNKNOWN)] };
101
- }
102
- module.exports.T_ARRAY = T_ARRAY;
103
- function T_TUPLE(types) {
104
- return { kind: "tuple", types: (types ?? []) };
105
- }
106
- module.exports.T_TUPLE = T_TUPLE;
107
- function T_NULLABLE(t) {
108
- return T_UNION(t, T_NULL);
109
- }
110
- module.exports.T_NULLABLE = T_NULLABLE;
111
- function T_NAMED(name) {
112
- return { kind: "named", name };
113
- }
114
- module.exports.T_NAMED = T_NAMED;
115
- function T_FN(params, ret) {
116
- return { kind: "fn", params: (params ?? []), ret: (ret ?? T_VOID) };
117
- }
118
- module.exports.T_FN = T_FN;
119
- function T_OBJECT(shape) {
120
- return { kind: "object", shape: (shape ?? new Map()) };
121
- }
122
- module.exports.T_OBJECT = T_OBJECT;
123
- function T_RECORD(key, val_) {
124
- return { kind: "record", key: (key ?? T_STRING), val: (val_ ?? T_UNKNOWN) };
125
- }
126
- module.exports.T_RECORD = T_RECORD;
127
- function T_LITERAL(value, kind) {
128
- return { kind: "literal", value, prim: kind };
129
- }
130
- module.exports.T_LITERAL = T_LITERAL;
131
- function typeStr(t) {
132
- if (!t) {
133
- return "unknown";
134
- }
135
- if ((t.kind == "any")) {
136
- return "Any";
137
- }
138
- if ((t.kind == "unknown")) {
139
- return "Unknown";
140
- }
141
- if ((t.kind == "never")) {
142
- return "Never";
143
- }
144
- if ((t.kind == "void")) {
145
- return "Void";
146
- }
147
- if ((t.kind == "null")) {
148
- return "Null";
149
- }
150
- if ((t.kind == "primitive")) {
151
- return t.name;
152
- }
153
- if ((t.kind == "literal")) {
154
- return JSON.stringify(t.value);
155
- }
156
- if ((t.kind == "union")) {
157
- return t.members.map(typeStr).join(" | ");
158
- }
159
- if ((t.kind == "intersection")) {
160
- return t.members.map(typeStr).join(" & ");
161
- }
162
- if ((t.kind == "tuple")) {
163
- return (("[" + t.types.map(typeStr).join(", ")) + "]");
164
- }
165
- if ((t.kind == "object")) {
166
- const entries = [];
167
- for (const pair of (t.shape ?? new Map()).entries()) {
168
- entries.push(((pair[0] + ": ") + typeStr(pair[1])));
169
- }
170
- return (("{" + entries.join(", ")) + "}");
171
- }
172
- if ((t.kind == "record")) {
173
- return (((("Record<" + typeStr(t.key)) + ", ") + typeStr(t.val)) + ">");
174
- }
175
- if ((t.kind == "generic")) {
176
- if ((t.args && (t.args.length > 0))) {
177
- return (((t.name + "<") + t.args.map(typeStr).join(", ")) + ">");
178
- }
179
- return t.name;
180
- }
181
- if ((t.kind == "named")) {
182
- return t.name;
183
- }
184
- if ((t.kind == "fn")) {
185
- return ((("(" + (t.params ?? []).map(typeStr).join(", ")) + ") -> ") + typeStr(t.ret));
186
- }
187
- if ((t.kind == "keyof")) {
188
- return ("keyof " + typeStr(t.inner));
189
- }
190
- if ((t.kind == "conditional")) {
191
- return ((((((typeStr(t.check) + " extends ") + typeStr(t.extends)) + " ? ") + typeStr(t.then)) + " : ") + typeStr(t.else));
192
- }
193
- return "unknown";
194
- }
195
- module.exports.typeStr = typeStr;
196
- function splitAtTopLevel(str, sep) {
197
- const parts = [];
198
- let depth = 0;
199
- let start = 0;
200
- let i = 0;
201
- while ((i < str.length)) {
202
- const c = str[i];
203
- if ("<([{".includes(c)) {
204
- depth = (depth + 1);
205
- }
206
- else if (">)]}".includes(c)) {
207
- depth = (depth - 1);
208
- }
209
- else if (((depth == 0) && (str.slice(i, (i + sep.length)) == sep))) {
210
- parts.push(str.slice(start, i));
211
- start = (i + sep.length);
212
- i = ((i + sep.length) - 1);
213
- }
214
- i = (i + 1);
215
- }
216
- parts.push(str.slice(start));
217
- return parts.filter((p) => (p.trim().length > 0));
218
- }
219
- const PRIMITIVE_MAP = { String: T_STRING, string: T_STRING, Int: T_INT, int: T_INT, Float: T_FLOAT, float: T_FLOAT, Number: T_NUMBER, number: T_NUMBER, Bool: T_BOOL, boolean: T_BOOL, Boolean: T_BOOL, bool: T_BOOL, Void: T_VOID, void: T_VOID, Never: T_NEVER, never: T_NEVER, Any: T_ANY, any: T_ANY, Unknown: T_UNKNOWN, unknown: T_UNKNOWN, Null: T_NULL, null: T_NULL, undefined: T_VOID, Object: T_NAMED("Object"), object: T_NAMED("Object"), Symbol: T_NAMED("Symbol"), symbol: T_NAMED("Symbol"), BigInt: T_NAMED("BigInt"), bigint: T_NAMED("BigInt") };
220
- function parseAnnotation(str) {
221
- if (!str) {
222
- return null;
223
- }
224
- let s = str.trim();
225
- if ((s.startsWith("(") && s.endsWith(")"))) {
226
- s = s.slice(1, -1).trim();
227
- }
228
- const unionParts = splitAtTopLevel(s, " | ");
229
- if ((unionParts.length > 1)) {
230
- return T_UNION(...unionParts.map(parseAnnotation));
231
- }
232
- const interParts = splitAtTopLevel(s, " & ");
233
- if ((interParts.length > 1)) {
234
- return T_INTERSECTION(...interParts.map(parseAnnotation));
235
- }
236
- const condMatch = s.match(/^(\w+)\s+extends\s+(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/);
237
- if (condMatch) {
238
- return { kind: "conditional", check: parseAnnotation(condMatch[1]), extends: parseAnnotation(condMatch[2]), then: parseAnnotation(condMatch[3]), else: parseAnnotation(condMatch[4]) };
239
- }
240
- if (s.startsWith("keyof ")) {
241
- return { kind: "keyof", inner: parseAnnotation(s.slice(6)) };
242
- }
243
- if (s.startsWith("typeof ")) {
244
- return { kind: "typeof", name: s.slice(7) };
245
- }
246
- if (s.startsWith("readonly ")) {
247
- return parseAnnotation(s.slice(9));
248
- }
249
- if (s.startsWith("infer ")) {
250
- return T_ANY;
251
- }
252
- const fnMatch = (s.match(/^fn\(([^)]*)\)\s*->\s*(.+)$/) ?? s.match(/^\(([^)]*)\)\s*->\s*(.+)$/));
253
- if (fnMatch) {
254
- const paramStr = fnMatch[1].trim();
255
- const retStr = fnMatch[2].trim();
256
- const params = (paramStr ? splitAtTopLevel(paramStr, ", ").map((p) => parseAnnotation(p.slice(((p.indexOf(":") >= 0) ? (p.indexOf(":") + 1) : 0)).trim())) : []);
257
- return T_FN(params, parseAnnotation(retStr));
258
- }
259
- if (s.endsWith("?")) {
260
- return T_NULLABLE(parseAnnotation(s.slice(0, -1)));
261
- }
262
- if (s.endsWith("[]")) {
263
- return T_ARRAY(parseAnnotation(s.slice(0, -2)));
264
- }
265
- if ((s.startsWith("[") && s.endsWith("]"))) {
266
- const inner = s.slice(1, -1);
267
- if (!inner.trim()) {
268
- return T_TUPLE([]);
269
- }
270
- const parts = splitAtTopLevel(inner, ", ");
271
- return T_TUPLE(parts.map((p) => parseAnnotation(p.replace(/^\.\.\./, "").trim())));
272
- }
273
- if (s.startsWith(`${") and s.endsWith("}`)) {
274
- const inner = s.slice(1, -1).trim();
275
- const shape = new Map();
276
- if (inner) {
277
- const pairs = splitAtTopLevel(inner, ", ");
278
- for (const pair of pairs) {
279
- const idxMatch = pair.match(/^\[(\w+):\s*\w+\]:\s*(.+)$/);
280
- if (idxMatch) {
281
- shape.set("[index]", parseAnnotation(idxMatch[2]));
282
- continue;
283
- }
284
- const colonIdx = pair.indexOf(":");
285
- if ((colonIdx >= 0)) {
286
- const rawKey = pair.slice(0, colonIdx).trim().replace(/^readonly\s+/, "");
287
- const key = rawKey.replace(/\?$/, "");
288
- const opt = rawKey.endsWith("?");
289
- const valType = parseAnnotation(pair.slice((colonIdx + 1)).trim());
290
- shape.set(key, (opt ? T_UNION(valType, T_VOID) : valType));
291
- }
292
- }
293
- }
294
- return T_OBJECT(shape);
295
- }
296
- const genMatch = s.match(/^(\w+)<(.+)>$/s);
297
- if (genMatch) {
298
- const gname = genMatch[1];
299
- const rawArgs = splitAtTopLevel(genMatch[2], ", ");
300
- const args = rawArgs.map((a) => parseAnnotation(a.trim()));
301
- if ((((gname == "Array") || (gname == "List")) || (gname == "ReadonlyArray"))) {
302
- return T_ARRAY((args[0] ?? T_UNKNOWN));
303
- }
304
- if ((gname == "NonNullable")) {
305
- return resolveNonNullable(args[0]);
306
- }
307
- if ((gname == "Partial")) {
308
- return { kind: "utility", util: "Partial", inner: args[0] };
309
- }
310
- if ((gname == "Required")) {
311
- return { kind: "utility", util: "Required", inner: args[0] };
312
- }
313
- if ((gname == "Readonly")) {
314
- return args[0];
315
- }
316
- if ((gname == "Record")) {
317
- return T_RECORD((args[0] ?? T_STRING), (args[1] ?? T_UNKNOWN));
318
- }
319
- if ((gname == "Pick")) {
320
- return { kind: "utility", util: "Pick", inner: args[0], keys: args[1] };
321
- }
322
- if ((gname == "Omit")) {
323
- return { kind: "utility", util: "Omit", inner: args[0], keys: args[1] };
324
- }
325
- if ((gname == "Exclude")) {
326
- return { kind: "utility", util: "Exclude", inner: args[0], keys: args[1] };
327
- }
328
- if ((gname == "Extract")) {
329
- return { kind: "utility", util: "Extract", inner: args[0], keys: args[1] };
330
- }
331
- if ((gname == "ReturnType")) {
332
- return { kind: "utility", util: "ReturnType", inner: args[0] };
333
- }
334
- if ((gname == "Parameters")) {
335
- return { kind: "utility", util: "Parameters", inner: args[0] };
336
- }
337
- if ((gname == "Awaited")) {
338
- return { kind: "utility", util: "Awaited", inner: args[0] };
339
- }
340
- return { kind: "generic", name: gname, args };
341
- }
342
- if (PRIMITIVE_MAP[s]) {
343
- return PRIMITIVE_MAP[s];
344
- }
345
- return T_NAMED(s);
346
- }
347
- module.exports.parseAnnotation = parseAnnotation;
348
- function resolveNonNullable(t) {
349
- if (!t) {
350
- return T_UNKNOWN;
351
- }
352
- if ((t.kind == "union")) {
353
- return T_UNION(...t.members.filter((m) => ((m.kind != "null") && (m.kind != "void"))));
354
- }
355
- if (((t.kind == "null") || (t.kind == "void"))) {
356
- return T_NEVER;
357
- }
358
- return t;
359
- }
360
- function basicAssignable(from_, to_) {
361
- if ((!from_ || !to_)) {
362
- return true;
363
- }
364
- if ((to_.kind == "any")) {
365
- return true;
366
- }
367
- if ((from_.kind == "any")) {
368
- return true;
369
- }
370
- if ((from_.kind == "never")) {
371
- return true;
372
- }
373
- if ((to_.kind == "unknown")) {
374
- return true;
375
- }
376
- if (((from_.kind == "void") && (to_.kind == "void"))) {
377
- return true;
378
- }
379
- if (((from_.kind == "null") && (to_.kind == "null"))) {
380
- return true;
381
- }
382
- if (((from_.kind == "null") && (to_.kind == "union"))) {
383
- return to_.members.some((m) => (((m.kind == "null") || (m.kind == "any")) || (m.kind == "void")));
384
- }
385
- if ((from_.kind == "union")) {
386
- return from_.members.every((m) => basicAssignable(m, to_));
387
- }
388
- if ((to_.kind == "union")) {
389
- return to_.members.some((m) => basicAssignable(from_, m));
390
- }
391
- if ((from_.kind == "intersection")) {
392
- return from_.members.some((m) => basicAssignable(m, to_));
393
- }
394
- if ((to_.kind == "intersection")) {
395
- return to_.members.every((m) => basicAssignable(from_, m));
396
- }
397
- if (((from_.kind == "primitive") && (to_.kind == "primitive"))) {
398
- if ((from_.name == to_.name)) {
399
- return true;
400
- }
401
- if (((to_.name == "Number") && (((from_.name == "Int") || (from_.name == "Float")) || (from_.name == "Number")))) {
402
- return true;
403
- }
404
- if (((to_.name == "Float") && (from_.name == "Int"))) {
405
- return true;
406
- }
407
- if (((from_.name == "Bool") && (to_.name == "Boolean"))) {
408
- return true;
409
- }
410
- if (((from_.name == "Boolean") && (to_.name == "Bool"))) {
411
- return true;
412
- }
413
- return false;
414
- }
415
- if (((from_.kind == "literal") && (to_.kind == "primitive"))) {
416
- const lmap = { string: "String", number: "Number", boolean: "Bool" };
417
- return ((lmap[from_.prim] == to_.name) || ((from_.prim == "number") && (((to_.name == "Int") || (to_.name == "Float")) || (to_.name == "Number"))));
418
- }
419
- if (((from_.kind == "named") && (to_.kind == "named"))) {
420
- return ((from_.name == to_.name) || (to_.name == "Object"));
421
- }
422
- if (((from_.kind == "generic") && (to_.kind == "generic"))) {
423
- const arrayNames = new Set(["Array", "List", "ReadonlyArray"]);
424
- if ((from_.name != to_.name)) {
425
- if (!(arrayNames.has(from_.name) && arrayNames.has(to_.name))) {
426
- return false;
427
- }
428
- }
429
- if ((from_.args.length != to_.args.length)) {
430
- return false;
431
- }
432
- return from_.args.every((a, i) => basicAssignable(a, to_.args[i]));
433
- }
434
- if (((from_.kind == "tuple") && (to_.kind == "tuple"))) {
435
- if ((from_.types.length != to_.types.length)) {
436
- return false;
437
- }
438
- return from_.types.every((t, i) => basicAssignable(t, to_.types[i]));
439
- }
440
- if ((((from_.kind == "generic") && (from_.name == "Array")) && (to_.kind == "tuple"))) {
441
- const elemType = (from_.args[0] ?? T_UNKNOWN);
442
- if ((elemType.kind == "unknown")) {
443
- return true;
444
- }
445
- return to_.types.every((t) => basicAssignable(elemType, t));
446
- }
447
- if (((from_.kind == "object") && (to_.kind == "object"))) {
448
- for (const pair of to_.shape.entries()) {
449
- const key = pair[0];
450
- const toType = pair[1];
451
- if (!from_.shape.has(key)) {
452
- return false;
453
- }
454
- if (!basicAssignable(from_.shape.get(key), toType)) {
455
- return false;
456
- }
457
- }
458
- return true;
459
- }
460
- if (((from_.kind == "object") && (to_.kind == "named"))) {
461
- return true;
462
- }
463
- if (((from_.kind == "fn") && (to_.kind == "fn"))) {
464
- if ((to_.ret && from_.ret)) {
465
- return basicAssignable(from_.ret, to_.ret);
466
- }
467
- return true;
468
- }
469
- if (((from_.kind == "record") && (to_.kind == "record"))) {
470
- return basicAssignable(from_.val, to_.val);
471
- }
472
- if ((to_.kind == "utility")) {
473
- return true;
474
- }
475
- if ((from_.kind == "utility")) {
476
- return true;
477
- }
478
- return false;
479
- }
480
- function mergeTypes(a, b) {
481
- if ((!a || (a.kind == "unknown"))) {
482
- return (b ?? T_UNKNOWN);
483
- }
484
- if ((!b || (b.kind == "unknown"))) {
485
- return a;
486
- }
487
- if ((typeStr(a) == typeStr(b))) {
488
- return a;
489
- }
490
- if (((a.kind == "any") || (b.kind == "any"))) {
491
- return T_ANY;
492
- }
493
- return T_UNION(a, b);
494
- }
495
- class TypeEnv {
496
- constructor(parent, vars, retType, isAsync) {
497
- this.parent = parent;
498
- this.vars = vars;
499
- this.retType = retType;
500
- this.isAsync = isAsync;
501
- }
502
-
503
- set(name, type_) {
504
- this.vars.set(name, type_);
505
- }
506
-
507
- has(name) {
508
- let e = this;
509
- while (e) {
510
- if (e.vars.has(name)) {
511
- return true;
512
- }
513
- e = e.parent;
514
- }
515
- return false;
516
- }
517
-
518
- get(name) {
519
- let env = this;
520
- while (env) {
521
- if (env.vars.has(name)) {
522
- return env.vars.get(name);
523
- }
524
- env = env.parent;
525
- }
526
- return null;
527
- }
528
-
529
- child() {
530
- return new TypeEnv(this, new Map(), this.retType, this.isAsync);
531
- }
532
-
533
- childFn(retType, isAsync_) {
534
- return new TypeEnv(this, new Map(), retType, (isAsync_ ?? false));
535
- }
536
-
537
- narrow(name, type_) {
538
- const c = new TypeEnv(this, new Map(), this.retType, this.isAsync);
539
- if ((name && type_)) {
540
- c.vars.set(name, type_);
541
- }
542
- return c;
543
- }
544
-
545
- }
546
-
547
- module.exports.TypeEnv = TypeEnv;
548
- class TypeCheckError {
549
- constructor(message, name, hint, line, col) {
550
- this.message = message;
551
- this.name = name;
552
- this.hint = hint;
553
- this.line = line;
554
- this.col = col;
555
- }
556
-
557
- }
558
-
559
- class FluxTypeChecker {
560
- constructor(errors, warnings, interfaces, types, classes, enums) {
561
- this.errors = errors;
562
- this.warnings = warnings;
563
- this.interfaces = interfaces;
564
- this.types = types;
565
- this.classes = classes;
566
- this.enums = enums;
567
- }
568
-
569
- _err(msg, loc, hint) {
570
- const e = new TypeCheckError();
571
- e.message = msg;
572
- e.name = "TypeError";
573
- e.hint = (hint ?? null);
574
- if (loc) {
575
- e.line = loc.line;
576
- e.col = loc.col;
577
- }
578
- this.errors.push(e);
579
- }
580
-
581
- _warn(msg, loc, hint) {
582
- const w = new TypeCheckError();
583
- w.message = msg;
584
- w.name = "TypeError";
585
- w.hint = (hint ?? null);
586
- if (loc) {
587
- w.line = loc.line;
588
- w.col = loc.col;
589
- }
590
- this.warnings.push(w);
591
- }
592
-
593
- check(ast) {
594
- this.errors = [];
595
- this.warnings = [];
596
- this.interfaces = new Map();
597
- this.types = new Map();
598
- this.classes = new Map();
599
- this.enums = new Map();
600
- this._collectDeclarations(ast.body);
601
- this._validateImplementations();
602
- const env = new TypeEnv(null, new Map(), null, false);
603
- this._registerBuiltins(env);
604
- this._checkStmts(ast.body, env);
605
- return { errors: this.errors, warnings: this.warnings };
606
- }
607
-
608
- _collectDeclarations(stmts) {
609
- for (const node of stmts) {
610
- const n = ((node.type == "ExportDecl") ? node.decl : node);
611
- if (!n) {
612
- continue;
613
- }
614
- if ((n.type == "InterfaceDecl")) {
615
- this.interfaces.set(n.name, n);
616
- }
617
- else if ((n.type == "TypeDecl")) {
618
- this.types.set(n.name, n);
619
- }
620
- else if ((n.type == "ClassDecl")) {
621
- this.classes.set(n.name, n);
622
- }
623
- else if ((n.type == "EnumDecl")) {
624
- this.enums.set(n.name, n);
625
- }
626
- }
627
- }
628
-
629
- _validateImplementations() {
630
- for (const clsPair of this.classes.entries()) {
631
- const cls = clsPair[1];
632
- for (const ifaceName of (cls.interfaces ?? [])) {
633
- this._checkInterfaceImpl(cls, ifaceName);
634
- }
635
- }
636
- }
637
-
638
- _checkInterfaceImpl(cls, ifaceName) {
639
- const iface = this.interfaces.get(ifaceName);
640
- if (!iface) {
641
- this._warn((((("Class '" + cls.name) + "' implements unknown interface '") + ifaceName) + "'"), cls.loc, (("Define 'interface " + ifaceName) + "' before use"));
642
- return;
643
- }
644
- for (const member of iface.members) {
645
- if ((member.kind == "method")) {
646
- const impl = cls.methods.find((m) => (m.name == member.name));
647
- if (!impl) {
648
- this._err((((((("Class '" + cls.name) + "' does not implement method '") + member.name) + "()' required by '") + ifaceName) + "'"), cls.loc, (("Add 'fn " + member.name) + "(...)' to the class"));
649
- }
650
- }
651
- else if (((member.kind == "field") && !member.optional)) {
652
- const hasField = cls.fields.find((f) => (f.name == member.name));
653
- const hasMethod = cls.methods.find((m) => (m.name == member.name));
654
- if ((!hasField && !hasMethod)) {
655
- this._err((((((("Class '" + cls.name) + "' is missing field '") + member.name) + "' required by '") + ifaceName) + "'"), cls.loc, (((("Add '" + member.name) + ": ") + (member.typeAnn ?? "Any")) + "' to the class"));
656
- }
657
- }
658
- }
659
- for (const superIface of (iface.superInterfaces ?? [])) {
660
- this._checkInterfaceImpl(cls, superIface);
661
- }
662
- }
663
-
664
- _isStructurallyCompatible(objShape, typeName) {
665
- const iface = this.interfaces.get(typeName);
666
- if (!iface) {
667
- const cls = this.classes.get(typeName);
668
- if (!cls) {
669
- return false;
670
- }
671
- for (const field of cls.fields) {
672
- if ((!objShape.has(field.name) && !field.optional)) {
673
- return false;
674
- }
675
- }
676
- return true;
677
- }
678
- for (const member of iface.members) {
679
- if (((member.kind == "field") && !member.optional)) {
680
- if (!objShape.has(member.name)) {
681
- return false;
682
- }
683
- }
684
- }
685
- return true;
686
- }
687
-
688
- _isAssignable(from_, to_) {
689
- if ((!from_ || !to_)) {
690
- return true;
691
- }
692
- if ((to_.kind == "any")) {
693
- return true;
694
- }
695
- if ((from_.kind == "any")) {
696
- return true;
697
- }
698
- if ((from_.kind == "never")) {
699
- return true;
700
- }
701
- if ((to_.kind == "unknown")) {
702
- return true;
703
- }
704
- if (((from_.kind == "object") && (to_.kind == "named"))) {
705
- return this._isStructurallyCompatible(from_.shape, to_.name);
706
- }
707
- if (((from_.kind == "named") && (to_.kind == "named"))) {
708
- if ((from_.name == to_.name)) {
709
- return true;
710
- }
711
- if ((to_.name == "Object")) {
712
- return true;
713
- }
714
- const cls = this.classes.get(from_.name);
715
- if ((cls && (cls.interfaces ?? []).includes(to_.name))) {
716
- return true;
717
- }
718
- if ((cls && (cls.superClass == to_.name))) {
719
- return true;
720
- }
721
- const iface = this.interfaces.get(from_.name);
722
- if ((iface && (iface.superInterfaces ?? []).includes(to_.name))) {
723
- return true;
724
- }
725
- return false;
726
- }
727
- if ((to_.kind == "utility")) {
728
- if ((to_.util == "Partial")) {
729
- return true;
730
- }
731
- if ((to_.util == "Required")) {
732
- return this._isAssignable(from_, to_.inner);
733
- }
734
- if ((to_.util == "NonNullable")) {
735
- return ((from_.kind != "null") && (from_.kind != "void"));
736
- }
737
- return true;
738
- }
739
- if ((from_.kind == "utility")) {
740
- return true;
741
- }
742
- return basicAssignable(from_, to_);
743
- }
744
-
745
- _analyzeNarrowingCondition(condExpr, env) {
746
- if (!condExpr) {
747
- return null;
748
- }
749
- if (((((condExpr.type == "BinaryExpr") && ((condExpr.op == "!=") || (condExpr.op == "!=="))) && (condExpr.left.type == "Identifier")) && (condExpr.right.type == "NullLit"))) {
750
- const name = condExpr.left.name;
751
- const t = env.get(name);
752
- if ((t && (t.kind == "union"))) {
753
- const narrowed = T_UNION(...t.members.filter((m) => ((m.kind != "null") && (m.kind != "void"))));
754
- return { varName: name, trueType: narrowed, falseType: T_UNION(T_NULL, T_VOID) };
755
- }
756
- }
757
- if ((((((condExpr.type == "BinaryExpr") && ((condExpr.op == "===") || (condExpr.op == "=="))) && (condExpr.left.type == "TypeofExpr")) && (condExpr.left.operand.type == "Identifier")) && (condExpr.right.type == "StringLit"))) {
758
- const name = condExpr.left.operand.name;
759
- const typeMap = { string: T_STRING, number: T_NUMBER, boolean: T_BOOL, undefined: T_VOID };
760
- const narrowedTrue = (typeMap[condExpr.right.value] ?? T_UNKNOWN);
761
- return { varName: name, trueType: narrowedTrue, falseType: (env.get(name) ?? T_UNKNOWN) };
762
- }
763
- if ((((condExpr.type == "BinaryExpr") && (condExpr.op == "instanceof")) && (condExpr.left.type == "Identifier"))) {
764
- const name = condExpr.left.name;
765
- const cls = ((condExpr.right.type == "Identifier") ? condExpr.right.name : null);
766
- if (cls) {
767
- return { varName: name, trueType: T_NAMED(cls), falseType: (env.get(name) ?? T_UNKNOWN) };
768
- }
769
- }
770
- if ((condExpr.type == "Identifier")) {
771
- const name = condExpr.name;
772
- const t = env.get(name);
773
- if ((t && (t.kind == "union"))) {
774
- const narrowed = T_UNION(...t.members.filter((m) => ((m.kind != "null") && (m.kind != "void"))));
775
- return { varName: name, trueType: narrowed, falseType: T_UNION(T_NULL, T_VOID) };
776
- }
777
- }
778
- return null;
779
- }
780
-
781
- _registerBuiltins(env) {
782
- env.set("console", T_NAMED("Console"));
783
- env.set("process", T_NAMED("Process"));
784
- env.set("Math", T_NAMED("Math"));
785
- env.set("JSON", T_NAMED("JSON"));
786
- env.set("Date", T_NAMED("Date"));
787
- env.set("Promise", T_NAMED("Promise"));
788
- env.set("Error", T_NAMED("Error"));
789
- env.set("Buffer", T_NAMED("Buffer"));
790
- env.set("RegExp", T_NAMED("RegExp"));
791
- env.set("Map", T_NAMED("Map"));
792
- env.set("Set", T_NAMED("Set"));
793
- env.set("WeakMap", T_NAMED("WeakMap"));
794
- env.set("WeakSet", T_NAMED("WeakSet"));
795
- env.set("Symbol", T_NAMED("Symbol"));
796
- env.set("Object", T_NAMED("Object"));
797
- env.set("Array", T_NAMED("Array"));
798
- env.set("String", T_NAMED("String"));
799
- env.set("Number", T_NAMED("Number"));
800
- env.set("Boolean", T_NAMED("Boolean"));
801
- env.set("Function", T_NAMED("Function"));
802
- env.set("parseInt", T_FN([T_STRING, T_INT], T_INT));
803
- env.set("parseFloat", T_FN([T_STRING], T_FLOAT));
804
- env.set("isNaN", T_FN([T_NUMBER], T_BOOL));
805
- env.set("isFinite", T_FN([T_NUMBER], T_BOOL));
806
- env.set("require", T_FN([T_STRING], T_ANY));
807
- env.set("fetch", T_FN([T_STRING], T_ANY));
808
- env.set("print", T_FN([], T_VOID));
809
- env.set("undefined", T_VOID);
810
- env.set("Infinity", T_NUMBER);
811
- env.set("NaN", T_NUMBER);
812
- env.set("globalThis", T_NAMED("Object"));
813
- }
814
-
815
- _inferType(node, env) {
816
- if (!node) {
817
- return T_UNKNOWN;
818
- }
819
- if ((node.type == "NumberLit")) {
820
- if (String(node.value).includes(".")) {
821
- return T_FLOAT;
822
- }
823
- return T_INT;
824
- }
825
- if ((node.type == "StringLit")) {
826
- return T_STRING;
827
- }
828
- if ((node.type == "BoolLit")) {
829
- return T_BOOL;
830
- }
831
- if ((node.type == "NullLit")) {
832
- return T_NULL;
833
- }
834
- if ((node.type == "Identifier")) {
835
- const t = env.get(node.name);
836
- return (t ?? T_UNKNOWN);
837
- }
838
- if ((node.type == "ArrayExpr")) {
839
- if ((node.items.length == 0)) {
840
- return T_ARRAY(T_UNKNOWN);
841
- }
842
- const elemTypes = node.items.map((i) => (i ? this._inferType(i, env) : T_UNKNOWN));
843
- const merged = elemTypes.reduce((a, b) => mergeTypes(a, b), T_UNKNOWN);
844
- return T_ARRAY(merged);
845
- }
846
- if ((node.type == "ObjectExpr")) {
847
- const shape = new Map();
848
- for (const pair of node.pairs) {
849
- if ((!pair.spread && pair.key)) {
850
- shape.set(pair.key, (pair.value ? this._inferType(pair.value, env) : T_UNKNOWN));
851
- }
852
- }
853
- return T_OBJECT(shape);
854
- }
855
- if ((node.type == "LambdaExpr")) {
856
- const paramTypes = node.params.map((p) => (p.typeAnn ? parseAnnotation(p.typeAnn) : T_UNKNOWN));
857
- const retType = (node.retType ? parseAnnotation(node.retType) : T_UNKNOWN);
858
- return T_FN(paramTypes, retType);
859
- }
860
- if (((node.type == "CallExpr") || (node.type == "OptCallExpr"))) {
861
- const calleeType = this._inferType(node.callee, env);
862
- if ((calleeType.kind == "fn")) {
863
- return (calleeType.ret ?? T_UNKNOWN);
864
- }
865
- return T_UNKNOWN;
866
- }
867
- if (((node.type == "MemberExpr") || (node.type == "OptMemberExpr"))) {
868
- return T_UNKNOWN;
869
- }
870
- if ((node.type == "TernaryExpr")) {
871
- const thenType = this._inferType(node.then, env);
872
- const elseType = this._inferType(node.else_, env);
873
- return mergeTypes(thenType, elseType);
874
- }
875
- if ((node.type == "BinaryExpr")) {
876
- if ((((((node.op == "+") || (node.op == "-")) || (node.op == "*")) || (node.op == "/")) || (node.op == "%"))) {
877
- return T_NUMBER;
878
- }
879
- if (((((((((node.op == "==") || (node.op == "!=")) || (node.op == "===")) || (node.op == "!==")) || (node.op == "<")) || (node.op == ">")) || (node.op == "<=")) || (node.op == ">="))) {
880
- return T_BOOL;
881
- }
882
- if (((((node.op == "and") || (node.op == "or")) || (node.op == "&&")) || (node.op == "||"))) {
883
- return T_BOOL;
884
- }
885
- return T_UNKNOWN;
886
- }
887
- if ((node.type == "AwaitExpr")) {
888
- const inner = this._inferType(node.operand, env);
889
- return inner;
890
- }
891
- if ((node.type == "NewExpr")) {
892
- if ((node.callee && (node.callee.type == "Identifier"))) {
893
- return T_NAMED(node.callee.name);
894
- }
895
- return T_UNKNOWN;
896
- }
897
- if ((node.type == "TemplateLit")) {
898
- return T_STRING;
899
- }
900
- if (((node.type == "CastExpr") || (node.type == "AsConstExpr"))) {
901
- if (node.typeAnn) {
902
- return parseAnnotation(node.typeAnn);
903
- }
904
- return this._inferType(node.expr, env);
905
- }
906
- return T_UNKNOWN;
907
- }
908
-
909
- _checkStmts(stmts, env) {
910
- for (const node of stmts) {
911
- this._checkStmt(node, env);
912
- }
913
- }
914
-
915
- _checkStmt(node, env) {
916
- if (!node) {
917
- return;
918
- }
919
- if ((node.type == "VarDecl")) {
920
- const declared = (node.typeAnn ? parseAnnotation(node.typeAnn) : null);
921
- let actual = null;
922
- if (node.init) {
923
- actual = this._inferType(node.init, env);
924
- }
925
- if (((declared && actual) && (actual.kind != "unknown"))) {
926
- if (!this._isAssignable(actual, declared)) {
927
- this._err((((((("Type '" + typeStr(actual)) + "' is not assignable to '") + node.name) + ": ") + typeStr(declared)) + "'"), node.loc, (("Change the value to match '" + typeStr(declared)) + "' or update the annotation"));
928
- }
929
- }
930
- env.set(node.name, ((declared ?? actual) ?? T_UNKNOWN));
931
- }
932
- else if ((node.type == "DestructureDecl")) {
933
- const srcType = (node.init ? this._inferType(node.init, env) : T_UNKNOWN);
934
- if ((node.patternType == "object")) {
935
- for (const p of node.pattern) {
936
- let memberType = T_UNKNOWN;
937
- if (((srcType.kind == "object") && srcType.shape.has(p.key))) {
938
- memberType = srcType.shape.get(p.key);
939
- }
940
- env.set(p.alias, memberType);
941
- }
942
- }
943
- else {
944
- let idx = 0;
945
- for (const p of node.pattern) {
946
- if (p) {
947
- let elemType = T_UNKNOWN;
948
- if (((srcType.kind == "tuple") && srcType.types[idx])) {
949
- elemType = srcType.types[idx];
950
- }
951
- else if (((srcType.kind == "generic") && (srcType.name == "Array"))) {
952
- elemType = (srcType.args[0] ?? T_UNKNOWN);
953
- }
954
- env.set(p.name, elemType);
955
- }
956
- idx = (idx + 1);
957
- }
958
- }
959
- }
960
- else if ((node.type == "FnDecl")) {
961
- const retType = (node.retType ? parseAnnotation(node.retType) : null);
962
- const paramTypes = node.params.map((p) => (p.typeAnn ? parseAnnotation(p.typeAnn) : T_UNKNOWN));
963
- if (node.name) {
964
- env.set(node.name, T_FN(paramTypes, (retType ?? T_UNKNOWN)));
965
- }
966
- const fnEnv = env.childFn(retType, node.async);
967
- let i = 0;
968
- for (const p of node.params) {
969
- fnEnv.set(p.name, paramTypes[i]);
970
- i = (i + 1);
971
- }
972
- if (node.inline) {
973
- const bodyType = this._inferType(node.body, fnEnv);
974
- if (((retType && bodyType) && (bodyType.kind != "unknown"))) {
975
- if (!this._isAssignable(bodyType, retType)) {
976
- this._err((((((("Function '" + (node.name ?? "(anon)")) + "' returns '") + typeStr(bodyType)) + "' but declared '") + typeStr(retType)) + "'"), node.loc, "Fix return type or update the annotation");
977
- }
978
- }
979
- }
980
- else {
981
- this._checkStmts(node.body, fnEnv);
982
- }
983
- }
984
- else if ((node.type == "ClassDecl")) {
985
- env.set(node.name, T_NAMED(node.name));
986
- const clsEnv = env.child();
987
- const shape = new Map();
988
- for (const f of node.fields) {
989
- const ft = (f.typeAnn ? parseAnnotation(f.typeAnn) : T_UNKNOWN);
990
- clsEnv.set(f.name, ft);
991
- shape.set(f.name, ft);
992
- }
993
- clsEnv.set("self", T_OBJECT(shape));
994
- for (const m of node.methods) {
995
- this._checkStmt(m, clsEnv);
996
- }
997
- }
998
- else if ((node.type == "TypeDecl")) {
999
- for (const v of node.variants) {
1000
- if ((v.fields.length == 0)) {
1001
- env.set(v.name, T_NAMED(node.name));
1002
- }
1003
- else {
1004
- env.set(v.name, T_FN(v.fields.map((f_) => T_ANY), T_NAMED(node.name)));
1005
- }
1006
- }
1007
- }
1008
- else if ((node.type == "InterfaceDecl")) {
1009
- env.set(node.name, T_NAMED(node.name));
1010
- }
1011
- else if ((node.type == "EnumDecl")) {
1012
- env.set(node.name, T_NAMED(node.name));
1013
- }
1014
- else if ((node.type == "IfStmt")) {
1015
- this._inferType(node.cond, env);
1016
- const narrowing = this._analyzeNarrowingCondition(node.cond, env);
1017
- const thenEnv = (narrowing ? env.narrow(narrowing.varName, narrowing.trueType) : env.child());
1018
- const elseEnv = (narrowing ? env.narrow(narrowing.varName, narrowing.falseType) : env.child());
1019
- this._checkStmts(node.then, thenEnv);
1020
- for (const ei of node.elseifs) {
1021
- this._inferType(ei.cond, env);
1022
- this._checkStmts(ei.body, env.child());
1023
- }
1024
- if (node.else_) {
1025
- this._checkStmts(node.else_, elseEnv);
1026
- }
1027
- }
1028
- else if ((node.type == "ForInStmt")) {
1029
- const iterType = this._inferType(node.iter, env);
1030
- const inner = env.child();
1031
- if (((iterType.kind == "generic") && (iterType.name == "Array"))) {
1032
- inner.set(node.var, (iterType.args[0] ?? T_UNKNOWN));
1033
- }
1034
- else if ((iterType.kind == "tuple")) {
1035
- inner.set(node.var, (iterType.types[0] ?? T_UNKNOWN));
1036
- }
1037
- else {
1038
- inner.set(node.var, T_UNKNOWN);
1039
- }
1040
- this._checkStmts(node.body, inner);
1041
- }
1042
- else if (((node.type == "WhileStmt") || (node.type == "DoWhileStmt"))) {
1043
- this._inferType(node.cond, env);
1044
- this._checkStmts((node.body ?? []), env.child());
1045
- }
1046
- else if ((node.type == "MatchStmt")) {
1047
- this._inferType(node.subject, env);
1048
- for (const arm of node.arms) {
1049
- const inner = env.child();
1050
- if ((arm.pattern.type == "VariantPat")) {
1051
- for (const b of arm.pattern.bindings) {
1052
- inner.set(b, T_UNKNOWN);
1053
- }
1054
- }
1055
- this._checkStmts(arm.body, inner);
1056
- }
1057
- }
1058
- else if ((node.type == "ReturnStmt")) {
1059
- if (node.value) {
1060
- const retType = env.retType;
1061
- const retActual = this._inferType(node.value, env);
1062
- if (((retType && retActual) && (retActual.kind != "unknown"))) {
1063
- if (!this._isAssignable(retActual, retType)) {
1064
- this._err((((("Return type '" + typeStr(retActual)) + "' is not assignable to declared '") + typeStr(retType)) + "'"), node.loc, "Fix the return value or update the return type annotation");
1065
- }
1066
- }
1067
- }
1068
- }
1069
- else if ((node.type == "TryCatchStmt")) {
1070
- this._checkStmts(node.tryBody, env.child());
1071
- if (node.catchBody) {
1072
- const inner = env.child();
1073
- if (node.catchParam) {
1074
- inner.set(node.catchParam, T_ANY);
1075
- }
1076
- this._checkStmts(node.catchBody, inner);
1077
- }
1078
- if (node.finallyBody) {
1079
- this._checkStmts(node.finallyBody, env.child());
1080
- }
1081
- }
1082
- else if ((node.type == "ThrowStmt")) {
1083
- if (node.value) {
1084
- this._inferType(node.value, env);
1085
- }
1086
- }
1087
- else if ((node.type == "ImportDecl")) {
1088
- if (node.defaultName) {
1089
- env.set(node.defaultName, T_ANY);
1090
- }
1091
- if (node.namespaceName) {
1092
- env.set(node.namespaceName, T_ANY);
1093
- }
1094
- for (const n of node.names) {
1095
- const nm = ((typeof n == "string") ? n : n.alias);
1096
- env.set(nm, T_ANY);
1097
- }
1098
- }
1099
- else if ((node.type == "ExportDecl")) {
1100
- if (node.isDefault) {
1101
- this._inferType(node.decl, env);
1102
- }
1103
- else {
1104
- this._checkStmt(node.decl, env);
1105
- }
1106
- }
1107
- else if ((node.type == "ExprStmt")) {
1108
- this._inferType(node.expr, env);
1109
- }
1110
- }
1111
-
1112
- }
1113
-
1114
- module.exports.FluxTypeChecker = FluxTypeChecker;
1
+ function map(arr, fn) { return arr.map(fn); } function filter(arr, fn) { return arr.filter(fn); } function reduce(arr, fn, init) { return arguments.length >= 3 ? arr.reduce(fn, init) : arr.reduce(fn); } function find(arr, fn) { return arr.find(fn); } function some(arr, fn) { return arr.some(fn); } function every(arr, fn) { return arr.every(fn); } function join(arr, sep) { return arr.join(sep != null ? sep : ','); } function includes(arr, val) { return arr.includes(val); } function entries(obj) { return Object.entries(obj); } function trim(s) { return String(s).trim(); } function startsWith(s, prefix) { return String(s).startsWith(prefix); } function endsWith(s, suffix) { return String(s).endsWith(suffix); } "use strict"; const T_ANY = Object.freeze({ kind: "any" }); module.exports.T_ANY = T_ANY; const T_UNKNOWN = Object.freeze({ kind: "unknown" }); module.exports.T_UNKNOWN = T_UNKNOWN; const T_NEVER = Object.freeze({ kind: "never" }); module.exports.T_NEVER = T_NEVER; const T_VOID = Object.freeze({ kind: "void" }); module.exports.T_VOID = T_VOID; const T_NULL = Object.freeze({ kind: "null" }); module.exports.T_NULL = T_NULL; const T_STRING = Object.freeze({ kind: "primitive", name: "String" }); module.exports.T_STRING = T_STRING; const T_INT = Object.freeze({ kind: "primitive", name: "Int" }); module.exports.T_INT = T_INT; const T_FLOAT = Object.freeze({ kind: "primitive", name: "Float" }); module.exports.T_FLOAT = T_FLOAT; const T_NUMBER = Object.freeze({ kind: "primitive", name: "Number" }); module.exports.T_NUMBER = T_NUMBER; const T_BOOL = Object.freeze({ kind: "primitive", name: "Bool" }); module.exports.T_BOOL = T_BOOL; function T_UNION(..._g) { const flat = []; for (const _h of _g) { if ((_h && (_h.kind == "union"))) { for (const _i of _h.members) { flat.push(_i); } } else if (_h) { flat.push(_h); } } const seen = new Set(); const deduped = []; for (const _h of flat) { const k = typeStr(_h); if (!seen.has(k)) { seen.add(k); deduped.push(_h); } } if ((deduped.length == 0)) { return T_NEVER; } if ((deduped.length == 1)) { return deduped[0]; } return { kind: "union", members: deduped }; } module.exports.T_UNION = T_UNION; function T_INTERSECTION(..._g) { const flat = []; for (const _h of _g) { if ((_h && (_h.kind == "intersection"))) { for (const _i of _h.members) { flat.push(_i); } } else if (_h) { flat.push(_h); } } if ((flat.length == 1)) { return flat[0]; } return { kind: "intersection", members: flat }; } module.exports.T_INTERSECTION = T_INTERSECTION; function T_ARRAY(_j) { return { kind: "generic", name: "Array", args: [(_j ?? T_UNKNOWN)] }; } module.exports.T_ARRAY = T_ARRAY; function T_TUPLE(_k) { return { kind: "tuple", types: (_k ?? []) }; } module.exports.T_TUPLE = T_TUPLE; function T_NULLABLE(_l) { return T_UNION(_l, T_NULL); } module.exports.T_NULLABLE = T_NULLABLE; function T_NAMED(_m) { return { kind: "named", name: _m }; } module.exports.T_NAMED = T_NAMED; function T_FN(_n, _o) { return { kind: "fn", params: (_n ?? []), ret: (_o ?? T_VOID) }; } module.exports.T_FN = T_FN; function T_OBJECT(_p) { return { kind: "object", shape: (_p ?? new Map()) }; } module.exports.T_OBJECT = T_OBJECT; function T_RECORD(_q, _r) { return { kind: "record", key: (_q ?? T_STRING), val: (_r ?? T_UNKNOWN) }; } module.exports.T_RECORD = T_RECORD; function T_LITERAL(_s, _t) { return { kind: "literal", value: _s, prim: _t }; } module.exports.T_LITERAL = T_LITERAL; function typeStr(_l) { if (!_l) { return "unknown"; } if ((_l.kind == "any")) { return "Any"; } if ((_l.kind == "unknown")) { return "Unknown"; } if ((_l.kind == "never")) { return "Never"; } if ((_l.kind == "void")) { return "Void"; } if ((_l.kind == "null")) { return "Null"; } if ((_l.kind == "primitive")) { return _l.name; } if ((_l.kind == "literal")) { return JSON.stringify(_l.value); } if ((_l.kind == "union")) { return _l.members.map(typeStr).join(" | "); } if ((_l.kind == "intersection")) { return _l.members.map(typeStr).join(" & "); } if ((_l.kind == "tuple")) { return (("[" + _l.types.map(typeStr).join(", ")) + "]"); } if ((_l.kind == "object")) { const entries = []; for (const _u of (_l.shape ?? new Map()).entries()) { entries.push(((_u[0] + ": ") + typeStr(_u[1]))); } return (("{" + entries.join(", ")) + "}"); } if ((_l.kind == "record")) { return (((("Record<" + typeStr(_l.key)) + ", ") + typeStr(_l.val)) + ">"); } if ((_l.kind == "generic")) { if ((_l.args && (_l.args.length > 0))) { return (((_l.name + "<") + _l.args.map(typeStr).join(", ")) + ">"); } return _l.name; } if ((_l.kind == "named")) { return _l.name; } if ((_l.kind == "fn")) { return ((("(" + (_l.params ?? []).map(typeStr).join(", ")) + ") -> ") + typeStr(_l.ret)); } if ((_l.kind == "keyof")) { return ("keyof " + typeStr(_l.inner)); } if ((_l.kind == "conditional")) { return ((((((typeStr(_l.check) + " extends ") + typeStr(_l.extends)) + " ? ") + typeStr(_l.then)) + " : ") + typeStr(_l.else)); } return "unknown"; } module.exports.typeStr = typeStr; function _a(_v, _w) { const parts = []; let depth = 0; let start = 0; let i = 0; while ((i < _v.length)) { const c = _v[i]; if ("<([{".includes(c)) { depth = (depth + 1); } else if (">)]}".includes(c)) { depth = (depth - 1); } else if (((depth == 0) && (_v.slice(i, (i + _w.length)) == _w))) { parts.push(_v.slice(start, i)); start = (i + _w.length); i = ((i + _w.length) - 1); } i = (i + 1); } parts.push(_v.slice(start)); return parts.filter((_x) => (_x.trim().length > 0)); } const _b = { String: T_STRING, string: T_STRING, Int: T_INT, int: T_INT, Float: T_FLOAT, float: T_FLOAT, Number: T_NUMBER, number: T_NUMBER, Bool: T_BOOL, boolean: T_BOOL, Boolean: T_BOOL, bool: T_BOOL, Void: T_VOID, void: T_VOID, Never: T_NEVER, never: T_NEVER, Any: T_ANY, any: T_ANY, Unknown: T_UNKNOWN, unknown: T_UNKNOWN, Null: T_NULL, null: T_NULL, undefined: T_VOID, Object: T_NAMED("Object"), object: T_NAMED("Object"), Symbol: T_NAMED("Symbol"), symbol: T_NAMED("Symbol"), BigInt: T_NAMED("BigInt"), bigint: T_NAMED("BigInt") }; function parseAnnotation(_v) { if (!_v) { return null; } let s = _v.trim(); if ((s.startsWith("(") && s.endsWith(")"))) { s = s.slice(1, -1).trim(); } const unionParts = _a(s, " | "); if ((unionParts.length > 1)) { return T_UNION(...unionParts.map(parseAnnotation)); } const interParts = _a(s, " & "); if ((interParts.length > 1)) { return T_INTERSECTION(...interParts.map(parseAnnotation)); } const condMatch = s.match(/^(\w+)\s+extends\s+(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/); if (condMatch) { return { kind: "conditional", check: parseAnnotation(condMatch[1]), extends: parseAnnotation(condMatch[2]), then: parseAnnotation(condMatch[3]), else: parseAnnotation(condMatch[4]) }; } if (s.startsWith("keyof ")) { return { kind: "keyof", inner: parseAnnotation(s.slice(6)) }; } if (s.startsWith("typeof ")) { return { kind: "typeof", name: s.slice(7) }; } if (s.startsWith("readonly ")) { return parseAnnotation(s.slice(9)); } if (s.startsWith("infer ")) { return T_ANY; } const fnMatch = (s.match(/^fn\(([^)]*)\)\s*->\s*(.+)$/) ?? s.match(/^\(([^)]*)\)\s*->\s*(.+)$/)); if (fnMatch) { const paramStr = fnMatch[1].trim(); const retStr = fnMatch[2].trim(); const _n = (paramStr ? _a(paramStr, ", ").map((_x) => parseAnnotation(_x.slice(((_x.indexOf(":") >= 0) ? (_x.indexOf(":") + 1) : 0)).trim())) : []); return T_FN(_n, parseAnnotation(retStr)); } if (s.endsWith("?")) { return T_NULLABLE(parseAnnotation(s.slice(0, -1))); } if (s.endsWith("[]")) { return T_ARRAY(parseAnnotation(s.slice(0, -2))); } if ((s.startsWith("[") && s.endsWith("]"))) { const inner = s.slice(1, -1); if (!inner.trim()) { return T_TUPLE([]); } const parts = _a(inner, ", "); return T_TUPLE(parts.map((_x) => parseAnnotation(_x.replace(/^\.\.\./, "").trim()))); } if (s.startsWith(`${") and s.endsWith("}`)) { const inner = s.slice(1, -1).trim(); const _p = new Map(); if (inner) { const pairs = _a(inner, ", "); for (const _u of pairs) { const idxMatch = _u.match(/^\[(\w+):\s*\w+\]:\s*(.+)$/); if (idxMatch) { _p.set("[index]", parseAnnotation(idxMatch[2])); continue; } const colonIdx = _u.indexOf(":"); if ((colonIdx >= 0)) { const rawKey = _u.slice(0, colonIdx).trim().replace(/^readonly\s+/, ""); const _q = rawKey.replace(/\?$/, ""); const opt = rawKey.endsWith("?"); const valType = parseAnnotation(_u.slice((colonIdx + 1)).trim()); _p.set(_q, (opt ? T_UNION(valType, T_VOID) : valType)); } } } return T_OBJECT(_p); } const genMatch = s.match(/^(\w+)<(.+)>$/s); if (genMatch) { const gname = genMatch[1]; const rawArgs = _a(genMatch[2], ", "); const args = rawArgs.map((_y) => parseAnnotation(_y.trim())); if ((((gname == "Array") || (gname == "List")) || (gname == "ReadonlyArray"))) { return T_ARRAY((args[0] ?? T_UNKNOWN)); } if ((gname == "NonNullable")) { return _c(args[0]); } if ((gname == "Partial")) { return { kind: "utility", util: "Partial", inner: args[0] }; } if ((gname == "Required")) { return { kind: "utility", util: "Required", inner: args[0] }; } if ((gname == "Readonly")) { return args[0]; } if ((gname == "Record")) { return T_RECORD((args[0] ?? T_STRING), (args[1] ?? T_UNKNOWN)); } if ((gname == "Pick")) { return { kind: "utility", util: "Pick", inner: args[0], keys: args[1] }; } if ((gname == "Omit")) { return { kind: "utility", util: "Omit", inner: args[0], keys: args[1] }; } if ((gname == "Exclude")) { return { kind: "utility", util: "Exclude", inner: args[0], keys: args[1] }; } if ((gname == "Extract")) { return { kind: "utility", util: "Extract", inner: args[0], keys: args[1] }; } if ((gname == "ReturnType")) { return { kind: "utility", util: "ReturnType", inner: args[0] }; } if ((gname == "Parameters")) { return { kind: "utility", util: "Parameters", inner: args[0] }; } if ((gname == "Awaited")) { return { kind: "utility", util: "Awaited", inner: args[0] }; } return { kind: "generic", name: gname, args }; } if (_b[s]) { return _b[s]; } return T_NAMED(s); } module.exports.parseAnnotation = parseAnnotation; function _c(_l) { if (!_l) { return T_UNKNOWN; } if ((_l.kind == "union")) { return T_UNION(..._l.members.filter((_h) => ((_h.kind != "null") && (_h.kind != "void")))); } if (((_l.kind == "null") || (_l.kind == "void"))) { return T_NEVER; } return _l; } function _d(_z, _aa) { if ((!_z || !_aa)) { return true; } if ((_aa.kind == "any")) { return true; } if ((_z.kind == "any")) { return true; } if ((_z.kind == "never")) { return true; } if ((_aa.kind == "unknown")) { return true; } if (((_z.kind == "void") && (_aa.kind == "void"))) { return true; } if (((_z.kind == "null") && (_aa.kind == "null"))) { return true; } if (((_z.kind == "null") && (_aa.kind == "union"))) { return _aa.members.some((_h) => (((_h.kind == "null") || (_h.kind == "any")) || (_h.kind == "void"))); } if ((_z.kind == "union")) { return _z.members.every((_h) => _d(_h, _aa)); } if ((_aa.kind == "union")) { return _aa.members.some((_h) => _d(_z, _h)); } if ((_z.kind == "intersection")) { return _z.members.some((_h) => _d(_h, _aa)); } if ((_aa.kind == "intersection")) { return _aa.members.every((_h) => _d(_z, _h)); } if (((_z.kind == "primitive") && (_aa.kind == "primitive"))) { if ((_z.name == _aa.name)) { return true; } if (((_aa.name == "Number") && (((_z.name == "Int") || (_z.name == "Float")) || (_z.name == "Number")))) { return true; } if (((_aa.name == "Float") && (_z.name == "Int"))) { return true; } if (((_z.name == "Bool") && (_aa.name == "Boolean"))) { return true; } if (((_z.name == "Boolean") && (_aa.name == "Bool"))) { return true; } return false; } if (((_z.kind == "literal") && (_aa.kind == "primitive"))) { const lmap = { string: "String", number: "Number", boolean: "Bool" }; return ((lmap[_z.prim] == _aa.name) || ((_z.prim == "number") && (((_aa.name == "Int") || (_aa.name == "Float")) || (_aa.name == "Number")))); } if (((_z.kind == "named") && (_aa.kind == "named"))) { return ((_z.name == _aa.name) || (_aa.name == "Object")); } if (((_z.kind == "generic") && (_aa.kind == "generic"))) { const arrayNames = new Set(["Array", "List", "ReadonlyArray"]); if ((_z.name != _aa.name)) { if (!(arrayNames.has(_z.name) && arrayNames.has(_aa.name))) { return false; } } if ((_z.args.length != _aa.args.length)) { return false; } return _z.args.every((_y, _ab) => _d(_y, _aa.args[_ab])); } if (((_z.kind == "tuple") && (_aa.kind == "tuple"))) { if ((_z.types.length != _aa.types.length)) { return false; } return _z.types.every((_l, _ab) => _d(_l, _aa.types[_ab])); } if ((((_z.kind == "generic") && (_z.name == "Array")) && (_aa.kind == "tuple"))) { const elemType = (_z.args[0] ?? T_UNKNOWN); if ((elemType.kind == "unknown")) { return true; } return _aa.types.every((_l) => _d(elemType, _l)); } if (((_z.kind == "object") && (_aa.kind == "object"))) { for (const _u of _aa.shape.entries()) { const _q = _u[0]; const toType = _u[1]; if (!_z.shape.has(_q)) { return false; } if (!_d(_z.shape.get(_q), toType)) { return false; } } return true; } if (((_z.kind == "object") && (_aa.kind == "named"))) { return true; } if (((_z.kind == "fn") && (_aa.kind == "fn"))) { if ((_aa.ret && _z.ret)) { return _d(_z.ret, _aa.ret); } return true; } if (((_z.kind == "record") && (_aa.kind == "record"))) { return _d(_z.val, _aa.val); } if ((_aa.kind == "utility")) { return true; } if ((_z.kind == "utility")) { return true; } return false; } function _e(_y, _ac) { if ((!_y || (_y.kind == "unknown"))) { return (_ac ?? T_UNKNOWN); } if ((!_ac || (_ac.kind == "unknown"))) { return _y; } if ((typeStr(_y) == typeStr(_ac))) { return _y; } if (((_y.kind == "any") || (_ac.kind == "any"))) { return T_ANY; } return T_UNION(_y, _ac); } class TypeEnv { constructor(parent, vars, retType, isAsync) { this.parent = parent; this.vars = vars; this.retType = retType; this.isAsync = isAsync; } set(_m, _ad) { this.vars.set(_m, _ad); } has(_m) { let e = this; while (e) { if (e.vars.has(_m)) { return true; } e = e.parent; } return false; } get(_m) { let env = this; while (env) { if (env.vars.has(_m)) { return env.vars.get(_m); } env = env.parent; } return null; } child() { return new TypeEnv(this, new Map(), this.retType, this.isAsync); } childFn(_ae, _af) { return new TypeEnv(this, new Map(), _ae, (_af ?? false)); } narrow(_m, _ad) { const c = new TypeEnv(this, new Map(), this.retType, this.isAsync); if ((_m && _ad)) { c.vars.set(_m, _ad); } return c; } } module.exports.TypeEnv = TypeEnv; class _f { constructor(message, name, hint, line, col) { this.message = message; this.name = name; this.hint = hint; this.line = line; this.col = col; } } class FluxTypeChecker { constructor(errors, warnings, interfaces, types, classes, enums) { this.errors = errors; this.warnings = warnings; this.interfaces = interfaces; this.types = types; this.classes = classes; this.enums = enums; } _err(_ag, _ah, _ai) { const e = new _f(); e.message = _ag; e.name = "TypeError"; e.hint = (_ai ?? null); if (_ah) { e.line = _ah.line; e.col = _ah.col; } this.errors.push(e); } _warn(_ag, _ah, _ai) { const w = new _f(); w.message = _ag; w.name = "TypeError"; w.hint = (_ai ?? null); if (_ah) { w.line = _ah.line; w.col = _ah.col; } this.warnings.push(w); } check(_aj) { this.errors = []; this.warnings = []; this.interfaces = new Map(); this.types = new Map(); this.classes = new Map(); this.enums = new Map(); this._collectDeclarations(_aj.body); this._validateImplementations(); const env = new TypeEnv(null, new Map(), null, false); this._registerBuiltins(env); this._checkStmts(_aj.body, env); return { errors: this.errors, warnings: this.warnings }; } _collectDeclarations(_ak) { for (const _al of _ak) { const n = ((_al.type == "ExportDecl") ? _al.decl : _al); if (!n) { continue; } if ((n.type == "InterfaceDecl")) { this.interfaces.set(n.name, n); } else if ((n.type == "TypeDecl")) { this.types.set(n.name, n); } else if ((n.type == "ClassDecl")) { this.classes.set(n.name, n); } else if ((n.type == "EnumDecl")) { this.enums.set(n.name, n); } } } _validateImplementations() { for (const _am of this.classes.entries()) { const cls = _am[1]; for (const _an of (cls.interfaces ?? [])) { this._checkInterfaceImpl(cls, _an); } } } _checkInterfaceImpl(_ao, _an) { const iface = this.interfaces.get(_an); if (!iface) { this._warn((((("Class '" + _ao.name) + "' implements unknown interface '") + _an) + "'"), _ao.loc, (("Define 'interface " + _an) + "' before use")); return; } for (const _ap of iface.members) { if ((_ap.kind == "method")) { const impl = _ao.methods.find((_h) => (_h.name == _ap.name)); if (!impl) { this._err((((((("Class '" + _ao.name) + "' does not implement method '") + _ap.name) + "()' required by '") + _an) + "'"), _ao.loc, (("Add 'fn " + _ap.name) + "(...)' to the class")); } } else if (((_ap.kind == "field") && !_ap.optional)) { const hasField = _ao.fields.find((_aq) => (_aq.name == _ap.name)); const hasMethod = _ao.methods.find((_h) => (_h.name == _ap.name)); if ((!hasField && !hasMethod)) { this._err((((((("Class '" + _ao.name) + "' is missing field '") + _ap.name) + "' required by '") + _an) + "'"), _ao.loc, (((("Add '" + _ap.name) + ": ") + (_ap.typeAnn ?? "Any")) + "' to the class")); } } } for (const _ar of (iface.superInterfaces ?? [])) { this._checkInterfaceImpl(_ao, _ar); } } _isStructurallyCompatible(_as, _at) { const iface = this.interfaces.get(_at); if (!iface) { const _ao = this.classes.get(_at); if (!_ao) { return false; } for (const _au of _ao.fields) { if ((!_as.has(_au.name) && !_au.optional)) { return false; } } return true; } for (const _ap of iface.members) { if (((_ap.kind == "field") && !_ap.optional)) { if (!_as.has(_ap.name)) { return false; } } } return true; } _isAssignable(_z, _aa) { if ((!_z || !_aa)) { return true; } if ((_aa.kind == "any")) { return true; } if ((_z.kind == "any")) { return true; } if ((_z.kind == "never")) { return true; } if ((_aa.kind == "unknown")) { return true; } if (((_z.kind == "object") && (_aa.kind == "named"))) { return this._isStructurallyCompatible(_z.shape, _aa.name); } if (((_z.kind == "named") && (_aa.kind == "named"))) { if ((_z.name == _aa.name)) { return true; } if ((_aa.name == "Object")) { return true; } const _ao = this.classes.get(_z.name); if ((_ao && (_ao.interfaces ?? []).includes(_aa.name))) { return true; } if ((_ao && (_ao.superClass == _aa.name))) { return true; } const iface = this.interfaces.get(_z.name); if ((iface && (iface.superInterfaces ?? []).includes(_aa.name))) { return true; } return false; } if ((_aa.kind == "utility")) { if ((_aa.util == "Partial")) { return true; } if ((_aa.util == "Required")) { return this._isAssignable(_z, _aa.inner); } if ((_aa.util == "NonNullable")) { return ((_z.kind != "null") && (_z.kind != "void")); } return true; } if ((_z.kind == "utility")) { return true; } return _d(_z, _aa); } _analyzeNarrowingCondition(_av, _aw) { if (!_av) { return null; } if (((((_av.type == "BinaryExpr") && ((_av.op == "!=") || (_av.op == "!=="))) && (_av.left.type == "Identifier")) && (_av.right.type == "NullLit"))) { const _m = _av.left.name; const _l = _aw.get(_m); if ((_l && (_l.kind == "union"))) { const narrowed = T_UNION(..._l.members.filter((_h) => ((_h.kind != "null") && (_h.kind != "void")))); return { varName: _m, trueType: narrowed, falseType: T_UNION(T_NULL, T_VOID) }; } } if ((((((_av.type == "BinaryExpr") && ((_av.op == "===") || (_av.op == "=="))) && (_av.left.type == "TypeofExpr")) && (_av.left.operand.type == "Identifier")) && (_av.right.type == "StringLit"))) { const _m = _av.left.operand.name; const typeMap = { string: T_STRING, number: T_NUMBER, boolean: T_BOOL, undefined: T_VOID }; const narrowedTrue = (typeMap[_av.right.value] ?? T_UNKNOWN); return { varName: _m, trueType: narrowedTrue, falseType: (_aw.get(_m) ?? T_UNKNOWN) }; } if ((((_av.type == "BinaryExpr") && (_av.op == "instanceof")) && (_av.left.type == "Identifier"))) { const _m = _av.left.name; const _ao = ((_av.right.type == "Identifier") ? _av.right.name : null); if (_ao) { return { varName: _m, trueType: T_NAMED(_ao), falseType: (_aw.get(_m) ?? T_UNKNOWN) }; } } if ((_av.type == "Identifier")) { const _m = _av.name; const _l = _aw.get(_m); if ((_l && (_l.kind == "union"))) { const narrowed = T_UNION(..._l.members.filter((_h) => ((_h.kind != "null") && (_h.kind != "void")))); return { varName: _m, trueType: narrowed, falseType: T_UNION(T_NULL, T_VOID) }; } } return null; } _registerBuiltins(_aw) { _aw.set("console", T_NAMED("Console")); _aw.set("process", T_NAMED("Process")); _aw.set("Math", T_NAMED("Math")); _aw.set("JSON", T_NAMED("JSON")); _aw.set("Date", T_NAMED("Date")); _aw.set("Promise", T_NAMED("Promise")); _aw.set("Error", T_NAMED("Error")); _aw.set("Buffer", T_NAMED("Buffer")); _aw.set("RegExp", T_NAMED("RegExp")); _aw.set("Map", T_NAMED("Map")); _aw.set("Set", T_NAMED("Set")); _aw.set("WeakMap", T_NAMED("WeakMap")); _aw.set("WeakSet", T_NAMED("WeakSet")); _aw.set("Symbol", T_NAMED("Symbol")); _aw.set("Object", T_NAMED("Object")); _aw.set("Array", T_NAMED("Array")); _aw.set("String", T_NAMED("String")); _aw.set("Number", T_NAMED("Number")); _aw.set("Boolean", T_NAMED("Boolean")); _aw.set("Function", T_NAMED("Function")); _aw.set("parseInt", T_FN([T_STRING, T_INT], T_INT)); _aw.set("parseFloat", T_FN([T_STRING], T_FLOAT)); _aw.set("isNaN", T_FN([T_NUMBER], T_BOOL)); _aw.set("isFinite", T_FN([T_NUMBER], T_BOOL)); _aw.set("require", T_FN([T_STRING], T_ANY)); _aw.set("fetch", T_FN([T_STRING], T_ANY)); _aw.set("print", T_FN([], T_VOID)); _aw.set("undefined", T_VOID); _aw.set("Infinity", T_NUMBER); _aw.set("NaN", T_NUMBER); _aw.set("globalThis", T_NAMED("Object")); } _inferType(_al, _aw) { if (!_al) { return T_UNKNOWN; } if ((_al.type == "NumberLit")) { if (String(_al.value).includes(".")) { return T_FLOAT; } return T_INT; } if ((_al.type == "StringLit")) { return T_STRING; } if ((_al.type == "BoolLit")) { return T_BOOL; } if ((_al.type == "NullLit")) { return T_NULL; } if ((_al.type == "Identifier")) { const _l = _aw.get(_al.name); return (_l ?? T_UNKNOWN); } if ((_al.type == "ArrayExpr")) { if ((_al.items.length == 0)) { return T_ARRAY(T_UNKNOWN); } const elemTypes = _al.items.map((_ab) => (_ab ? this._inferType(_ab, _aw) : T_UNKNOWN)); const merged = elemTypes.reduce((_y, _ac) => _e(_y, _ac), T_UNKNOWN); return T_ARRAY(merged); } if ((_al.type == "ObjectExpr")) { const _p = new Map(); for (const _u of _al.pairs) { if ((!_u.spread && _u.key)) { _p.set(_u.key, (_u.value ? this._inferType(_u.value, _aw) : T_UNKNOWN)); } } return T_OBJECT(_p); } if ((_al.type == "LambdaExpr")) { const paramTypes = _al.params.map((_x) => (_x.typeAnn ? parseAnnotation(_x.typeAnn) : T_UNKNOWN)); const _ae = (_al.retType ? parseAnnotation(_al.retType) : T_UNKNOWN); return T_FN(paramTypes, _ae); } if (((_al.type == "CallExpr") || (_al.type == "OptCallExpr"))) { const calleeType = this._inferType(_al.callee, _aw); if ((calleeType.kind == "fn")) { return (calleeType.ret ?? T_UNKNOWN); } return T_UNKNOWN; } if (((_al.type == "MemberExpr") || (_al.type == "OptMemberExpr"))) { return T_UNKNOWN; } if ((_al.type == "TernaryExpr")) { const thenType = this._inferType(_al.then, _aw); const elseType = this._inferType(_al.else_, _aw); return _e(thenType, elseType); } if ((_al.type == "BinaryExpr")) { if ((((((_al.op == "+") || (_al.op == "-")) || (_al.op == "*")) || (_al.op == "/")) || (_al.op == "%"))) { return T_NUMBER; } if (((((((((_al.op == "==") || (_al.op == "!=")) || (_al.op == "===")) || (_al.op == "!==")) || (_al.op == "<")) || (_al.op == ">")) || (_al.op == "<=")) || (_al.op == ">="))) { return T_BOOL; } if (((((_al.op == "and") || (_al.op == "or")) || (_al.op == "&&")) || (_al.op == "||"))) { return T_BOOL; } return T_UNKNOWN; } if ((_al.type == "AwaitExpr")) { const inner = this._inferType(_al.operand, _aw); return inner; } if ((_al.type == "NewExpr")) { if ((_al.callee && (_al.callee.type == "Identifier"))) { return T_NAMED(_al.callee.name); } return T_UNKNOWN; } if ((_al.type == "TemplateLit")) { return T_STRING; } if (((_al.type == "CastExpr") || (_al.type == "AsConstExpr"))) { if (_al.typeAnn) { return parseAnnotation(_al.typeAnn); } return this._inferType(_al.expr, _aw); } return T_UNKNOWN; } _checkStmts(_ak, _aw) { for (const _al of _ak) { this._checkStmt(_al, _aw); } } _checkStmt(_al, _aw) { if (!_al) { return; } if ((_al.type == "VarDecl")) { const declared = (_al.typeAnn ? parseAnnotation(_al.typeAnn) : null); let actual = null; if (_al.init) { actual = this._inferType(_al.init, _aw); } if (((declared && actual) && (actual.kind != "unknown"))) { if (!this._isAssignable(actual, declared)) { this._err((((((("Type '" + typeStr(actual)) + "' is not assignable to '") + _al.name) + ": ") + typeStr(declared)) + "'"), _al.loc, (("Change the value to match '" + typeStr(declared)) + "' or update the annotation")); } } _aw.set(_al.name, ((declared ?? actual) ?? T_UNKNOWN)); } else if ((_al.type == "DestructureDecl")) { const srcType = (_al.init ? this._inferType(_al.init, _aw) : T_UNKNOWN); if ((_al.patternType == "object")) { for (const _x of _al.pattern) { let memberType = T_UNKNOWN; if (((srcType.kind == "object") && srcType.shape.has(_x.key))) { memberType = srcType.shape.get(_x.key); } _aw.set(_x.alias, memberType); } } else { let idx = 0; for (const _x of _al.pattern) { if (_x) { let elemType = T_UNKNOWN; if (((srcType.kind == "tuple") && srcType.types[idx])) { elemType = srcType.types[idx]; } else if (((srcType.kind == "generic") && (srcType.name == "Array"))) { elemType = (srcType.args[0] ?? T_UNKNOWN); } _aw.set(_x.name, elemType); } idx = (idx + 1); } } } else if ((_al.type == "FnDecl")) { const _ae = (_al.retType ? parseAnnotation(_al.retType) : null); const paramTypes = _al.params.map((_x) => (_x.typeAnn ? parseAnnotation(_x.typeAnn) : T_UNKNOWN)); if (_al.name) { _aw.set(_al.name, T_FN(paramTypes, (_ae ?? T_UNKNOWN))); } const fnEnv = _aw.childFn(_ae, _al.async); let _ab = 0; for (const _x of _al.params) { fnEnv.set(_x.name, paramTypes[_ab]); _ab = (_ab + 1); } if (_al.inline) { const bodyType = this._inferType(_al.body, fnEnv); if (((_ae && bodyType) && (bodyType.kind != "unknown"))) { if (!this._isAssignable(bodyType, _ae)) { this._err((((((("Function '" + (_al.name ?? "(anon)")) + "' returns '") + typeStr(bodyType)) + "' but declared '") + typeStr(_ae)) + "'"), _al.loc, "Fix return type or update the annotation"); } } } else { this._checkStmts(_al.body, fnEnv); } } else if ((_al.type == "ClassDecl")) { _aw.set(_al.name, T_NAMED(_al.name)); const clsEnv = _aw.child(); const _p = new Map(); for (const _aq of _al.fields) { const ft = (_aq.typeAnn ? parseAnnotation(_aq.typeAnn) : T_UNKNOWN); clsEnv.set(_aq.name, ft); _p.set(_aq.name, ft); } clsEnv.set("self", T_OBJECT(_p)); for (const _h of _al.methods) { this._checkStmt(_h, clsEnv); } } else if ((_al.type == "DeclareDecl")) { const d = _al.decl; if ((d.type == "FnDecl")) { const _ae = (d.retType ? parseAnnotation(d.retType) : null); const paramTypes = d.params.map((_x) => (_x.typeAnn ? parseAnnotation(_x.typeAnn) : T_UNKNOWN)); if (d.name) { _aw.set(d.name, T_FN(paramTypes, (_ae ?? T_UNKNOWN))); } } else if ((d.type == "VarDecl")) { const _l = (d.typeAnn ? parseAnnotation(d.typeAnn) : T_UNKNOWN); _aw.set(d.name, _l); } else if ((d.type == "ClassDecl")) { _aw.set(d.name, T_NAMED(d.name)); } } else if ((_al.type == "TypeDecl")) { for (const _ax of _al.variants) { if ((_ax.fields.length == 0)) { _aw.set(_ax.name, T_NAMED(_al.name)); } else { _aw.set(_ax.name, T_FN(_ax.fields.map((_ay) => T_ANY), T_NAMED(_al.name))); } } } else if ((_al.type == "InterfaceDecl")) { _aw.set(_al.name, T_NAMED(_al.name)); } else if ((_al.type == "EnumDecl")) { _aw.set(_al.name, T_NAMED(_al.name)); } else if ((_al.type == "IfStmt")) { this._inferType(_al.cond, _aw); const narrowing = this._analyzeNarrowingCondition(_al.cond, _aw); const thenEnv = (narrowing ? _aw.narrow(narrowing.varName, narrowing.trueType) : _aw.child()); const elseEnv = (narrowing ? _aw.narrow(narrowing.varName, narrowing.falseType) : _aw.child()); this._checkStmts(_al.then, thenEnv); for (const _az of _al.elseifs) { this._inferType(_az.cond, _aw); this._checkStmts(_az.body, _aw.child()); } if (_al.else_) { this._checkStmts(_al.else_, elseEnv); } } else if ((_al.type == "ForInStmt")) { const iterType = this._inferType(_al.iter, _aw); const inner = _aw.child(); if (((iterType.kind == "generic") && (iterType.name == "Array"))) { inner.set(_al.var, (iterType.args[0] ?? T_UNKNOWN)); } else if ((iterType.kind == "tuple")) { inner.set(_al.var, (iterType.types[0] ?? T_UNKNOWN)); } else { inner.set(_al.var, T_UNKNOWN); } this._checkStmts(_al.body, inner); } else if (((_al.type == "WhileStmt") || (_al.type == "DoWhileStmt"))) { this._inferType(_al.cond, _aw); this._checkStmts((_al.body ?? []), _aw.child()); } else if ((_al.type == "MatchStmt")) { this._inferType(_al.subject, _aw); for (const _ba of _al.arms) { const inner = _aw.child(); if ((_ba.pattern.type == "VariantPat")) { for (const _ac of _ba.pattern.bindings) { inner.set(_ac, T_UNKNOWN); } } this._checkStmts(_ba.body, inner); } } else if ((_al.type == "ReturnStmt")) { if (_al.value) { const _ae = _aw.retType; const retActual = this._inferType(_al.value, _aw); if (((_ae && retActual) && (retActual.kind != "unknown"))) { if (!this._isAssignable(retActual, _ae)) { this._err((((("Return type '" + typeStr(retActual)) + "' is not assignable to declared '") + typeStr(_ae)) + "'"), _al.loc, "Fix the return value or update the return type annotation"); } } } } else if ((_al.type == "TryCatchStmt")) { this._checkStmts(_al.tryBody, _aw.child()); if (_al.catchBody) { const inner = _aw.child(); if (_al.catchParam) { inner.set(_al.catchParam, T_ANY); } this._checkStmts(_al.catchBody, inner); } if (_al.finallyBody) { this._checkStmts(_al.finallyBody, _aw.child()); } } else if ((_al.type == "ThrowStmt")) { if (_al.value) { this._inferType(_al.value, _aw); } } else if ((_al.type == "ImportDecl")) { if (_al.defaultName) { _aw.set(_al.defaultName, T_ANY); } if (_al.namespaceName) { _aw.set(_al.namespaceName, T_ANY); } for (const _bb of _al.names) { const nm = ((typeof _bb == "string") ? _bb : _bb.alias); _aw.set(nm, T_ANY); } } else if ((_al.type == "ExportDecl")) { if (_al.isDefault) { this._inferType(_al.decl, _aw); } else { this._checkStmt(_al.decl, _aw); } } else if ((_al.type == "ExprStmt")) { this._inferType(_al.expr, _aw); } } } module.exports.FluxTypeChecker = FluxTypeChecker;