@hoox-sh/pynets 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/CHANGELOG.md +30 -0
- package/LICENSE +661 -0
- package/NOTICE +46 -0
- package/README.md +327 -0
- package/dist/browser.js +44 -0
- package/dist/index.d.ts +348 -0
- package/dist/index.js +41741 -0
- package/package.json +77 -0
- package/src/ast/builder.ts +1002 -0
- package/src/ast/dump.ts +43 -0
- package/src/ast/helper.ts +77 -0
- package/src/ast/nodes.ts +570 -0
- package/src/ast/unparse.ts +360 -0
- package/src/cli/rich.ts +378 -0
- package/src/cli.ts +627 -0
- package/src/generated/PinescriptLexer.interp +267 -0
- package/src/generated/PinescriptLexer.tokens +131 -0
- package/src/generated/PinescriptLexer.ts +673 -0
- package/src/generated/PinescriptLexerBase.ts +395 -0
- package/src/generated/PinescriptParser.interp +267 -0
- package/src/generated/PinescriptParser.tokens +131 -0
- package/src/generated/PinescriptParser.ts +8863 -0
- package/src/generated/PinescriptParserBase.ts +21 -0
- package/src/generated/PinescriptParserVisitor.ts +840 -0
- package/src/index.ts +55 -0
- package/src/parser/LexerBase.ts +395 -0
- package/src/parser/ParserBase.ts +21 -0
- package/src/parser/error.ts +33 -0
- package/src/runtime/array.ts +486 -0
- package/src/runtime/color.ts +164 -0
- package/src/runtime/drawings.ts +510 -0
- package/src/runtime/input.ts +102 -0
- package/src/runtime/interpret.ts +3897 -0
- package/src/runtime/library.ts +282 -0
- package/src/runtime/log.ts +69 -0
- package/src/runtime/map.ts +85 -0
- package/src/runtime/math.ts +231 -0
- package/src/runtime/matrix.ts +1154 -0
- package/src/runtime/provider.ts +232 -0
- package/src/runtime/request.ts +372 -0
- package/src/runtime/series.ts +44 -0
- package/src/runtime/str.ts +433 -0
- package/src/runtime/strategy.ts +1105 -0
- package/src/runtime/ta.ts +2093 -0
- package/src/runtime/ticker.ts +81 -0
- package/src/runtime/time.ts +439 -0
- package/src/runtime/timeframe.ts +85 -0
- package/src/runtime/udt.ts +119 -0
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (C) 2024-2026 jango_blockchained
|
|
3
|
+
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
*
|
|
5
|
+
* ANTLR parse tree → ASDL subset. Slice 1 adds assignment visits
|
|
6
|
+
* (`x = …`, `var`/`varip`, `:=`) on top of slice-0 expressions;
|
|
7
|
+
* TypeDef / EnumDef visit type_declaration and enum_declaration.
|
|
8
|
+
*/
|
|
9
|
+
import type { ParserRuleContext, RuleNode } from "antlr4";
|
|
10
|
+
import PinescriptParserVisitor from "../generated/PinescriptParserVisitor.ts";
|
|
11
|
+
import {
|
|
12
|
+
type Additive_expressionContext,
|
|
13
|
+
type Additive_opContext,
|
|
14
|
+
type Argument_definitionContext,
|
|
15
|
+
type Argument_listContext,
|
|
16
|
+
type Attributed_type_nameContext,
|
|
17
|
+
type Break_statementContext,
|
|
18
|
+
type Compound_name_initializationContext,
|
|
19
|
+
type Compound_reassignmentContext,
|
|
20
|
+
type Compound_tuple_initializationContext,
|
|
21
|
+
type Conjunction_expressionContext,
|
|
22
|
+
type Continue_statementContext,
|
|
23
|
+
type Declaration_modeContext,
|
|
24
|
+
type Conditional_expressionContext,
|
|
25
|
+
type Disjunction_expressionContext,
|
|
26
|
+
type Elif_structureContext,
|
|
27
|
+
type Else_blockContext,
|
|
28
|
+
type Enum_declarationContext,
|
|
29
|
+
type Enum_definitionContext,
|
|
30
|
+
type Enum_definitionsContext,
|
|
31
|
+
type Equal_trailing_pairContext,
|
|
32
|
+
type Equality_expressionContext,
|
|
33
|
+
type For_iteratorContext,
|
|
34
|
+
type For_structureContext,
|
|
35
|
+
type For_structure_inContext,
|
|
36
|
+
type For_structure_toContext,
|
|
37
|
+
type Function_declarationContext,
|
|
38
|
+
type Greater_than_equal_trailing_pairContext,
|
|
39
|
+
type Greater_than_trailing_pairContext,
|
|
40
|
+
type Expression_statementContext,
|
|
41
|
+
type Field_definitionContext,
|
|
42
|
+
type Field_definitionsContext,
|
|
43
|
+
type If_structureContext,
|
|
44
|
+
type If_tailContext,
|
|
45
|
+
type Import_statementContext,
|
|
46
|
+
type Indented_local_blockContext,
|
|
47
|
+
type Inequality_expressionContext,
|
|
48
|
+
type Less_than_equal_trailing_pairContext,
|
|
49
|
+
type Less_than_trailing_pairContext,
|
|
50
|
+
type Inline_local_blockContext,
|
|
51
|
+
type Local_blockContext,
|
|
52
|
+
type Literal_boolContext,
|
|
53
|
+
type Literal_colorContext,
|
|
54
|
+
type Literal_expressionContext,
|
|
55
|
+
type Literal_numberContext,
|
|
56
|
+
type Literal_stringContext,
|
|
57
|
+
type Method_declarationContext,
|
|
58
|
+
type Method_parameter_definitionContext,
|
|
59
|
+
type Method_parameter_listContext,
|
|
60
|
+
type Multiplicative_expressionContext,
|
|
61
|
+
type Multiplicative_opContext,
|
|
62
|
+
type Name_loadContext,
|
|
63
|
+
type Name_storeContext,
|
|
64
|
+
type NameContext,
|
|
65
|
+
type Primary_expression_attributeContext,
|
|
66
|
+
type Primary_expression_callContext,
|
|
67
|
+
type Primary_expression_subscriptContext,
|
|
68
|
+
type Not_equal_trailing_pairContext,
|
|
69
|
+
type Parameter_definitionContext,
|
|
70
|
+
type Parameter_listContext,
|
|
71
|
+
type Simple_name_initializationContext,
|
|
72
|
+
type Simple_reassignmentContext,
|
|
73
|
+
type Simple_tuple_initializationContext,
|
|
74
|
+
type Structure_expressionContext,
|
|
75
|
+
type Structure_statementContext,
|
|
76
|
+
type Switch_casesContext,
|
|
77
|
+
type Switch_default_caseContext,
|
|
78
|
+
type Switch_pattern_caseContext,
|
|
79
|
+
type Switch_structureContext,
|
|
80
|
+
type Trailing_structure_statementsContext,
|
|
81
|
+
type Tuple_declarationContext,
|
|
82
|
+
type Tuple_expressionContext,
|
|
83
|
+
type Type_declarationContext,
|
|
84
|
+
type Type_specificationContext,
|
|
85
|
+
type Simple_statementsContext,
|
|
86
|
+
type Start_expressionContext,
|
|
87
|
+
type Start_scriptContext,
|
|
88
|
+
type Grouped_expressionContext,
|
|
89
|
+
type StatementContext,
|
|
90
|
+
type StatementsContext,
|
|
91
|
+
type Subscript_sliceContext,
|
|
92
|
+
type Unary_expressionContext,
|
|
93
|
+
type Unary_opContext,
|
|
94
|
+
type Variable_declarationContext,
|
|
95
|
+
type While_structureContext,
|
|
96
|
+
} from "../generated/PinescriptParser.ts";
|
|
97
|
+
import {
|
|
98
|
+
Add,
|
|
99
|
+
And,
|
|
100
|
+
Div,
|
|
101
|
+
Eq,
|
|
102
|
+
Gt,
|
|
103
|
+
GtE,
|
|
104
|
+
Invert,
|
|
105
|
+
Lt,
|
|
106
|
+
LtE,
|
|
107
|
+
NotEq,
|
|
108
|
+
Load,
|
|
109
|
+
Mod,
|
|
110
|
+
Mult,
|
|
111
|
+
NotOp,
|
|
112
|
+
Or,
|
|
113
|
+
Store,
|
|
114
|
+
Sub,
|
|
115
|
+
UAdd,
|
|
116
|
+
USub,
|
|
117
|
+
Var,
|
|
118
|
+
VarIp,
|
|
119
|
+
arg,
|
|
120
|
+
assign,
|
|
121
|
+
attribute,
|
|
122
|
+
binOp,
|
|
123
|
+
boolOp,
|
|
124
|
+
breakStmt,
|
|
125
|
+
call,
|
|
126
|
+
caseNode,
|
|
127
|
+
compare,
|
|
128
|
+
conditional,
|
|
129
|
+
continueStmt,
|
|
130
|
+
constant,
|
|
131
|
+
enumDef,
|
|
132
|
+
expression,
|
|
133
|
+
exprStmt,
|
|
134
|
+
forIn,
|
|
135
|
+
forTo,
|
|
136
|
+
functionDef,
|
|
137
|
+
ifExpr,
|
|
138
|
+
importStmt,
|
|
139
|
+
name,
|
|
140
|
+
param,
|
|
141
|
+
reAssign,
|
|
142
|
+
script,
|
|
143
|
+
subscript,
|
|
144
|
+
switchExpr,
|
|
145
|
+
tupleExpr,
|
|
146
|
+
typeDef,
|
|
147
|
+
unaryOp,
|
|
148
|
+
whileExpr,
|
|
149
|
+
type Arg,
|
|
150
|
+
type AST,
|
|
151
|
+
type Assign,
|
|
152
|
+
type Case,
|
|
153
|
+
type compare_op,
|
|
154
|
+
type decl_mode,
|
|
155
|
+
type expr,
|
|
156
|
+
type Name,
|
|
157
|
+
type operator,
|
|
158
|
+
type Param,
|
|
159
|
+
type stmt,
|
|
160
|
+
type unary_op,
|
|
161
|
+
} from "./nodes.ts";
|
|
162
|
+
|
|
163
|
+
function loc(node: AST, ctx: ParserRuleContext): void {
|
|
164
|
+
const start = ctx.start;
|
|
165
|
+
const stop = ctx.stop ?? ctx.start;
|
|
166
|
+
if (start) {
|
|
167
|
+
node.lineno = start.line;
|
|
168
|
+
node.col_offset = start.column;
|
|
169
|
+
}
|
|
170
|
+
if (stop) {
|
|
171
|
+
node.end_lineno = stop.line;
|
|
172
|
+
const text = stop.text ?? "";
|
|
173
|
+
node.end_col_offset = stop.column + text.length;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function parseNumberLiteral(text: string): number {
|
|
178
|
+
const cleaned = text.replaceAll("_", "");
|
|
179
|
+
if (/^0[xX]/.test(cleaned)) return Number.parseInt(cleaned, 16);
|
|
180
|
+
if (/^0[bB]/.test(cleaned)) return Number.parseInt(cleaned.slice(2), 2);
|
|
181
|
+
if (/^0[oO]/.test(cleaned)) return Number.parseInt(cleaned.slice(2), 8);
|
|
182
|
+
return Number(cleaned);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function unescapeStringBody(inner: string): string {
|
|
186
|
+
let out = "";
|
|
187
|
+
for (let i = 0; i < inner.length; i++) {
|
|
188
|
+
const ch = inner[i]!;
|
|
189
|
+
if (ch !== "\\" || i + 1 >= inner.length) {
|
|
190
|
+
out += ch;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const next = inner[++i]!;
|
|
194
|
+
switch (next) {
|
|
195
|
+
case "n":
|
|
196
|
+
out += "\n";
|
|
197
|
+
break;
|
|
198
|
+
case "r":
|
|
199
|
+
out += "\r";
|
|
200
|
+
break;
|
|
201
|
+
case "t":
|
|
202
|
+
out += "\t";
|
|
203
|
+
break;
|
|
204
|
+
case "\\":
|
|
205
|
+
case "'":
|
|
206
|
+
case '"':
|
|
207
|
+
out += next;
|
|
208
|
+
break;
|
|
209
|
+
default:
|
|
210
|
+
out += next;
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function parseStringLiteral(text: string): string {
|
|
218
|
+
if (
|
|
219
|
+
(text.startsWith('"""') && text.endsWith('"""')) ||
|
|
220
|
+
(text.startsWith("'''") && text.endsWith("'''"))
|
|
221
|
+
) {
|
|
222
|
+
return text.slice(3, -3);
|
|
223
|
+
}
|
|
224
|
+
if (text.length >= 2) {
|
|
225
|
+
const q = text[0]!;
|
|
226
|
+
if ((q === '"' || q === "'") && text.endsWith(q)) {
|
|
227
|
+
return unescapeStringBody(text.slice(1, -1));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return text;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function unwrap(value: unknown): unknown {
|
|
234
|
+
while (Array.isArray(value) && value.length === 1) value = value[0];
|
|
235
|
+
if (Array.isArray(value)) return value.map(unwrap);
|
|
236
|
+
return value;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** antlr4-js `getToken` may return null or a hollow object; require a real symbol. */
|
|
240
|
+
function hasTerminal(tok: unknown): boolean {
|
|
241
|
+
if (tok == null || typeof tok !== "object") return false;
|
|
242
|
+
if (!("symbol" in tok)) return false;
|
|
243
|
+
return (tok as { symbol?: unknown }).symbol != null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function isRuleCtx(value: unknown): value is ParserRuleContext {
|
|
247
|
+
return (
|
|
248
|
+
value != null &&
|
|
249
|
+
typeof value === "object" &&
|
|
250
|
+
"ruleIndex" in value &&
|
|
251
|
+
typeof (value as { ruleIndex?: unknown }).ruleIndex === "number"
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function setStoreCtx(node: expr): expr {
|
|
256
|
+
if (node.kind === "Name" || node.kind === "Attribute" || node.kind === "Subscript") {
|
|
257
|
+
node.ctx = Store;
|
|
258
|
+
}
|
|
259
|
+
return node;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export class PinescriptASTBuilder extends PinescriptParserVisitor<unknown> {
|
|
263
|
+
/**
|
|
264
|
+
* antlr4-js default `visitChildren` includes terminals and wraps every
|
|
265
|
+
* child. Skip terminals, unwrap 1-element arrays per child, but do not
|
|
266
|
+
* flatten `visit()` globally (argument lists must stay arrays).
|
|
267
|
+
*/
|
|
268
|
+
override visitChildren(node: RuleNode): unknown {
|
|
269
|
+
const children = (node as ParserRuleContext).children ?? [];
|
|
270
|
+
const results: unknown[] = [];
|
|
271
|
+
for (const child of children) {
|
|
272
|
+
if (!isRuleCtx(child)) continue;
|
|
273
|
+
const accept = (child as { accept?: (v: unknown) => unknown }).accept;
|
|
274
|
+
if (typeof accept !== "function") continue;
|
|
275
|
+
const r = unwrap(accept.call(child, this));
|
|
276
|
+
if (r !== undefined && r !== null) results.push(r);
|
|
277
|
+
}
|
|
278
|
+
if (results.length === 0) return undefined;
|
|
279
|
+
if (results.length === 1) return results[0];
|
|
280
|
+
return results;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
visitStart_script = (ctx: Start_scriptContext): unknown => {
|
|
284
|
+
const stmts = ctx.statements();
|
|
285
|
+
const body = stmts ? (this.visit(stmts) as stmt[]) : [];
|
|
286
|
+
return script(body);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
visitStart_expression = (ctx: Start_expressionContext): unknown => {
|
|
290
|
+
return expression(this.visit(ctx.expression()) as expr);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
visitStatements = (ctx: StatementsContext): unknown => {
|
|
294
|
+
const out: stmt[] = [];
|
|
295
|
+
for (const stmtCtx of ctx.statement_list()) {
|
|
296
|
+
const visited = unwrap(this.visit(stmtCtx)) as stmt[] | stmt | undefined;
|
|
297
|
+
if (Array.isArray(visited)) out.push(...(visited as stmt[]));
|
|
298
|
+
else if (visited) out.push(visited);
|
|
299
|
+
}
|
|
300
|
+
return out;
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
visitStatement = (ctx: StatementContext): unknown => {
|
|
304
|
+
const comp = ctx.compound_statement();
|
|
305
|
+
const simp = ctx.simple_statements();
|
|
306
|
+
const trail = ctx.trailing_structure_statements();
|
|
307
|
+
if (comp) return [this.visit(comp)];
|
|
308
|
+
if (simp) return this.visit(simp);
|
|
309
|
+
if (trail) return this.visit(trail);
|
|
310
|
+
return [];
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
visitSimple_statements = (ctx: Simple_statementsContext): unknown => {
|
|
314
|
+
return ctx.simple_statement_list().map((s) => this.visit(s));
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
visitExpression_statement = (ctx: Expression_statementContext): unknown => {
|
|
318
|
+
const node = exprStmt(this.visit(ctx.expression()) as expr);
|
|
319
|
+
loc(node, ctx);
|
|
320
|
+
return node;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
visitConditional_expression = (ctx: Conditional_expressionContext): unknown => {
|
|
324
|
+
const test = this.visit(ctx.disjunction_expression()) as expr;
|
|
325
|
+
if (hasTerminal(ctx.QUESTION())) {
|
|
326
|
+
const body = this.visit(ctx.expression(0)) as expr;
|
|
327
|
+
const orelse = this.visit(ctx.expression(1)) as expr;
|
|
328
|
+
const node = conditional(test, body, orelse);
|
|
329
|
+
loc(node, ctx);
|
|
330
|
+
return node;
|
|
331
|
+
}
|
|
332
|
+
return test;
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
visitDisjunction_expression = (ctx: Disjunction_expressionContext): unknown => {
|
|
336
|
+
const exprs = ctx.conjunction_expression_list() ?? [];
|
|
337
|
+
if (exprs.length > 1) {
|
|
338
|
+
const values = exprs.map((e) => this.visit(e) as expr);
|
|
339
|
+
const node = boolOp(Or, values);
|
|
340
|
+
loc(node, ctx);
|
|
341
|
+
return node;
|
|
342
|
+
}
|
|
343
|
+
return this.visit(exprs[0]);
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
visitConjunction_expression = (ctx: Conjunction_expressionContext): unknown => {
|
|
347
|
+
const exprs = ctx.bitwise_or_expression_list() ?? [];
|
|
348
|
+
if (exprs.length > 1) {
|
|
349
|
+
const values = exprs.map((e) => this.visit(e) as expr);
|
|
350
|
+
const node = boolOp(And, values);
|
|
351
|
+
loc(node, ctx);
|
|
352
|
+
return node;
|
|
353
|
+
}
|
|
354
|
+
return this.visit(exprs[0]);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
visitAdditive_expression = (ctx: Additive_expressionContext): unknown => {
|
|
358
|
+
if (ctx.additive_op()) {
|
|
359
|
+
const node = binOp(
|
|
360
|
+
this.visit(ctx.additive_expression()) as expr,
|
|
361
|
+
this.visit(ctx.additive_op()) as operator,
|
|
362
|
+
this.visit(ctx.multiplicative_expression()) as expr,
|
|
363
|
+
);
|
|
364
|
+
loc(node, ctx);
|
|
365
|
+
return node;
|
|
366
|
+
}
|
|
367
|
+
return this.visit(ctx.multiplicative_expression());
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
visitAdditive_op = (ctx: Additive_opContext): unknown => {
|
|
371
|
+
if (ctx.PLUS()) return Add;
|
|
372
|
+
if (ctx.MINUS()) return Sub;
|
|
373
|
+
return Add;
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
visitMultiplicative_expression = (ctx: Multiplicative_expressionContext): unknown => {
|
|
377
|
+
if (ctx.multiplicative_op()) {
|
|
378
|
+
const node = binOp(
|
|
379
|
+
this.visit(ctx.multiplicative_expression()) as expr,
|
|
380
|
+
this.visit(ctx.multiplicative_op()) as operator,
|
|
381
|
+
this.visit(ctx.unary_expression()) as expr,
|
|
382
|
+
);
|
|
383
|
+
loc(node, ctx);
|
|
384
|
+
return node;
|
|
385
|
+
}
|
|
386
|
+
return this.visit(ctx.unary_expression());
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
visitMultiplicative_op = (ctx: Multiplicative_opContext): unknown => {
|
|
390
|
+
if (ctx.STAR()) return Mult;
|
|
391
|
+
if (ctx.SLASH()) return Div;
|
|
392
|
+
if (ctx.PERCENT()) return Mod;
|
|
393
|
+
return Mult;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
visitUnary_expression = (ctx: Unary_expressionContext): unknown => {
|
|
397
|
+
if (ctx.unary_op()) {
|
|
398
|
+
const node = unaryOp(
|
|
399
|
+
this.visit(ctx.unary_op()) as unary_op,
|
|
400
|
+
this.visit(ctx.unary_expression()) as expr,
|
|
401
|
+
);
|
|
402
|
+
loc(node, ctx);
|
|
403
|
+
return node;
|
|
404
|
+
}
|
|
405
|
+
return this.visit(ctx.primary_expression());
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
visitUnary_op = (ctx: Unary_opContext): unknown => {
|
|
409
|
+
if (ctx.NOT()) return NotOp;
|
|
410
|
+
if (ctx.PLUS()) return UAdd;
|
|
411
|
+
if (ctx.MINUS()) return USub;
|
|
412
|
+
if (ctx.TILDE()) return Invert;
|
|
413
|
+
return UAdd;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
visitPrimary_expression_call = (ctx: Primary_expression_callContext): unknown => {
|
|
417
|
+
const func = this.visit(ctx.primary_expression()) as expr;
|
|
418
|
+
const argsCtx = ctx.argument_list();
|
|
419
|
+
const args = isRuleCtx(argsCtx) ? asArgList(this.visit(argsCtx)) : [];
|
|
420
|
+
const node = call(func, args);
|
|
421
|
+
loc(node, ctx);
|
|
422
|
+
return node;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
visitPrimary_expression_attribute = (
|
|
426
|
+
ctx: Primary_expression_attributeContext,
|
|
427
|
+
): unknown => {
|
|
428
|
+
const value = this.visit(ctx.primary_expression()) as expr;
|
|
429
|
+
const n = this.visit(ctx.name_load()) as ReturnType<typeof name>;
|
|
430
|
+
const node = attribute(value, n.id, Load);
|
|
431
|
+
loc(node, ctx);
|
|
432
|
+
return node;
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
visitPrimary_expression_subscript = (
|
|
436
|
+
ctx: Primary_expression_subscriptContext,
|
|
437
|
+
): unknown => {
|
|
438
|
+
const value = this.visit(ctx.primary_expression()) as expr;
|
|
439
|
+
const items = this.visit(ctx.subscript_slice()) as expr;
|
|
440
|
+
const node = subscript(value, items, Load);
|
|
441
|
+
loc(node, ctx);
|
|
442
|
+
return node;
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
visitArgument_list = (ctx: Argument_listContext): unknown => {
|
|
446
|
+
return ctx.argument_definition_list().map((a) => this.visit(a));
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
visitArgument_definition = (ctx: Argument_definitionContext): unknown => {
|
|
450
|
+
const store = ctx.name_store();
|
|
451
|
+
let nameId: string | null = null;
|
|
452
|
+
// Grammar: `(name_store EQUAL)? expression`. antlr4-js `name_store()`
|
|
453
|
+
// can return a hollow object — require a real rule ctx + EQUAL.
|
|
454
|
+
if (isRuleCtx(store) && hasTerminal(ctx.EQUAL())) {
|
|
455
|
+
const visited = this.visit(store);
|
|
456
|
+
if (typeof visited === "string") nameId = visited;
|
|
457
|
+
else if (isName(visited)) nameId = visited.id;
|
|
458
|
+
else {
|
|
459
|
+
const text = store.getText();
|
|
460
|
+
nameId = text.length > 0 ? text : null;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
const node = arg(this.visit(ctx.expression()) as expr, nameId);
|
|
464
|
+
loc(node, ctx);
|
|
465
|
+
return node;
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
visitSubscript_slice = (ctx: Subscript_sliceContext): unknown => {
|
|
469
|
+
const items = ctx.expression_list().map((e) => this.visit(e) as expr);
|
|
470
|
+
if (items.length <= 1) return items[0];
|
|
471
|
+
const node = tupleExpr(items, Load);
|
|
472
|
+
loc(node, ctx);
|
|
473
|
+
return node;
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
visitLiteral_expression = (ctx: Literal_expressionContext): unknown => {
|
|
477
|
+
const child = ctx.getChild(0);
|
|
478
|
+
const value = this.visit(child);
|
|
479
|
+
const node = constant(value);
|
|
480
|
+
loc(node, ctx);
|
|
481
|
+
if (isRuleCtx(ctx.literal_color())) node.kind_lit = "#";
|
|
482
|
+
return node;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
visitLiteral_number = (ctx: Literal_numberContext): unknown => {
|
|
486
|
+
return parseNumberLiteral(ctx.getText());
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
visitLiteral_string = (ctx: Literal_stringContext): unknown => {
|
|
490
|
+
return parseStringLiteral(ctx.getText());
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
visitLiteral_bool = (ctx: Literal_boolContext): unknown => {
|
|
494
|
+
if (ctx.TRUE()) return true;
|
|
495
|
+
if (ctx.FALSE()) return false;
|
|
496
|
+
return false;
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
visitLiteral_color = (ctx: Literal_colorContext): unknown => {
|
|
500
|
+
return ctx.getText();
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
visitName = (ctx: NameContext): unknown => {
|
|
504
|
+
return ctx.getText();
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
visitName_load = (ctx: Name_loadContext): unknown => {
|
|
508
|
+
const node = name(ctx.name().getText(), Load);
|
|
509
|
+
loc(node, ctx);
|
|
510
|
+
return node;
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
visitName_store = (ctx: Name_storeContext): unknown => {
|
|
514
|
+
const node = name(ctx.name().getText(), Store);
|
|
515
|
+
loc(node, ctx);
|
|
516
|
+
return node;
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
visitGrouped_expression = (ctx: Grouped_expressionContext): unknown => {
|
|
520
|
+
return this.visit(ctx.expression());
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
visitTuple_expression = (ctx: Tuple_expressionContext): unknown => {
|
|
524
|
+
const elts = (ctx.expression_list() ?? []).map((e) => this.visit(e) as expr);
|
|
525
|
+
const node = tupleExpr(elts, Load);
|
|
526
|
+
loc(node, ctx);
|
|
527
|
+
return node;
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
visitType_specification = (ctx: Type_specificationContext): unknown => {
|
|
531
|
+
let typeSpec = this.visit(ctx.attributed_type_name()) as expr;
|
|
532
|
+
if (isRuleCtx(ctx.array_type_suffix())) {
|
|
533
|
+
const node = subscript(typeSpec, null, Load);
|
|
534
|
+
loc(node, ctx);
|
|
535
|
+
node.lineno = typeSpec.lineno;
|
|
536
|
+
node.col_offset = typeSpec.col_offset;
|
|
537
|
+
typeSpec = node;
|
|
538
|
+
}
|
|
539
|
+
return typeSpec;
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
visitAttributed_type_name = (ctx: Attributed_type_nameContext): unknown => {
|
|
543
|
+
const names = (ctx.name_load_list() ?? []).map((n) => this.visit(n) as Name);
|
|
544
|
+
if (names.length === 0) return undefined;
|
|
545
|
+
let ident: expr = names[0]!;
|
|
546
|
+
for (let i = 1; i < names.length; i++) {
|
|
547
|
+
const part = names[i]!;
|
|
548
|
+
const node = attribute(ident, part.id, Load);
|
|
549
|
+
node.lineno = ident.lineno;
|
|
550
|
+
node.col_offset = ident.col_offset;
|
|
551
|
+
node.end_lineno = part.end_lineno ?? null;
|
|
552
|
+
node.end_col_offset = part.end_col_offset ?? null;
|
|
553
|
+
ident = node;
|
|
554
|
+
}
|
|
555
|
+
return ident;
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
visitSimple_name_initialization = (ctx: Simple_name_initializationContext): unknown => {
|
|
559
|
+
const node = this.visit(ctx.variable_declaration()) as Assign;
|
|
560
|
+
node.value = this.visit(ctx.expression()) as expr;
|
|
561
|
+
if (hasTerminal(ctx.EXPORT())) node.export = 1;
|
|
562
|
+
loc(node, ctx);
|
|
563
|
+
return node;
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
visitCompound_name_initialization = (ctx: Compound_name_initializationContext): unknown => {
|
|
567
|
+
const node = this.visit(ctx.variable_declaration()) as Assign;
|
|
568
|
+
const valueCtx = ctx.structure_expression();
|
|
569
|
+
if (isRuleCtx(valueCtx)) node.value = this.visit(valueCtx) as expr;
|
|
570
|
+
if (hasTerminal(ctx.EXPORT())) node.export = 1;
|
|
571
|
+
loc(node, ctx);
|
|
572
|
+
return node;
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
visitCompound_tuple_initialization = (ctx: Compound_tuple_initializationContext): unknown => {
|
|
576
|
+
const target = this.visit(ctx.tuple_declaration()) as expr;
|
|
577
|
+
const value = this.visit(ctx.structure_expression()) as expr;
|
|
578
|
+
const node = assign(target, value);
|
|
579
|
+
loc(node, ctx);
|
|
580
|
+
return node;
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
visitCompound_reassignment = (ctx: Compound_reassignmentContext): unknown => {
|
|
584
|
+
const target = setStoreCtx(this.visit(ctx.primary_expression()) as expr);
|
|
585
|
+
const value = this.visit(ctx.structure_expression()) as expr;
|
|
586
|
+
const node = reAssign(target, value);
|
|
587
|
+
loc(node, ctx);
|
|
588
|
+
return node;
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
visitStructure_expression = (ctx: Structure_expressionContext): unknown => {
|
|
592
|
+
return this.visit(ctx.structure());
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
visitTrailing_structure_statements = (ctx: Trailing_structure_statementsContext): unknown => {
|
|
596
|
+
const stmts: stmt[] = [];
|
|
597
|
+
for (const s of ctx.simple_statement_list() ?? []) {
|
|
598
|
+
const visited = unwrap(this.visit(s));
|
|
599
|
+
if (Array.isArray(visited)) stmts.push(...(visited as stmt[]));
|
|
600
|
+
else if (visited) stmts.push(visited as stmt);
|
|
601
|
+
}
|
|
602
|
+
const structure = this.visit(ctx.structure()) as expr;
|
|
603
|
+
const wrapped = exprStmt(structure);
|
|
604
|
+
const structCtx = ctx.structure();
|
|
605
|
+
if (isRuleCtx(structCtx)) loc(wrapped, structCtx);
|
|
606
|
+
else loc(wrapped, ctx);
|
|
607
|
+
stmts.push(wrapped);
|
|
608
|
+
return stmts;
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
visitSimple_tuple_initialization = (ctx: Simple_tuple_initializationContext): unknown => {
|
|
612
|
+
const target = this.visit(ctx.tuple_declaration()) as expr;
|
|
613
|
+
const value = this.visit(ctx.expression()) as expr;
|
|
614
|
+
const node = assign(target, value);
|
|
615
|
+
loc(node, ctx);
|
|
616
|
+
return node;
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
visitSimple_reassignment = (ctx: Simple_reassignmentContext): unknown => {
|
|
620
|
+
const target = setStoreCtx(this.visit(ctx.primary_expression()) as expr);
|
|
621
|
+
const value = this.visit(ctx.expression()) as expr;
|
|
622
|
+
const node = reAssign(target, value);
|
|
623
|
+
loc(node, ctx);
|
|
624
|
+
return node;
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
visitVariable_declaration = (ctx: Variable_declarationContext): unknown => {
|
|
628
|
+
const target = this.visit(ctx.name_store()) as expr;
|
|
629
|
+
const typeCtx = ctx.type_specification();
|
|
630
|
+
const modeCtx = ctx.declaration_mode();
|
|
631
|
+
const typeSpec = isRuleCtx(typeCtx) ? ((this.visit(typeCtx) as expr | undefined) ?? null) : null;
|
|
632
|
+
const mode = isRuleCtx(modeCtx) ? ((this.visit(modeCtx) as decl_mode | undefined) ?? null) : null;
|
|
633
|
+
const node = assign(target, null, typeSpec, mode);
|
|
634
|
+
loc(node, ctx);
|
|
635
|
+
return node;
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
visitTuple_declaration = (ctx: Tuple_declarationContext): unknown => {
|
|
639
|
+
const elts = ctx.name_store_list().map((n) => this.visit(n) as expr);
|
|
640
|
+
const node = tupleExpr(elts, Store);
|
|
641
|
+
loc(node, ctx);
|
|
642
|
+
return node;
|
|
643
|
+
};
|
|
644
|
+
|
|
645
|
+
visitDeclaration_mode = (ctx: Declaration_modeContext): unknown => {
|
|
646
|
+
if (hasTerminal(ctx.VARIP())) return VarIp;
|
|
647
|
+
if (hasTerminal(ctx.VAR())) return Var;
|
|
648
|
+
return undefined;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
visitFunction_declaration = (ctx: Function_declarationContext): unknown => {
|
|
652
|
+
const fname = this.visit(ctx.name()) as string;
|
|
653
|
+
const argsCtx = ctx.parameter_list();
|
|
654
|
+
const args = isRuleCtx(argsCtx) ? asParamList(this.visit(argsCtx)) : [];
|
|
655
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
656
|
+
const exported = hasTerminal(ctx.EXPORT()) ? 1 : 0;
|
|
657
|
+
const node = functionDef(fname, args, body, 0, exported);
|
|
658
|
+
loc(node, ctx);
|
|
659
|
+
return node;
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
visitParameter_list = (ctx: Parameter_listContext): unknown => {
|
|
663
|
+
return ctx.parameter_definition_list().map((p) => this.visit(p));
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
visitParameter_definition = (ctx: Parameter_definitionContext): unknown => {
|
|
667
|
+
const nameNode = this.visit(ctx.name_store()) as ReturnType<typeof name>;
|
|
668
|
+
const defaultCtx = ctx.expression();
|
|
669
|
+
const typeCtx = ctx.type_specification();
|
|
670
|
+
const defaultValue = isRuleCtx(defaultCtx)
|
|
671
|
+
? ((this.visit(defaultCtx) as expr | undefined) ?? null)
|
|
672
|
+
: null;
|
|
673
|
+
const typeSpec = isRuleCtx(typeCtx) ? ((this.visit(typeCtx) as expr | undefined) ?? null) : null;
|
|
674
|
+
const node = param(nameNode.id, defaultValue, typeSpec);
|
|
675
|
+
loc(node, ctx);
|
|
676
|
+
return node;
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
visitMethod_declaration = (ctx: Method_declarationContext): unknown => {
|
|
680
|
+
const fname = this.visit(ctx.name()) as string;
|
|
681
|
+
const argsCtx = ctx.method_parameter_list();
|
|
682
|
+
const args = isRuleCtx(argsCtx) ? asParamList(this.visit(argsCtx)) : [];
|
|
683
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
684
|
+
const exported = hasTerminal(ctx.EXPORT()) ? 1 : 0;
|
|
685
|
+
const node = functionDef(fname, args, body, 1, exported);
|
|
686
|
+
loc(node, ctx);
|
|
687
|
+
return node;
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
visitMethod_parameter_list = (ctx: Method_parameter_listContext): unknown => {
|
|
691
|
+
return ctx.method_parameter_definition_list().map((p) => this.visit(p));
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
visitMethod_parameter_definition = (ctx: Method_parameter_definitionContext): unknown => {
|
|
695
|
+
const typeCtx = ctx.type_specification();
|
|
696
|
+
const nameCtx = ctx.name_store();
|
|
697
|
+
if (isRuleCtx(typeCtx) && isRuleCtx(nameCtx)) {
|
|
698
|
+
const typeSpec = (this.visit(typeCtx) as expr | undefined) ?? null;
|
|
699
|
+
const nameNode = this.visit(nameCtx) as ReturnType<typeof name>;
|
|
700
|
+
const node = param(nameNode.id, null, typeSpec);
|
|
701
|
+
loc(node, ctx);
|
|
702
|
+
return node;
|
|
703
|
+
}
|
|
704
|
+
return this.visit(ctx.parameter_definition());
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
visitType_declaration = (ctx: Type_declarationContext): unknown => {
|
|
708
|
+
const tname = this.visit(ctx.name()) as string;
|
|
709
|
+
const body = asStmtList(this.visit(ctx.field_definitions()));
|
|
710
|
+
const exported = hasTerminal(ctx.EXPORT()) ? 1 : 0;
|
|
711
|
+
const node = typeDef(tname, body, exported);
|
|
712
|
+
loc(node, ctx);
|
|
713
|
+
return node;
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
visitEnum_declaration = (ctx: Enum_declarationContext): unknown => {
|
|
717
|
+
const ename = this.visit(ctx.name()) as string;
|
|
718
|
+
const body = asStmtList(this.visit(ctx.enum_definitions()));
|
|
719
|
+
const exported = hasTerminal(ctx.EXPORT()) ? 1 : 0;
|
|
720
|
+
const node = enumDef(ename, body, exported);
|
|
721
|
+
loc(node, ctx);
|
|
722
|
+
return node;
|
|
723
|
+
};
|
|
724
|
+
|
|
725
|
+
visitField_definitions = (ctx: Field_definitionsContext): unknown => {
|
|
726
|
+
return ctx.field_definition_list().map((d) => this.visit(d));
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
visitField_definition = (ctx: Field_definitionContext): unknown => {
|
|
730
|
+
const target = this.visit(ctx.name_store()) as expr;
|
|
731
|
+
const valueCtx = ctx.expression();
|
|
732
|
+
const typeCtx = ctx.type_specification();
|
|
733
|
+
const value = isRuleCtx(valueCtx) ? ((this.visit(valueCtx) as expr | undefined) ?? null) : null;
|
|
734
|
+
const typeSpec = isRuleCtx(typeCtx) ? ((this.visit(typeCtx) as expr | undefined) ?? null) : null;
|
|
735
|
+
const mode = hasTerminal(ctx.VARIP()) ? VarIp : null;
|
|
736
|
+
const node = assign(target, value, typeSpec, mode);
|
|
737
|
+
loc(node, ctx);
|
|
738
|
+
return node;
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
visitEnum_definitions = (ctx: Enum_definitionsContext): unknown => {
|
|
742
|
+
return ctx.enum_definition_list().map((d) => this.visit(d));
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
visitEnum_definition = (ctx: Enum_definitionContext): unknown => {
|
|
746
|
+
const target = this.visit(ctx.name_store()) as expr;
|
|
747
|
+
const valueCtx = ctx.expression();
|
|
748
|
+
const value = isRuleCtx(valueCtx) ? ((this.visit(valueCtx) as expr | undefined) ?? null) : null;
|
|
749
|
+
const node = assign(target, value);
|
|
750
|
+
loc(node, ctx);
|
|
751
|
+
return node;
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
visitStructure_statement = (ctx: Structure_statementContext): unknown => {
|
|
755
|
+
const node = exprStmt(this.visit(ctx.structure()) as expr);
|
|
756
|
+
loc(node, ctx);
|
|
757
|
+
return node;
|
|
758
|
+
};
|
|
759
|
+
|
|
760
|
+
visitIf_structure = (ctx: If_structureContext): unknown => {
|
|
761
|
+
const test = this.visit(ctx.expression()) as expr;
|
|
762
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
763
|
+
const tail = ctx.if_tail();
|
|
764
|
+
const orelse = isRuleCtx(tail) ? asStmtList(this.visit(tail)) : [];
|
|
765
|
+
const node = ifExpr(test, body, orelse);
|
|
766
|
+
loc(node, ctx);
|
|
767
|
+
return node;
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
visitFor_structure = (ctx: For_structureContext): unknown => {
|
|
771
|
+
const to = ctx.for_structure_to();
|
|
772
|
+
if (isRuleCtx(to)) return this.visit(to);
|
|
773
|
+
const inn = ctx.for_structure_in();
|
|
774
|
+
if (isRuleCtx(inn)) return this.visit(inn);
|
|
775
|
+
return this.visitChildren(ctx);
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
visitFor_iterator = (ctx: For_iteratorContext): unknown => {
|
|
779
|
+
const tup = ctx.tuple_declaration();
|
|
780
|
+
if (isRuleCtx(tup)) return this.visit(tup);
|
|
781
|
+
return this.visit(ctx.name_store());
|
|
782
|
+
};
|
|
783
|
+
|
|
784
|
+
visitFor_structure_to = (ctx: For_structure_toContext): unknown => {
|
|
785
|
+
const target = this.visit(ctx.for_iterator()) as expr;
|
|
786
|
+
const start = this.visit(ctx.expression(0)) as expr;
|
|
787
|
+
const end = this.visit(ctx.expression(1)) as expr;
|
|
788
|
+
const stepCtx = ctx.expression(2);
|
|
789
|
+
const step = isRuleCtx(stepCtx) ? ((this.visit(stepCtx) as expr | undefined) ?? null) : null;
|
|
790
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
791
|
+
const node = forTo(target, start, end, body, step);
|
|
792
|
+
loc(node, ctx);
|
|
793
|
+
return node;
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
visitFor_structure_in = (ctx: For_structure_inContext): unknown => {
|
|
797
|
+
const target = this.visit(ctx.for_iterator()) as expr;
|
|
798
|
+
const iterable = this.visit(ctx.expression()) as expr;
|
|
799
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
800
|
+
const node = forIn(target, iterable, body);
|
|
801
|
+
loc(node, ctx);
|
|
802
|
+
return node;
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
visitWhile_structure = (ctx: While_structureContext): unknown => {
|
|
806
|
+
const test = this.visit(ctx.expression()) as expr;
|
|
807
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
808
|
+
const node = whileExpr(test, body);
|
|
809
|
+
loc(node, ctx);
|
|
810
|
+
return node;
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
visitSwitch_structure = (ctx: Switch_structureContext): unknown => {
|
|
814
|
+
const cases = asCaseList(this.visit(ctx.switch_cases()));
|
|
815
|
+
const subjectCtx = ctx.expression();
|
|
816
|
+
const subject = isRuleCtx(subjectCtx)
|
|
817
|
+
? ((this.visit(subjectCtx) as expr | undefined) ?? null)
|
|
818
|
+
: null;
|
|
819
|
+
const node = switchExpr(cases, subject);
|
|
820
|
+
loc(node, ctx);
|
|
821
|
+
return node;
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
visitSwitch_cases = (ctx: Switch_casesContext): unknown => {
|
|
825
|
+
const cases: unknown[] = (ctx.switch_pattern_case_list() ?? []).map((c) => this.visit(c));
|
|
826
|
+
const defaultCase = ctx.switch_default_case();
|
|
827
|
+
if (isRuleCtx(defaultCase)) cases.push(this.visit(defaultCase));
|
|
828
|
+
return cases;
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
visitSwitch_pattern_case = (ctx: Switch_pattern_caseContext): unknown => {
|
|
832
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
833
|
+
const pattern = this.visit(ctx.expression()) as expr;
|
|
834
|
+
const node = caseNode(body, pattern);
|
|
835
|
+
loc(node, ctx);
|
|
836
|
+
return node;
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
visitSwitch_default_case = (ctx: Switch_default_caseContext): unknown => {
|
|
840
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
841
|
+
const node = caseNode(body, null);
|
|
842
|
+
loc(node, ctx);
|
|
843
|
+
return node;
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
visitElif_structure = (ctx: Elif_structureContext): unknown => {
|
|
847
|
+
const test = this.visit(ctx.expression()) as expr;
|
|
848
|
+
const body = asStmtList(this.visit(ctx.local_block()));
|
|
849
|
+
const tail = ctx.if_tail();
|
|
850
|
+
const orelse = isRuleCtx(tail) ? asStmtList(this.visit(tail)) : [];
|
|
851
|
+
const inner = ifExpr(test, body, orelse);
|
|
852
|
+
loc(inner, ctx);
|
|
853
|
+
const wrapped = exprStmt(inner);
|
|
854
|
+
loc(wrapped, ctx);
|
|
855
|
+
return [wrapped];
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
visitIf_tail = (ctx: If_tailContext): unknown => {
|
|
859
|
+
const elif = ctx.elif_structure();
|
|
860
|
+
if (isRuleCtx(elif)) return this.visit(elif);
|
|
861
|
+
const els = ctx.else_block();
|
|
862
|
+
if (isRuleCtx(els)) return this.visit(els);
|
|
863
|
+
return [];
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
visitElse_block = (ctx: Else_blockContext): unknown => {
|
|
867
|
+
return this.visit(ctx.local_block());
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
visitLocal_block = (ctx: Local_blockContext): unknown => {
|
|
871
|
+
const indented = ctx.indented_local_block();
|
|
872
|
+
if (isRuleCtx(indented)) return this.visit(indented);
|
|
873
|
+
const inline = ctx.inline_local_block();
|
|
874
|
+
if (isRuleCtx(inline)) return this.visit(inline);
|
|
875
|
+
return [];
|
|
876
|
+
};
|
|
877
|
+
|
|
878
|
+
visitIndented_local_block = (ctx: Indented_local_blockContext): unknown => {
|
|
879
|
+
return this.visit(ctx.statements());
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
visitInline_local_block = (ctx: Inline_local_blockContext): unknown => {
|
|
883
|
+
return asStmtList(this.visit(ctx.statement()));
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
visitEquality_expression = (ctx: Equality_expressionContext): unknown => {
|
|
887
|
+
const left = this.visit(ctx.inequality_expression()) as expr;
|
|
888
|
+
const pairs = ctx.equality_trailing_pair_list() ?? [];
|
|
889
|
+
if (pairs.length === 0) return left;
|
|
890
|
+
const ops: compare_op[] = [];
|
|
891
|
+
const comparators: expr[] = [];
|
|
892
|
+
for (const p of pairs) {
|
|
893
|
+
const pair = this.visit(p) as [compare_op, expr];
|
|
894
|
+
ops.push(pair[0]);
|
|
895
|
+
comparators.push(pair[1]);
|
|
896
|
+
}
|
|
897
|
+
const node = compare(left, ops, comparators);
|
|
898
|
+
loc(node, ctx);
|
|
899
|
+
return node;
|
|
900
|
+
};
|
|
901
|
+
|
|
902
|
+
visitEqual_trailing_pair = (ctx: Equal_trailing_pairContext): unknown => {
|
|
903
|
+
return [Eq, this.visit(ctx.inequality_expression())];
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
visitNot_equal_trailing_pair = (ctx: Not_equal_trailing_pairContext): unknown => {
|
|
907
|
+
return [NotEq, this.visit(ctx.inequality_expression())];
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
visitInequality_expression = (ctx: Inequality_expressionContext): unknown => {
|
|
911
|
+
const left = this.visit(ctx.shift_expression()) as expr;
|
|
912
|
+
const pairs = ctx.inequality_trailing_pair_list() ?? [];
|
|
913
|
+
if (pairs.length === 0) return left;
|
|
914
|
+
const ops: compare_op[] = [];
|
|
915
|
+
const comparators: expr[] = [];
|
|
916
|
+
for (const p of pairs) {
|
|
917
|
+
const pair = unwrap(this.visit(p)) as [compare_op, expr];
|
|
918
|
+
ops.push(pair[0]);
|
|
919
|
+
comparators.push(pair[1]);
|
|
920
|
+
}
|
|
921
|
+
const node = compare(left, ops, comparators);
|
|
922
|
+
loc(node, ctx);
|
|
923
|
+
return node;
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
visitLess_than_equal_trailing_pair = (ctx: Less_than_equal_trailing_pairContext): unknown => {
|
|
927
|
+
return [LtE, this.visit(ctx.shift_expression())];
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
visitLess_than_trailing_pair = (ctx: Less_than_trailing_pairContext): unknown => {
|
|
931
|
+
return [Lt, this.visit(ctx.shift_expression())];
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
visitGreater_than_equal_trailing_pair = (ctx: Greater_than_equal_trailing_pairContext): unknown => {
|
|
935
|
+
return [GtE, this.visit(ctx.shift_expression())];
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
visitGreater_than_trailing_pair = (ctx: Greater_than_trailing_pairContext): unknown => {
|
|
939
|
+
return [Gt, this.visit(ctx.shift_expression())];
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
visitBreak_statement = (ctx: Break_statementContext): unknown => {
|
|
943
|
+
const node = breakStmt();
|
|
944
|
+
loc(node, ctx);
|
|
945
|
+
return node;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
visitContinue_statement = (ctx: Continue_statementContext): unknown => {
|
|
949
|
+
const node = continueStmt();
|
|
950
|
+
loc(node, ctx);
|
|
951
|
+
return node;
|
|
952
|
+
};
|
|
953
|
+
|
|
954
|
+
visitImport_statement = (ctx: Import_statementContext): unknown => {
|
|
955
|
+
const namespace = String(this.visit(ctx.name(0)) ?? "");
|
|
956
|
+
const libName = String(this.visit(ctx.name(1)) ?? "");
|
|
957
|
+
const versionRaw = this.visit(ctx.literal_number());
|
|
958
|
+
const version = typeof versionRaw === "number" && Number.isFinite(versionRaw) ? Math.trunc(versionRaw) : 1;
|
|
959
|
+
const aliasCtx = ctx.AS() ? ctx.name(2) : undefined;
|
|
960
|
+
const alias = aliasCtx ? String(this.visit(aliasCtx) ?? "") : null;
|
|
961
|
+
const node = importStmt(namespace, libName, version, alias || null);
|
|
962
|
+
loc(node, ctx);
|
|
963
|
+
return node;
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
function asStmtList(value: unknown): stmt[] {
|
|
968
|
+
const u = unwrap(value);
|
|
969
|
+
if (u == null) return [];
|
|
970
|
+
if (Array.isArray(u)) return u.filter(Boolean) as stmt[];
|
|
971
|
+
return [u as stmt];
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function asParamList(value: unknown): Param[] {
|
|
975
|
+
const u = unwrap(value);
|
|
976
|
+
if (u == null) return [];
|
|
977
|
+
if (Array.isArray(u)) return u.filter(Boolean) as Param[];
|
|
978
|
+
return [u as Param];
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function asArgList(value: unknown): Arg[] {
|
|
982
|
+
const u = unwrap(value);
|
|
983
|
+
if (u == null) return [];
|
|
984
|
+
if (Array.isArray(u)) return u.filter(Boolean) as Arg[];
|
|
985
|
+
return [u as Arg];
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
function asCaseList(value: unknown): Case[] {
|
|
989
|
+
const u = unwrap(value);
|
|
990
|
+
if (u == null) return [];
|
|
991
|
+
if (Array.isArray(u)) return u.filter(Boolean) as Case[];
|
|
992
|
+
return [u as Case];
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function isName(value: unknown): value is Name {
|
|
996
|
+
return (
|
|
997
|
+
value != null &&
|
|
998
|
+
typeof value === "object" &&
|
|
999
|
+
(value as { kind?: unknown }).kind === "Name" &&
|
|
1000
|
+
typeof (value as { id?: unknown }).id === "string"
|
|
1001
|
+
);
|
|
1002
|
+
}
|