@xnoxs/flux-lang 3.2.1 → 3.2.2

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/src/checker.js DELETED
@@ -1,322 +0,0 @@
1
- 'use strict';
2
-
3
- // ── Flux Static Checker ───────────────────────────────────────────────────────
4
- // Stage 1: Val immutability analysis (fast, always runs)
5
- // Stage 2: Full type inference & checking (runs via FluxTypeChecker)
6
-
7
- class CheckError {
8
- constructor(message, loc, hint = null) {
9
- this.message = message;
10
- this.loc = loc;
11
- this.hint = hint;
12
- this.name = 'CheckError';
13
- if (loc) { this.line = loc.line; this.col = loc.col; }
14
- }
15
- }
16
-
17
- class Scope {
18
- constructor(parent = null) {
19
- this.parent = parent;
20
- this.vars = new Map(); // name → { kind:'val'|'var', loc }
21
- }
22
-
23
- define(name, kind, loc) { this.vars.set(name, { kind, loc }); }
24
-
25
- lookup(name) {
26
- let scope = this;
27
- while (scope) {
28
- if (scope.vars.has(name)) return scope.vars.get(name);
29
- scope = scope.parent;
30
- }
31
- return null;
32
- }
33
-
34
- isVal(name) {
35
- const entry = this.lookup(name);
36
- return entry && entry.kind === 'val';
37
- }
38
- }
39
-
40
- class Checker {
41
- constructor() {
42
- this.errors = [];
43
- this.warnings = [];
44
- }
45
-
46
- check(ast) {
47
- this.errors = [];
48
- this.warnings = [];
49
- const scope = new Scope();
50
- this.walkStmts(ast.body, scope);
51
- return { errors: this.errors, warnings: this.warnings };
52
- }
53
-
54
- error(msg, loc, hint = null) { this.errors.push(new CheckError(msg, loc, hint)); }
55
- warn(msg, loc, hint = null) { this.warnings.push(new CheckError(msg, loc, hint)); }
56
-
57
- walkStmts(stmts, scope) {
58
- for (const node of stmts) this.walkStmt(node, scope);
59
- }
60
-
61
- walkStmt(node, scope) {
62
- if (!node) return;
63
- switch (node.type) {
64
- case 'VarDecl':
65
- if (node.init) this.walkExpr(node.init, scope);
66
- scope.define(node.name, node.kind, node.loc);
67
- break;
68
-
69
- case 'DestructureDecl':
70
- if (node.init) this.walkExpr(node.init, scope);
71
- if (node.patternType === 'object') {
72
- for (const p of node.pattern) scope.define(p.alias, node.kind, node.loc);
73
- } else {
74
- for (const p of node.pattern) { if (p) scope.define(p.name, node.kind, node.loc); }
75
- }
76
- break;
77
-
78
- case 'FnDecl': {
79
- const inner = new Scope(scope);
80
- for (const p of node.params) inner.define(p.name, 'val', node.loc);
81
- if (node.name) scope.define(node.name, 'val', node.loc);
82
- if (node.inline) {
83
- this.walkExpr(node.body, inner);
84
- } else {
85
- this.walkStmts(node.body, inner);
86
- }
87
- break;
88
- }
89
-
90
- case 'ClassDecl': {
91
- scope.define(node.name, 'val', node.loc);
92
- const cls = new Scope(scope);
93
- for (const f of node.fields) cls.define(f.name, 'var', node.loc);
94
- for (const m of node.methods) this.walkStmt(m, cls);
95
- break;
96
- }
97
-
98
- case 'TypeDecl':
99
- for (const v of node.variants) scope.define(v.name, 'val', node.loc);
100
- break;
101
-
102
- case 'InterfaceDecl':
103
- scope.define(node.name, 'val', node.loc);
104
- break;
105
-
106
- case 'EnumDecl':
107
- scope.define(node.name, 'val', node.loc);
108
- break;
109
-
110
- case 'IfStmt':
111
- this.walkExpr(node.cond, scope);
112
- this.walkStmts(node.then, new Scope(scope));
113
- for (const ei of node.elseifs) {
114
- this.walkExpr(ei.cond, scope);
115
- this.walkStmts(ei.body, new Scope(scope));
116
- }
117
- if (node.else_) this.walkStmts(node.else_, new Scope(scope));
118
- break;
119
-
120
- case 'ForInStmt': {
121
- this.walkExpr(node.iter, scope);
122
- const inner = new Scope(scope);
123
- inner.define(node.var, 'val', node.loc);
124
- this.walkStmts(node.body, inner);
125
- break;
126
- }
127
-
128
- case 'WhileStmt':
129
- this.walkExpr(node.cond, scope);
130
- this.walkStmts(node.body, new Scope(scope));
131
- break;
132
-
133
- case 'DoWhileStmt':
134
- this.walkStmts(node.body, new Scope(scope));
135
- this.walkExpr(node.cond, scope);
136
- break;
137
-
138
- case 'MatchStmt':
139
- this.walkExpr(node.subject, scope);
140
- for (const arm of node.arms) {
141
- const inner = new Scope(scope);
142
- if (arm.pattern.type === 'VariantPat') {
143
- for (const b of arm.pattern.bindings) inner.define(b, 'val', node.loc);
144
- }
145
- if (arm.guard) this.walkExpr(arm.guard, inner);
146
- this.walkStmts(arm.body, inner);
147
- }
148
- break;
149
-
150
- case 'ReturnStmt':
151
- if (node.value) this.walkExpr(node.value, scope);
152
- break;
153
-
154
- case 'ThrowStmt':
155
- this.walkExpr(node.value, scope);
156
- break;
157
-
158
- case 'TryCatchStmt': {
159
- this.walkStmts(node.tryBody, new Scope(scope));
160
- if (node.catchBody) {
161
- const inner = new Scope(scope);
162
- if (node.catchParam) inner.define(node.catchParam, 'val', node.loc);
163
- this.walkStmts(node.catchBody, inner);
164
- }
165
- if (node.finallyBody) this.walkStmts(node.finallyBody, new Scope(scope));
166
- break;
167
- }
168
-
169
- case 'ImportDecl':
170
- if (node.defaultName) scope.define(node.defaultName, 'val', node.loc);
171
- if (node.namespaceName) scope.define(node.namespaceName, 'val', node.loc);
172
- for (const n of node.names) scope.define(typeof n === 'string' ? n : n.alias, 'val', node.loc);
173
- break;
174
-
175
- case 'ExportDecl':
176
- this.walkStmt(node.isDefault ? { type: 'ExprStmt', expr: node.decl } : node.decl, scope);
177
- break;
178
-
179
- case 'ExprStmt':
180
- this.walkExpr(node.expr, scope);
181
- break;
182
-
183
- case 'BreakStmt':
184
- case 'ContinueStmt':
185
- break;
186
-
187
- default:
188
- // Unknown node — skip silently
189
- }
190
- }
191
-
192
- walkExpr(node, scope) {
193
- if (!node) return;
194
- switch (node.type) {
195
-
196
- case 'AssignExpr': {
197
- const target = node.target;
198
- if (target.type === 'Identifier') {
199
- if (scope.isVal(target.name)) {
200
- this.error(
201
- `Cannot reassign 'val ${target.name}' — val is immutable`,
202
- target.loc,
203
- `Use 'var ${target.name}' if you need a mutable variable`
204
- );
205
- }
206
- }
207
- this.walkExpr(node.target, scope);
208
- this.walkExpr(node.value, scope);
209
- break;
210
- }
211
-
212
- case 'UpdateExpr':
213
- if (node.operand.type === 'Identifier' && scope.isVal(node.operand.name)) {
214
- this.error(
215
- `Cannot apply '${node.op}' to 'val ${node.operand.name}' — val is immutable`,
216
- node.operand.loc,
217
- `Use 'var ${node.operand.name}' if you need a mutable variable`
218
- );
219
- }
220
- this.walkExpr(node.operand, scope);
221
- break;
222
-
223
- case 'BinaryExpr':
224
- case 'PipeExpr':
225
- this.walkExpr(node.left, scope);
226
- this.walkExpr(node.right, scope);
227
- break;
228
-
229
- case 'UnaryExpr':
230
- case 'AwaitExpr':
231
- case 'TypeofExpr':
232
- this.walkExpr(node.operand, scope);
233
- break;
234
-
235
- case 'TernaryExpr':
236
- this.walkExpr(node.cond, scope);
237
- this.walkExpr(node.then, scope);
238
- this.walkExpr(node.else_, scope);
239
- break;
240
-
241
- case 'CallExpr':
242
- case 'OptCallExpr':
243
- this.walkExpr(node.callee, scope);
244
- for (const a of node.args) this.walkExpr(a, scope);
245
- break;
246
-
247
- case 'MemberExpr':
248
- case 'OptMemberExpr':
249
- this.walkExpr(node.obj, scope);
250
- break;
251
-
252
- case 'IndexExpr':
253
- case 'OptIndexExpr':
254
- this.walkExpr(node.obj, scope);
255
- this.walkExpr(node.idx, scope);
256
- break;
257
-
258
- case 'NewExpr':
259
- for (const a of node.args) this.walkExpr(a, scope);
260
- break;
261
-
262
- case 'ArrayExpr':
263
- for (const i of node.items) if (i) this.walkExpr(i, scope);
264
- break;
265
-
266
- case 'ObjectExpr':
267
- for (const p of node.pairs) if (p.value) this.walkExpr(p.value, scope);
268
- break;
269
-
270
- case 'SpreadExpr':
271
- this.walkExpr(node.expr, scope);
272
- break;
273
-
274
- case 'LambdaExpr': {
275
- const inner = new Scope(scope);
276
- for (const p of node.params) inner.define(p.name, 'val', null);
277
- this.walkExpr(node.body, inner);
278
- break;
279
- }
280
-
281
- case 'FnDecl': {
282
- const inner = new Scope(scope);
283
- for (const p of node.params) inner.define(p.name, 'val', null);
284
- if (node.inline) {
285
- this.walkExpr(node.body, inner);
286
- } else {
287
- this.walkStmts(node.body, inner);
288
- }
289
- break;
290
- }
291
-
292
- case 'TemplateLit':
293
- break;
294
-
295
- case 'CastExpr':
296
- case 'AsConstExpr':
297
- case 'SatisfiesExpr':
298
- case 'IsExpr':
299
- case 'NonNullExpr':
300
- this.walkExpr(node.expr, scope);
301
- break;
302
-
303
- case 'RangeExpr':
304
- this.walkExpr(node.start, scope);
305
- this.walkExpr(node.end, scope);
306
- break;
307
-
308
- case 'Identifier':
309
- case 'NumberLit':
310
- case 'BoolLit':
311
- case 'NullLit':
312
- case 'StringLit':
313
- case 'SelfExpr':
314
- break;
315
-
316
- default:
317
- // Unknown expression node — skip
318
- }
319
- }
320
- }
321
-
322
- module.exports = { Checker };