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