@angular-wave/angular.ts 0.0.48 → 0.0.50
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/Makefile +3 -0
- package/README.md +1 -1
- package/css/angular.css +0 -6
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/jsdoc.json +24 -0
- package/package.json +6 -2
- package/src/core/compile/compile.md +1 -1
- package/src/core/compile/compile.spec.js +50 -48
- package/src/core/interpolate/interpolate.js +1 -18
- package/src/core/on.spec.js +7 -12
- package/src/core/parser/ast.js +234 -69
- package/src/core/parser/interpreter.js +246 -50
- package/src/core/parser/lexer.js +144 -57
- package/src/core/parser/parse.js +38 -278
- package/src/core/parser/parse.md +44 -0
- package/src/core/parser/parser.js +32 -6
- package/src/core/parser/shared.js +7 -1
- package/src/core/prop.spec.js +4 -4
- package/src/core/scope/scope.js +14 -10
- package/src/directive/csp.md +0 -26
- package/src/directive/form/form.spec.js +18 -18
- package/src/directive/include/include.spec.js +18 -18
- package/src/directive/switch/switch.spec.js +4 -4
- package/src/shared/constants.js +3 -2
- package/src/shared/jqlite/jqlite.js +2 -2
- package/src/types.js +4 -1
- package/types/core/parser/ast.d.ts +269 -67
- package/types/core/parser/interpreter.d.ts +202 -53
- package/types/core/parser/lexer.d.ts +153 -0
- package/types/core/parser/parse.d.ts +23 -34
- package/types/core/parser/parser.d.ts +43 -14
- package/types/core/parser/shared.d.ts +7 -1
- package/types/core/scope/scope.d.ts +11 -11
- package/types/shared/jqlite/jqlite.d.ts +4 -4
- package/types/types.d.ts +1 -1
- package/src/core/parser/compiler.js +0 -561
- package/types/core/parser/compiler.d.ts +0 -49
package/src/core/parser/ast.js
CHANGED
|
@@ -2,12 +2,55 @@ import { $parseMinErr } from "./parse";
|
|
|
2
2
|
import { isAssignable } from "./shared";
|
|
3
3
|
import { ASTType } from "./ast-type";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {Object} ASTNode
|
|
7
|
+
* @property {string} type - The type of the AST node.
|
|
8
|
+
* @property {string} [name] - The name of the identifier.
|
|
9
|
+
* @property {string} [kind] - The kind of the property (e.g., 'init').
|
|
10
|
+
* @property {*} [value] - The value of the node if it is a literal.
|
|
11
|
+
* @property {ASTNode[]} [elements] - The elements of an array node.
|
|
12
|
+
* @property {ASTNode[]} [properties] - The properties of an object node.
|
|
13
|
+
* @property {ASTNode} [key] - The key of an object property.
|
|
14
|
+
* @property {ASTNode} [value] - The value of an object property.
|
|
15
|
+
* @property {ASTNode} [left] - The left-hand side of a binary expression.
|
|
16
|
+
* @property {ASTNode} [right] - The right-hand side of a binary expression.
|
|
17
|
+
* @property {ASTNode} [argument] - The argument of a unary expression.
|
|
18
|
+
* @property {ASTNode} [test] - The test expression of a conditional expression.
|
|
19
|
+
* @property {ASTNode} [alternate] - The alternate expression of a conditional expression.
|
|
20
|
+
* @property {ASTNode} [consequent] - The consequent expression of a conditional expression.
|
|
21
|
+
* @property {ASTNode[]} [body] - The body of a program or block statement.
|
|
22
|
+
* @property {ASTNode} [expression] - The expression of an expression statement.
|
|
23
|
+
* @property {ASTNode} [callee] - The callee of a call expression.
|
|
24
|
+
* @property {ASTNode[]} [arguments] - The arguments of a call expression.
|
|
25
|
+
* @property {boolean} [prefix] - Indicates if a unary operator is a prefix.
|
|
26
|
+
* @property {ASTNode} [object] - The object of a member expression.
|
|
27
|
+
* @property {ASTNode} [property] - The property of a member expression.
|
|
28
|
+
* @property {boolean} [computed] - Indicates if a member expression is computed.
|
|
29
|
+
* @property {string} [operator] - The operator of a binary or logical expression.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {import('./lexer').Lexer} lexer - The lexer instance for tokenizing input
|
|
34
|
+
* @param {import("./parser").ParserOptions} options
|
|
35
|
+
*/
|
|
36
|
+
export class AST {
|
|
37
|
+
constructor(lexer, options) {
|
|
38
|
+
/** @type {import('./lexer').Lexer} */
|
|
39
|
+
this.lexer = lexer;
|
|
40
|
+
|
|
41
|
+
/** @type {import("./parser").ParserOptions} */
|
|
42
|
+
this.options = options;
|
|
43
|
+
this.selfReferential = {
|
|
44
|
+
this: { type: ASTType.ThisExpression },
|
|
45
|
+
$locals: { type: ASTType.LocalsExpression },
|
|
46
|
+
};
|
|
47
|
+
}
|
|
9
48
|
|
|
10
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Parses the input text and generates an AST.
|
|
51
|
+
* @param {string} text - The input text to parse.
|
|
52
|
+
* @returns {ASTNode} The root node of the AST.
|
|
53
|
+
*/
|
|
11
54
|
ast(text) {
|
|
12
55
|
this.text = text;
|
|
13
56
|
this.tokens = this.lexer.lex(text);
|
|
@@ -19,8 +62,12 @@ AST.prototype = {
|
|
|
19
62
|
}
|
|
20
63
|
|
|
21
64
|
return value;
|
|
22
|
-
}
|
|
65
|
+
}
|
|
23
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Parses a program.
|
|
69
|
+
* @returns {ASTNode} The program node.
|
|
70
|
+
*/
|
|
24
71
|
program() {
|
|
25
72
|
const body = [];
|
|
26
73
|
let hasMore = true;
|
|
@@ -32,27 +79,43 @@ AST.prototype = {
|
|
|
32
79
|
}
|
|
33
80
|
}
|
|
34
81
|
return { type: ASTType.Program, body };
|
|
35
|
-
}
|
|
82
|
+
}
|
|
36
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Parses an expression statement.
|
|
86
|
+
* @returns {ASTNode} The expression statement node.
|
|
87
|
+
*/
|
|
37
88
|
expressionStatement() {
|
|
38
89
|
return {
|
|
39
90
|
type: ASTType.ExpressionStatement,
|
|
40
91
|
expression: this.filterChain(),
|
|
41
92
|
};
|
|
42
|
-
}
|
|
93
|
+
}
|
|
43
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Parses a filter chain.
|
|
97
|
+
* @returns {ASTNode} The filter chain node.
|
|
98
|
+
*/
|
|
44
99
|
filterChain() {
|
|
45
100
|
let left = this.expression();
|
|
46
101
|
while (this.expect("|")) {
|
|
47
102
|
left = this.filter(left);
|
|
48
103
|
}
|
|
49
104
|
return left;
|
|
50
|
-
}
|
|
105
|
+
}
|
|
51
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Parses an expression.
|
|
109
|
+
* @returns {ASTNode} The expression node.
|
|
110
|
+
*/
|
|
52
111
|
expression() {
|
|
53
112
|
return this.assignment();
|
|
54
|
-
}
|
|
113
|
+
}
|
|
55
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Parses an assignment expression.
|
|
117
|
+
* @returns {ASTNode} The assignment expression node.
|
|
118
|
+
*/
|
|
56
119
|
assignment() {
|
|
57
120
|
let result = this.ternary();
|
|
58
121
|
if (this.expect("=")) {
|
|
@@ -68,8 +131,12 @@ AST.prototype = {
|
|
|
68
131
|
};
|
|
69
132
|
}
|
|
70
133
|
return result;
|
|
71
|
-
}
|
|
134
|
+
}
|
|
72
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Parses a ternary expression.
|
|
138
|
+
* @returns {ASTNode} The ternary expression node.
|
|
139
|
+
*/
|
|
73
140
|
ternary() {
|
|
74
141
|
const test = this.logicalOR();
|
|
75
142
|
let alternate;
|
|
@@ -87,8 +154,12 @@ AST.prototype = {
|
|
|
87
154
|
}
|
|
88
155
|
}
|
|
89
156
|
return test;
|
|
90
|
-
}
|
|
157
|
+
}
|
|
91
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Parses a logical OR expression.
|
|
161
|
+
* @returns {ASTNode} The logical OR expression node.
|
|
162
|
+
*/
|
|
92
163
|
logicalOR() {
|
|
93
164
|
let left = this.logicalAND();
|
|
94
165
|
while (this.expect("||")) {
|
|
@@ -100,8 +171,12 @@ AST.prototype = {
|
|
|
100
171
|
};
|
|
101
172
|
}
|
|
102
173
|
return left;
|
|
103
|
-
}
|
|
174
|
+
}
|
|
104
175
|
|
|
176
|
+
/**
|
|
177
|
+
* Parses a logical AND expression.
|
|
178
|
+
* @returns {ASTNode} The logical AND expression node.
|
|
179
|
+
*/
|
|
105
180
|
logicalAND() {
|
|
106
181
|
let left = this.equality();
|
|
107
182
|
while (this.expect("&&")) {
|
|
@@ -113,77 +188,101 @@ AST.prototype = {
|
|
|
113
188
|
};
|
|
114
189
|
}
|
|
115
190
|
return left;
|
|
116
|
-
}
|
|
191
|
+
}
|
|
117
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Parses an equality expression.
|
|
195
|
+
* @returns {ASTNode} The equality expression node.
|
|
196
|
+
*/
|
|
118
197
|
equality() {
|
|
119
198
|
let left = this.relational();
|
|
120
199
|
let token;
|
|
121
200
|
while ((token = this.expect("==", "!=", "===", "!=="))) {
|
|
122
201
|
left = {
|
|
123
202
|
type: ASTType.BinaryExpression,
|
|
124
|
-
operator: token.text,
|
|
203
|
+
operator: /** @type {import("./lexer").Token} */ (token).text,
|
|
125
204
|
left,
|
|
126
205
|
right: this.relational(),
|
|
127
206
|
};
|
|
128
207
|
}
|
|
129
208
|
return left;
|
|
130
|
-
}
|
|
209
|
+
}
|
|
131
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Parses a relational expression.
|
|
213
|
+
* @returns {ASTNode} The relational expression node.
|
|
214
|
+
*/
|
|
132
215
|
relational() {
|
|
133
216
|
let left = this.additive();
|
|
134
217
|
let token;
|
|
135
218
|
while ((token = this.expect("<", ">", "<=", ">="))) {
|
|
136
219
|
left = {
|
|
137
220
|
type: ASTType.BinaryExpression,
|
|
138
|
-
operator: token.text,
|
|
221
|
+
operator: /** @type {import("./lexer").Token} */ (token).text,
|
|
139
222
|
left,
|
|
140
223
|
right: this.additive(),
|
|
141
224
|
};
|
|
142
225
|
}
|
|
143
226
|
return left;
|
|
144
|
-
}
|
|
227
|
+
}
|
|
145
228
|
|
|
229
|
+
/**
|
|
230
|
+
* Parses an additive expression.
|
|
231
|
+
* @returns {ASTNode} The additive expression node.
|
|
232
|
+
*/
|
|
146
233
|
additive() {
|
|
147
234
|
let left = this.multiplicative();
|
|
148
235
|
let token;
|
|
149
236
|
while ((token = this.expect("+", "-"))) {
|
|
150
237
|
left = {
|
|
151
238
|
type: ASTType.BinaryExpression,
|
|
152
|
-
operator: token.text,
|
|
239
|
+
operator: /** @type {import("./lexer").Token} */ (token).text,
|
|
153
240
|
left,
|
|
154
241
|
right: this.multiplicative(),
|
|
155
242
|
};
|
|
156
243
|
}
|
|
157
244
|
return left;
|
|
158
|
-
}
|
|
245
|
+
}
|
|
159
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Parses a multiplicative expression.
|
|
249
|
+
* @returns {ASTNode} The multiplicative expression node.
|
|
250
|
+
*/
|
|
160
251
|
multiplicative() {
|
|
161
252
|
let left = this.unary();
|
|
162
253
|
let token;
|
|
163
254
|
while ((token = this.expect("*", "/", "%"))) {
|
|
164
255
|
left = {
|
|
165
256
|
type: ASTType.BinaryExpression,
|
|
166
|
-
operator: token.text,
|
|
257
|
+
operator: /** @type {import("./lexer").Token} */ (token).text,
|
|
167
258
|
left,
|
|
168
259
|
right: this.unary(),
|
|
169
260
|
};
|
|
170
261
|
}
|
|
171
262
|
return left;
|
|
172
|
-
}
|
|
263
|
+
}
|
|
173
264
|
|
|
265
|
+
/**
|
|
266
|
+
* Parses a unary expression.
|
|
267
|
+
* @returns {ASTNode} The unary expression node.
|
|
268
|
+
*/
|
|
174
269
|
unary() {
|
|
175
270
|
let token;
|
|
176
271
|
if ((token = this.expect("+", "-", "!"))) {
|
|
177
272
|
return {
|
|
178
273
|
type: ASTType.UnaryExpression,
|
|
179
|
-
operator: token.text,
|
|
274
|
+
operator: /** @type {import("./lexer").Token} */ (token).text,
|
|
180
275
|
prefix: true,
|
|
181
276
|
argument: this.unary(),
|
|
182
277
|
};
|
|
183
278
|
}
|
|
184
279
|
return this.primary();
|
|
185
|
-
}
|
|
280
|
+
}
|
|
186
281
|
|
|
282
|
+
/**
|
|
283
|
+
* Parses a primary expression.
|
|
284
|
+
* @returns {ASTNode} The primary expression node.
|
|
285
|
+
*/
|
|
187
286
|
primary() {
|
|
188
287
|
let primary;
|
|
189
288
|
if (this.expect("(")) {
|
|
@@ -196,38 +295,43 @@ AST.prototype = {
|
|
|
196
295
|
} else if (
|
|
197
296
|
Object.prototype.hasOwnProperty.call(
|
|
198
297
|
this.selfReferential,
|
|
199
|
-
this.peek().text,
|
|
298
|
+
/** @type {import("./lexer").Token} */ (this.peek()).text,
|
|
200
299
|
)
|
|
201
300
|
) {
|
|
202
301
|
primary = structuredClone(this.selfReferential[this.consume().text]);
|
|
203
302
|
} else if (
|
|
204
303
|
Object.prototype.hasOwnProperty.call(
|
|
205
304
|
this.options.literals,
|
|
206
|
-
this.peek().text,
|
|
305
|
+
/** @type {import("./lexer").Token} */ (this.peek()).text,
|
|
207
306
|
)
|
|
208
307
|
) {
|
|
209
308
|
primary = {
|
|
210
309
|
type: ASTType.Literal,
|
|
211
310
|
value: this.options.literals[this.consume().text],
|
|
212
311
|
};
|
|
213
|
-
} else if (
|
|
312
|
+
} else if (
|
|
313
|
+
/** @type {import("./lexer").Token} */ (this.peek()).identifier
|
|
314
|
+
) {
|
|
214
315
|
primary = this.identifier();
|
|
215
|
-
} else if (this.peek().constant) {
|
|
316
|
+
} else if (/** @type {import("./lexer").Token} */ (this.peek()).constant) {
|
|
216
317
|
primary = this.constant();
|
|
217
318
|
} else {
|
|
218
|
-
this.throwError(
|
|
319
|
+
this.throwError(
|
|
320
|
+
"not a primary expression",
|
|
321
|
+
/** @type {import("./lexer").Token} */ (this.peek()),
|
|
322
|
+
);
|
|
219
323
|
}
|
|
220
324
|
|
|
221
325
|
let next;
|
|
222
326
|
while ((next = this.expect("(", "[", "."))) {
|
|
223
|
-
if (next.text === "(") {
|
|
327
|
+
if (/** @type {import("./lexer").Token} */ (next).text === "(") {
|
|
224
328
|
primary = {
|
|
225
329
|
type: ASTType.CallExpression,
|
|
226
330
|
callee: primary,
|
|
227
331
|
arguments: this.parseArguments(),
|
|
228
332
|
};
|
|
229
333
|
this.consume(")");
|
|
230
|
-
} else if (next.text === "[") {
|
|
334
|
+
} else if (/** @type {import("./lexer").Token} */ (next).text === "[") {
|
|
231
335
|
primary = {
|
|
232
336
|
type: ASTType.MemberExpression,
|
|
233
337
|
object: primary,
|
|
@@ -235,7 +339,7 @@ AST.prototype = {
|
|
|
235
339
|
computed: true,
|
|
236
340
|
};
|
|
237
341
|
this.consume("]");
|
|
238
|
-
} else if (next.text === ".") {
|
|
342
|
+
} else if (/** @type {import("./lexer").Token} */ (next).text === ".") {
|
|
239
343
|
primary = {
|
|
240
344
|
type: ASTType.MemberExpression,
|
|
241
345
|
object: primary,
|
|
@@ -247,9 +351,15 @@ AST.prototype = {
|
|
|
247
351
|
}
|
|
248
352
|
}
|
|
249
353
|
return primary;
|
|
250
|
-
}
|
|
354
|
+
}
|
|
251
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Parses a filter.
|
|
358
|
+
* @param {ASTNode} baseExpression - The base expression to apply the filter to.
|
|
359
|
+
* @returns {ASTNode} The filter node.
|
|
360
|
+
*/
|
|
252
361
|
filter(baseExpression) {
|
|
362
|
+
/** @type {ASTNode[]} */
|
|
253
363
|
const args = [baseExpression];
|
|
254
364
|
const result = {
|
|
255
365
|
type: ASTType.CallExpression,
|
|
@@ -263,9 +373,14 @@ AST.prototype = {
|
|
|
263
373
|
}
|
|
264
374
|
|
|
265
375
|
return result;
|
|
266
|
-
}
|
|
376
|
+
}
|
|
267
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Parses function arguments.
|
|
380
|
+
* @returns {ASTNode[]} The arguments array.
|
|
381
|
+
*/
|
|
268
382
|
parseArguments() {
|
|
383
|
+
/** @type {ASTNode[]} */
|
|
269
384
|
const args = [];
|
|
270
385
|
if (this.peekToken().text !== ")") {
|
|
271
386
|
do {
|
|
@@ -273,22 +388,35 @@ AST.prototype = {
|
|
|
273
388
|
} while (this.expect(","));
|
|
274
389
|
}
|
|
275
390
|
return args;
|
|
276
|
-
}
|
|
391
|
+
}
|
|
277
392
|
|
|
393
|
+
/**
|
|
394
|
+
* Parses an identifier.
|
|
395
|
+
* @returns {ASTNode} The identifier node.
|
|
396
|
+
*/
|
|
278
397
|
identifier() {
|
|
279
398
|
const token = this.consume();
|
|
280
399
|
if (!token.identifier) {
|
|
281
400
|
this.throwError("is not a valid identifier", token);
|
|
282
401
|
}
|
|
283
402
|
return { type: ASTType.Identifier, name: token.text };
|
|
284
|
-
}
|
|
403
|
+
}
|
|
285
404
|
|
|
405
|
+
/**
|
|
406
|
+
* Parses a constant.
|
|
407
|
+
* @returns {ASTNode} The constant node.
|
|
408
|
+
*/
|
|
286
409
|
constant() {
|
|
287
410
|
// TODO check that it is a constant
|
|
288
411
|
return { type: ASTType.Literal, value: this.consume().value };
|
|
289
|
-
}
|
|
412
|
+
}
|
|
290
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Parses an array declaration.
|
|
416
|
+
* @returns {ASTNode} The array declaration node.
|
|
417
|
+
*/
|
|
291
418
|
arrayDeclaration() {
|
|
419
|
+
/** @type {ASTNode[]} */
|
|
292
420
|
const elements = [];
|
|
293
421
|
if (this.peekToken().text !== "]") {
|
|
294
422
|
do {
|
|
@@ -302,10 +430,16 @@ AST.prototype = {
|
|
|
302
430
|
this.consume("]");
|
|
303
431
|
|
|
304
432
|
return { type: ASTType.ArrayExpression, elements };
|
|
305
|
-
}
|
|
433
|
+
}
|
|
306
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Parses an object.
|
|
437
|
+
* @returns {ASTNode} The object node.
|
|
438
|
+
*/
|
|
307
439
|
object() {
|
|
440
|
+
/** @type {ASTNode[]} */
|
|
308
441
|
const properties = [];
|
|
442
|
+
/** @type {ASTNode} */
|
|
309
443
|
let property;
|
|
310
444
|
if (this.peekToken().text !== "}") {
|
|
311
445
|
do {
|
|
@@ -314,12 +448,14 @@ AST.prototype = {
|
|
|
314
448
|
break;
|
|
315
449
|
}
|
|
316
450
|
property = { type: ASTType.Property, kind: "init" };
|
|
317
|
-
if (this.peek().constant) {
|
|
451
|
+
if (/** @type {import("./lexer").Token} */ (this.peek()).constant) {
|
|
318
452
|
property.key = this.constant();
|
|
319
453
|
property.computed = false;
|
|
320
454
|
this.consume(":");
|
|
321
455
|
property.value = this.expression();
|
|
322
|
-
} else if (
|
|
456
|
+
} else if (
|
|
457
|
+
/** @type {import("./lexer").Token} */ (this.peek()).identifier
|
|
458
|
+
) {
|
|
323
459
|
property.key = this.identifier();
|
|
324
460
|
property.computed = false;
|
|
325
461
|
if (this.peek(":")) {
|
|
@@ -336,7 +472,10 @@ AST.prototype = {
|
|
|
336
472
|
this.consume(":");
|
|
337
473
|
property.value = this.expression();
|
|
338
474
|
} else {
|
|
339
|
-
this.throwError(
|
|
475
|
+
this.throwError(
|
|
476
|
+
"invalid key",
|
|
477
|
+
/** @type {import("./lexer").Token} */ (this.peek()),
|
|
478
|
+
);
|
|
340
479
|
}
|
|
341
480
|
properties.push(property);
|
|
342
481
|
} while (this.expect(","));
|
|
@@ -344,8 +483,13 @@ AST.prototype = {
|
|
|
344
483
|
this.consume("}");
|
|
345
484
|
|
|
346
485
|
return { type: ASTType.ObjectExpression, properties };
|
|
347
|
-
}
|
|
486
|
+
}
|
|
348
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Throws a syntax error.
|
|
490
|
+
* @param {string} msg - The error message.
|
|
491
|
+
* @param {import("./lexer").Token} [token] - The token that caused the error.
|
|
492
|
+
*/
|
|
349
493
|
throwError(msg, token) {
|
|
350
494
|
throw $parseMinErr(
|
|
351
495
|
"syntax",
|
|
@@ -356,8 +500,13 @@ AST.prototype = {
|
|
|
356
500
|
this.text,
|
|
357
501
|
this.text.substring(token.index),
|
|
358
502
|
);
|
|
359
|
-
}
|
|
503
|
+
}
|
|
360
504
|
|
|
505
|
+
/**
|
|
506
|
+
* Consumes a token if it matches the expected type.
|
|
507
|
+
* @param {string} [e1] - The expected token type.
|
|
508
|
+
* @returns {import("./lexer").Token} The consumed token.
|
|
509
|
+
*/
|
|
361
510
|
consume(e1) {
|
|
362
511
|
if (this.tokens.length === 0) {
|
|
363
512
|
throw $parseMinErr(
|
|
@@ -369,11 +518,19 @@ AST.prototype = {
|
|
|
369
518
|
|
|
370
519
|
const token = this.expect(e1);
|
|
371
520
|
if (!token) {
|
|
372
|
-
this.throwError(
|
|
521
|
+
this.throwError(
|
|
522
|
+
`is unexpected, expecting [${e1}]`,
|
|
523
|
+
/** @type {import("./lexer").Token} */ (this.peek()),
|
|
524
|
+
);
|
|
525
|
+
} else {
|
|
526
|
+
return /** @type {import("./lexer").Token} */ (token);
|
|
373
527
|
}
|
|
374
|
-
|
|
375
|
-
},
|
|
528
|
+
}
|
|
376
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Returns the next token without consuming it.
|
|
532
|
+
* @returns {import("./lexer").Token} The next token.
|
|
533
|
+
*/
|
|
377
534
|
peekToken() {
|
|
378
535
|
if (this.tokens.length === 0) {
|
|
379
536
|
throw $parseMinErr(
|
|
@@ -383,40 +540,48 @@ AST.prototype = {
|
|
|
383
540
|
);
|
|
384
541
|
}
|
|
385
542
|
return this.tokens[0];
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Checks if the next token matches any of the expected types.
|
|
547
|
+
* @param {...string} [expected] - The expected token types.
|
|
548
|
+
* @returns {import('./lexer').Token|boolean} The next token if it matches, otherwise false.
|
|
549
|
+
*/
|
|
550
|
+
peek(...expected) {
|
|
551
|
+
return this.peekAhead(0, ...expected);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Checks if the token at the specified index matches any of the expected types.
|
|
556
|
+
* @param {number} i - The index to check.
|
|
557
|
+
* @param {...string} [expected] - The expected token types.
|
|
558
|
+
* @returns {import("./lexer").Token|boolean} The token at the specified index if it matches, otherwise false.
|
|
559
|
+
*/
|
|
560
|
+
peekAhead(i, ...expected) {
|
|
393
561
|
if (this.tokens.length > i) {
|
|
394
562
|
const token = this.tokens[i];
|
|
395
563
|
const t = token.text;
|
|
396
564
|
if (
|
|
397
|
-
t
|
|
398
|
-
|
|
399
|
-
t === e3 ||
|
|
400
|
-
t === e4 ||
|
|
401
|
-
(!e1 && !e2 && !e3 && !e4)
|
|
565
|
+
expected.includes(t) ||
|
|
566
|
+
(!expected[0] && !expected[1] && !expected[2] && !expected[3])
|
|
402
567
|
) {
|
|
403
568
|
return token;
|
|
404
569
|
}
|
|
405
570
|
}
|
|
406
571
|
return false;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Consumes the next token if it matches any of the expected types.
|
|
576
|
+
* @param {...string} [expected] - The expected token types.
|
|
577
|
+
* @returns {import("./lexer").Token|boolean} The consumed token if it matches, otherwise false.
|
|
578
|
+
*/
|
|
579
|
+
expect(...expected) {
|
|
580
|
+
const token = this.peek(...expected);
|
|
411
581
|
if (token) {
|
|
412
582
|
this.tokens.shift();
|
|
413
583
|
return token;
|
|
414
584
|
}
|
|
415
585
|
return false;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
selfReferential: {
|
|
419
|
-
this: { type: ASTType.ThisExpression },
|
|
420
|
-
$locals: { type: ASTType.LocalsExpression },
|
|
421
|
-
},
|
|
422
|
-
};
|
|
586
|
+
}
|
|
587
|
+
}
|