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