@ibyar/expressions 0.5.2 → 0.5.62
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/LICENSE +1 -1
- package/README.md +4 -3
- package/api/abstract.d.ts +5 -6
- package/api/abstract.js +8 -3
- package/api/abstract.js.map +1 -1
- package/api/class/class.d.ts +227 -0
- package/api/class/class.js +662 -0
- package/api/class/class.js.map +1 -0
- package/api/class/decorator.d.ts +20 -0
- package/api/class/decorator.js +48 -0
- package/api/class/decorator.js.map +1 -0
- package/api/computing/call.d.ts +3 -1
- package/api/computing/call.js +16 -4
- package/api/computing/call.js.map +1 -1
- package/api/computing/debugger.d.ts +15 -0
- package/api/computing/debugger.js +35 -0
- package/api/computing/debugger.js.map +1 -0
- package/api/computing/new.d.ts +2 -1
- package/api/computing/new.js +4 -0
- package/api/computing/new.js.map +1 -1
- package/api/computing/rest.d.ts +6 -6
- package/api/computing/rest.js +5 -2
- package/api/computing/rest.js.map +1 -1
- package/api/computing/return.d.ts +6 -1
- package/api/computing/return.js +8 -0
- package/api/computing/return.js.map +1 -1
- package/api/computing/spread.d.ts +2 -1
- package/api/computing/spread.js +5 -2
- package/api/computing/spread.js.map +1 -1
- package/api/computing/throw.d.ts +6 -1
- package/api/computing/throw.js +7 -0
- package/api/computing/throw.js.map +1 -1
- package/api/computing/yield.d.ts +2 -1
- package/api/computing/yield.js +3 -0
- package/api/computing/yield.js.map +1 -1
- package/api/definition/array.d.ts +12 -12
- package/api/definition/array.js +31 -25
- package/api/definition/array.js.map +1 -1
- package/api/definition/bind.d.ts +8 -2
- package/api/definition/bind.js +7 -1
- package/api/definition/bind.js.map +1 -1
- package/api/definition/function.d.ts +40 -51
- package/api/definition/function.js +292 -309
- package/api/definition/function.js.map +1 -1
- package/api/definition/member.d.ts +2 -2
- package/api/definition/member.js +1 -1
- package/api/definition/member.js.map +1 -1
- package/api/definition/object.d.ts +15 -12
- package/api/definition/object.js +43 -13
- package/api/definition/object.js.map +1 -1
- package/api/definition/statement.d.ts +2 -2
- package/api/definition/statement.js +7 -3
- package/api/definition/statement.js.map +1 -1
- package/api/definition/values.d.ts +44 -50
- package/api/definition/values.js +87 -149
- package/api/definition/values.js.map +1 -1
- package/api/deserialize/deserialize.d.ts +7 -1
- package/api/deserialize/deserialize.js +9 -1
- package/api/deserialize/deserialize.js.map +1 -1
- package/api/deserialize/type-store.d.ts +2 -2
- package/api/deserialize/type-store.js.map +1 -1
- package/api/expression.d.ts +159 -18
- package/api/expression.js.map +1 -1
- package/api/index.d.ts +2 -0
- package/api/index.js +2 -0
- package/api/index.js.map +1 -1
- package/api/module/common.d.ts +29 -0
- package/api/module/common.js +71 -0
- package/api/module/common.js.map +1 -0
- package/api/module/export.d.ts +129 -25
- package/api/module/export.js +333 -58
- package/api/module/export.js.map +1 -1
- package/api/module/import.d.ts +114 -25
- package/api/module/import.js +279 -68
- package/api/module/import.js.map +1 -1
- package/api/operators/assignment.d.ts +2 -2
- package/api/operators/assignment.js +1 -1
- package/api/operators/assignment.js.map +1 -1
- package/api/operators/await.d.ts +2 -2
- package/api/operators/await.js +1 -1
- package/api/operators/await.js.map +1 -1
- package/api/operators/binary.d.ts +2 -2
- package/api/operators/binary.js +1 -1
- package/api/operators/binary.js.map +1 -1
- package/api/operators/chaining.d.ts +2 -2
- package/api/operators/chaining.js +1 -1
- package/api/operators/chaining.js.map +1 -1
- package/api/operators/comma.d.ts +2 -2
- package/api/operators/comma.js +2 -2
- package/api/operators/comma.js.map +1 -1
- package/api/operators/grouping.d.ts +9 -2
- package/api/operators/grouping.js +8 -1
- package/api/operators/grouping.js.map +1 -1
- package/api/operators/logical.d.ts +2 -2
- package/api/operators/logical.js +1 -1
- package/api/operators/logical.js.map +1 -1
- package/api/operators/pipeline.d.ts +14 -2
- package/api/operators/pipeline.js +13 -1
- package/api/operators/pipeline.js.map +1 -1
- package/api/operators/ternary.d.ts +2 -2
- package/api/operators/ternary.js +1 -1
- package/api/operators/ternary.js.map +1 -1
- package/api/operators/unary.d.ts +3 -3
- package/api/operators/unary.js +7 -3
- package/api/operators/unary.js.map +1 -1
- package/api/operators/update.d.ts +2 -2
- package/api/operators/update.js +1 -1
- package/api/operators/update.js.map +1 -1
- package/api/{app/program.d.ts → program.d.ts} +8 -9
- package/api/program.js +45 -0
- package/api/program.js.map +1 -0
- package/api/statement/control/block.d.ts +8 -5
- package/api/statement/control/block.js +26 -23
- package/api/statement/control/block.js.map +1 -1
- package/api/statement/control/empty.d.ts +8 -1
- package/api/statement/control/empty.js +7 -0
- package/api/statement/control/empty.js.map +1 -1
- package/api/statement/control/if.d.ts +7 -2
- package/api/statement/control/if.js +6 -1
- package/api/statement/control/if.js.map +1 -1
- package/api/statement/control/switch.d.ts +10 -5
- package/api/statement/control/switch.js +22 -9
- package/api/statement/control/switch.js.map +1 -1
- package/api/statement/control/terminate.d.ts +46 -13
- package/api/statement/control/terminate.js +89 -20
- package/api/statement/control/terminate.js.map +1 -1
- package/api/statement/declarations/declares.d.ts +17 -16
- package/api/statement/declarations/declares.js +24 -19
- package/api/statement/declarations/declares.js.map +1 -1
- package/api/statement/iterations/for.d.ts +10 -5
- package/api/statement/iterations/for.js +42 -23
- package/api/statement/iterations/for.js.map +1 -1
- package/api/statement/iterations/while.d.ts +9 -3
- package/api/statement/iterations/while.js +27 -13
- package/api/statement/iterations/while.js.map +1 -1
- package/api/utils.d.ts +5 -0
- package/api/utils.js +4 -0
- package/api/utils.js.map +1 -0
- package/package.json +5 -5
- package/scope/finalizer.d.ts +4 -0
- package/scope/finalizer.js +11 -0
- package/scope/finalizer.js.map +1 -0
- package/scope/proxy.d.ts +5 -3
- package/scope/proxy.js +26 -26
- package/scope/proxy.js.map +1 -1
- package/scope/scope.d.ts +108 -51
- package/scope/scope.js +72 -134
- package/scope/scope.js.map +1 -1
- package/scope/stack.d.ts +117 -26
- package/scope/stack.js +154 -102
- package/scope/stack.js.map +1 -1
- package/v8/enums.d.ts +204 -0
- package/v8/enums.js +406 -0
- package/v8/enums.js.map +1 -0
- package/v8/index.d.ts +2 -1
- package/v8/index.js +2 -1
- package/v8/index.js.map +1 -1
- package/v8/inline.d.ts +213 -0
- package/v8/inline.js +2375 -0
- package/v8/inline.js.map +1 -0
- package/v8/nodes.d.ts +8 -7
- package/v8/nodes.js +39 -64
- package/v8/nodes.js.map +1 -1
- package/v8/parser.d.ts +49 -151
- package/v8/parser.js +839 -1607
- package/v8/parser.js.map +1 -1
- package/v8/stream.d.ts +39 -3
- package/v8/stream.js +685 -171
- package/v8/stream.js.map +1 -1
- package/v8/token.d.ts +244 -9
- package/v8/token.js +315 -47
- package/v8/token.js.map +1 -1
- package/visit/visitor.d.ts +3 -0
- package/visit/visitor.js +4 -7
- package/visit/visitor.js.map +1 -1
- package/api/app/class.d.ts +0 -117
- package/api/app/class.js +0 -292
- package/api/app/class.js.map +0 -1
- package/api/app/program.js +0 -39
- package/api/app/program.js.map +0 -1
- package/api/module/module.d.ts +0 -26
- package/api/module/module.js +0 -63
- package/api/module/module.js.map +0 -1
- package/v8/app.d.ts +0 -0
- package/v8/app.js +0 -2
- package/v8/app.js.map +0 -1
package/v8/inline.js
ADDED
|
@@ -0,0 +1,2375 @@
|
|
|
1
|
+
import { Token } from './token.js';
|
|
2
|
+
import { TokenStream } from './stream.js';
|
|
3
|
+
import { OfNode, Identifier, ThisNode, GetIdentifier, SetIdentifier, AsyncIdentifier, NullNode, AwaitIdentifier, ConstructorIdentifier, NameIdentifier, EvalIdentifier, ArgumentsIdentifier, TaggedTemplateExpression, TemplateLiteral, SuperIdentifier } from '../api/definition/values.js';
|
|
4
|
+
import { EmptyStatement } from '../api/statement/control/empty.js';
|
|
5
|
+
import { BlockStatement } from '../api/statement/control/block.js';
|
|
6
|
+
import { ArrowFunctionExpression, Param, FunctionExpression, FunctionDeclaration } from '../api/definition/function.js';
|
|
7
|
+
import { IfStatement } from '../api/statement/control/if.js';
|
|
8
|
+
import { NewExpression } from '../api/computing/new.js';
|
|
9
|
+
import { SpreadElement } from '../api/computing/spread.js';
|
|
10
|
+
import { RestElement } from '../api/computing/rest.js';
|
|
11
|
+
import { AssignmentExpression } from '../api/operators/assignment.js';
|
|
12
|
+
import { GroupingExpression } from '../api/operators/grouping.js';
|
|
13
|
+
import { MemberExpression } from '../api/definition/member.js';
|
|
14
|
+
import { BindExpression } from '../api/definition/bind.js';
|
|
15
|
+
import { ObjectExpression, Property, ObjectPattern } from '../api/definition/object.js';
|
|
16
|
+
import { ArrayExpression, ArrayPattern } from '../api/definition/array.js';
|
|
17
|
+
import { CallExpression } from '../api/computing/call.js';
|
|
18
|
+
import { DoWhileNode, WhileNode } from '../api/statement/iterations/while.js';
|
|
19
|
+
import { CatchClauseNode, ThrowStatement, TryCatchNode } from '../api/computing/throw.js';
|
|
20
|
+
import { SwitchCase, DefaultExpression, SwitchStatement } from '../api/statement/control/switch.js';
|
|
21
|
+
import { BreakStatement, ContinueStatement, LabeledStatement } from '../api/statement/control/terminate.js';
|
|
22
|
+
import { ReturnStatement } from '../api/computing/return.js';
|
|
23
|
+
import { YieldExpression } from '../api/computing/yield.js';
|
|
24
|
+
import { VariableDeclarator, VariableDeclarationNode } from '../api/statement/declarations/declares.js';
|
|
25
|
+
import { ForNode, ForOfNode, ForInNode, ForAwaitOfNode } from '../api/statement/iterations/for.js';
|
|
26
|
+
import { ConditionalExpression } from '../api/operators/ternary.js';
|
|
27
|
+
import { PipelineExpression } from '../api/operators/pipeline.js';
|
|
28
|
+
import { LogicalExpression } from '../api/operators/logical.js';
|
|
29
|
+
import { SequenceExpression } from '../api/operators/comma.js';
|
|
30
|
+
import { ChainExpression } from '../api/operators/chaining.js';
|
|
31
|
+
import { ExpressionStatement } from '../api/definition/statement.js';
|
|
32
|
+
import { buildPostfixExpression, buildUnaryExpression, expressionFromLiteral, shortcutNumericLiteralBinaryExpression } from './nodes.js';
|
|
33
|
+
import { AllowLabelledFunctionStatement, FunctionBodyType, FunctionKind, functionKindForImpl, FunctionSyntaxKind, isAsyncFunction, isAsyncGeneratorFunction, isAwaitAsIdentifierDisallowed, isClassMembersInitializerFunction, isGeneratorFunction, isModule, isResumableFunction, isSloppy, isStrict, LanguageMode, ParseFunctionFlag, ParsingArrowHeadFlag, PropertyKind, PropertyKindInfo, PropertyPosition, SubFunctionKind, VariableDeclarationContext } from './enums.js';
|
|
34
|
+
import { DebuggerStatement } from '../api/computing/debugger.js';
|
|
35
|
+
export class AbstractParser {
|
|
36
|
+
constructor(scanner, acceptIN) {
|
|
37
|
+
this.scanner = scanner;
|
|
38
|
+
this.previousAcceptIN = [];
|
|
39
|
+
this.previousFunctionKind = [];
|
|
40
|
+
this.previousAcceptIN.push(this.acceptIN = acceptIN ?? false);
|
|
41
|
+
this.previousFunctionKind.push(this.functionKind = FunctionKind.NormalFunction);
|
|
42
|
+
}
|
|
43
|
+
get languageMode() {
|
|
44
|
+
return this.scanner.getLanguageMode();
|
|
45
|
+
}
|
|
46
|
+
set languageMode(mode) {
|
|
47
|
+
this.scanner.setLanguageMode(mode);
|
|
48
|
+
}
|
|
49
|
+
position() {
|
|
50
|
+
return this.scanner.getPos();
|
|
51
|
+
}
|
|
52
|
+
setAcceptIN(acceptIN) {
|
|
53
|
+
this.previousAcceptIN.push(this.acceptIN);
|
|
54
|
+
this.acceptIN = acceptIN;
|
|
55
|
+
}
|
|
56
|
+
restoreAcceptIN() {
|
|
57
|
+
this.acceptIN = this.previousAcceptIN.pop() ?? false;
|
|
58
|
+
}
|
|
59
|
+
getLastFunctionKind() {
|
|
60
|
+
return this.previousFunctionKind.at(-2) ?? FunctionKind.NormalFunction;
|
|
61
|
+
}
|
|
62
|
+
setFunctionKind(functionKind) {
|
|
63
|
+
this.previousFunctionKind.push(this.functionKind);
|
|
64
|
+
this.functionKind = functionKind;
|
|
65
|
+
}
|
|
66
|
+
restoreFunctionKind() {
|
|
67
|
+
this.functionKind = this.previousFunctionKind.pop() ?? FunctionKind.NormalFunction;
|
|
68
|
+
}
|
|
69
|
+
setStatue(acceptIN, functionKind) {
|
|
70
|
+
this.setFunctionKind(functionKind);
|
|
71
|
+
this.setAcceptIN(acceptIN);
|
|
72
|
+
}
|
|
73
|
+
restoreStatue() {
|
|
74
|
+
this.restoreFunctionKind();
|
|
75
|
+
this.restoreAcceptIN();
|
|
76
|
+
}
|
|
77
|
+
current() {
|
|
78
|
+
return this.scanner.currentToken();
|
|
79
|
+
}
|
|
80
|
+
next() {
|
|
81
|
+
return this.scanner.next();
|
|
82
|
+
}
|
|
83
|
+
peek() {
|
|
84
|
+
return this.scanner.peek();
|
|
85
|
+
}
|
|
86
|
+
peekAhead() {
|
|
87
|
+
return this.scanner.peekAhead();
|
|
88
|
+
}
|
|
89
|
+
peekAheadPosition() {
|
|
90
|
+
return this.scanner.peekAheadPosition();
|
|
91
|
+
}
|
|
92
|
+
peekPosition() {
|
|
93
|
+
return this.scanner.peekPosition();
|
|
94
|
+
}
|
|
95
|
+
consume(token) {
|
|
96
|
+
if (this.scanner.next().isNotType(token)) {
|
|
97
|
+
throw new Error(this.errorMessage(`Parsing ${JSON.stringify(token)}`));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
check(token) {
|
|
101
|
+
const next = this.scanner.peek();
|
|
102
|
+
if (next.isType(token)) {
|
|
103
|
+
this.scanner.next();
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
checkAndGetValue(token) {
|
|
109
|
+
const next = this.scanner.peek();
|
|
110
|
+
if (next.isType(token)) {
|
|
111
|
+
this.scanner.next();
|
|
112
|
+
return next.value;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
checkValue(value) {
|
|
117
|
+
const next = this.scanner.peek();
|
|
118
|
+
if (next.value == value) {
|
|
119
|
+
this.scanner.next();
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
expect(token) {
|
|
125
|
+
const current = this.scanner.next();
|
|
126
|
+
if (current.isNotType(token)) {
|
|
127
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${JSON.stringify(token)}, current is ${JSON.stringify(current)}`));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
expectAndGetValue(token) {
|
|
131
|
+
const current = this.scanner.next();
|
|
132
|
+
if (current.isNotType(token)) {
|
|
133
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${JSON.stringify(token)}, current is ${JSON.stringify(current)}`));
|
|
134
|
+
}
|
|
135
|
+
return current.getValue();
|
|
136
|
+
}
|
|
137
|
+
checkInOrOf() {
|
|
138
|
+
if (this.check(Token.IN)) {
|
|
139
|
+
return 'IN';
|
|
140
|
+
}
|
|
141
|
+
else if (this.checkValue(OfNode)) {
|
|
142
|
+
return 'OF';
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
peekInOrOf() {
|
|
147
|
+
var next = this.peek();
|
|
148
|
+
if (next.isType(Token.IN)) {
|
|
149
|
+
return 'IN';
|
|
150
|
+
}
|
|
151
|
+
else if (next.value === OfNode) {
|
|
152
|
+
return 'OF';
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
isArguments(name) {
|
|
157
|
+
return name instanceof Identifier && name.getName() === 'arguments';
|
|
158
|
+
}
|
|
159
|
+
isEval(name) {
|
|
160
|
+
return name instanceof Identifier && name.getName() === 'eval';
|
|
161
|
+
}
|
|
162
|
+
isEvalOrArguments(name) {
|
|
163
|
+
return name instanceof Identifier && (name.getName() === 'eval' || name.getName() === 'arguments');
|
|
164
|
+
}
|
|
165
|
+
isNextLetKeyword() {
|
|
166
|
+
if (this.peek().isNotType(Token.LET)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const nextNextToken = this.peekAhead().token;
|
|
170
|
+
switch (nextNextToken) {
|
|
171
|
+
case Token.LBRACE:
|
|
172
|
+
case Token.LBRACK:
|
|
173
|
+
case Token.IDENTIFIER:
|
|
174
|
+
case Token.STATIC:
|
|
175
|
+
case Token.LET: // `let let;` is disallowed by static semantics, but the
|
|
176
|
+
// token must be first interpreted as a keyword in order
|
|
177
|
+
// for those semantics to apply. This ensures that ASI is
|
|
178
|
+
// not honored when a LineTerminator separates the
|
|
179
|
+
// tokens.
|
|
180
|
+
case Token.YIELD:
|
|
181
|
+
case Token.AWAIT:
|
|
182
|
+
case Token.GET:
|
|
183
|
+
case Token.SET:
|
|
184
|
+
case Token.ASYNC:
|
|
185
|
+
return true;
|
|
186
|
+
default:
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
isIdentifier(expression) {
|
|
191
|
+
return expression instanceof Identifier;
|
|
192
|
+
}
|
|
193
|
+
markParenthesized(expression) {
|
|
194
|
+
Reflect.set(expression, 'parenthesized', true);
|
|
195
|
+
}
|
|
196
|
+
clearParenthesized(expression) {
|
|
197
|
+
Reflect.deleteProperty(expression, 'parenthesized');
|
|
198
|
+
}
|
|
199
|
+
isParenthesized(expression) {
|
|
200
|
+
return Reflect.get(expression, 'parenthesized') === true;
|
|
201
|
+
}
|
|
202
|
+
isAssignableIdentifier(expression) {
|
|
203
|
+
// return expression instanceof AssignmentNode;
|
|
204
|
+
if (!(expression instanceof Identifier)) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
if (isStrict(this.languageMode) && this.isEvalOrArguments(expression)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
isPattern(expression) {
|
|
213
|
+
return expression instanceof ObjectExpression || expression instanceof ArrayExpression;
|
|
214
|
+
}
|
|
215
|
+
isProperty(expression) {
|
|
216
|
+
return expression instanceof Property || expression instanceof MemberExpression;
|
|
217
|
+
}
|
|
218
|
+
isCallNew(expression) {
|
|
219
|
+
return expression instanceof NewExpression;
|
|
220
|
+
}
|
|
221
|
+
isCall(expression) {
|
|
222
|
+
return expression instanceof CallExpression;
|
|
223
|
+
}
|
|
224
|
+
isEmptyStatement(expression) {
|
|
225
|
+
return expression instanceof EmptyStatement;
|
|
226
|
+
}
|
|
227
|
+
isValidReferenceExpression(expression) {
|
|
228
|
+
return this.isAssignableIdentifier(expression) || this.isProperty(expression);
|
|
229
|
+
}
|
|
230
|
+
expectSemicolon() {
|
|
231
|
+
const tok = this.peek();
|
|
232
|
+
if (tok.isType(Token.SEMICOLON)) {
|
|
233
|
+
this.next();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (this.scanner.hasLineTerminatorBeforeNext() || Token.isAutoSemicolon(tok.token)) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (this.scanner.currentToken().isType(Token.AWAIT) && !isAsyncFunction(this.functionKind)) {
|
|
240
|
+
throw new Error(this.errorMessage(`Await Not In Async Context/Function`));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
peekAnyIdentifier() {
|
|
244
|
+
return Token.isAnyIdentifier(this.peek().token);
|
|
245
|
+
}
|
|
246
|
+
expectContextualKeyword(keyword) {
|
|
247
|
+
const current = this.scanner.next();
|
|
248
|
+
if (!current.test((token, value) => Token.IDENTIFIER.equal(token) && keyword === value?.toString())) {
|
|
249
|
+
throw new Error(this.errorMessage(`Unexpected Token: current Token is ${JSON.stringify(current)}`));
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
checkContextualKeyword(keyword) {
|
|
254
|
+
const next = this.scanner.peek();
|
|
255
|
+
if (next.test((token, value) => Token.IDENTIFIER.equal(token) && keyword === value?.toString())) {
|
|
256
|
+
this.scanner.next();
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
peekContextualKeyword(keyword) {
|
|
262
|
+
const next = this.scanner.peek();
|
|
263
|
+
return next.test((token, value) => Token.IDENTIFIER.equal(token) && keyword === value?.toString());
|
|
264
|
+
}
|
|
265
|
+
methodKindFor(isStatic, flag) {
|
|
266
|
+
return functionKindForImpl(isStatic ? SubFunctionKind.StaticMethod : SubFunctionKind.NonStaticMethod, flag);
|
|
267
|
+
}
|
|
268
|
+
isGenerator() {
|
|
269
|
+
return isGeneratorFunction(this.functionKind);
|
|
270
|
+
}
|
|
271
|
+
isAsyncFunction() {
|
|
272
|
+
return isAsyncFunction(this.functionKind);
|
|
273
|
+
}
|
|
274
|
+
is_async_function() {
|
|
275
|
+
return isAsyncFunction(this.functionKind);
|
|
276
|
+
}
|
|
277
|
+
is_async_generator() {
|
|
278
|
+
return isAsyncGeneratorFunction(this.functionKind);
|
|
279
|
+
}
|
|
280
|
+
is_resumable() {
|
|
281
|
+
return isResumableFunction(this.functionKind);
|
|
282
|
+
}
|
|
283
|
+
isAwaitAllowed() {
|
|
284
|
+
return this.isAsyncFunction() || isModule(this.functionKind);
|
|
285
|
+
}
|
|
286
|
+
isAwaitAsIdentifierDisallowed() {
|
|
287
|
+
return isStrict(this.languageMode) ||
|
|
288
|
+
isAwaitAsIdentifierDisallowed(this.functionKind);
|
|
289
|
+
}
|
|
290
|
+
shouldBanArguments() {
|
|
291
|
+
return isClassMembersInitializerFunction(this.functionKind);
|
|
292
|
+
}
|
|
293
|
+
errorMessage(message) {
|
|
294
|
+
return this.scanner.createError(message);
|
|
295
|
+
}
|
|
296
|
+
reportErrorMessage(message) {
|
|
297
|
+
console.error(this.scanner.createError(message));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
export class JavaScriptInlineParser extends AbstractParser {
|
|
301
|
+
static parse(source, { mode, acceptIN } = {}) {
|
|
302
|
+
mode ?? (mode = LanguageMode.Strict);
|
|
303
|
+
const stream = (typeof source === 'string')
|
|
304
|
+
? TokenStream.getTokenStream(source, mode)
|
|
305
|
+
: Array.isArray(source) ? TokenStream.getTokenStream(source) : source;
|
|
306
|
+
acceptIN ?? (acceptIN = false);
|
|
307
|
+
const parser = new JavaScriptInlineParser(stream, acceptIN);
|
|
308
|
+
return parser.scan();
|
|
309
|
+
}
|
|
310
|
+
constructor(scanner, acceptIN) {
|
|
311
|
+
super(scanner, acceptIN);
|
|
312
|
+
}
|
|
313
|
+
scan() {
|
|
314
|
+
const list = this.parseStatementList(Token.EOS);
|
|
315
|
+
if (list.length === 1) {
|
|
316
|
+
return list[0];
|
|
317
|
+
}
|
|
318
|
+
return new ExpressionStatement(list);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Statement ::
|
|
322
|
+
* Block
|
|
323
|
+
* VariableStatement
|
|
324
|
+
* EmptyStatement
|
|
325
|
+
* ExpressionStatement
|
|
326
|
+
* IfStatement
|
|
327
|
+
* IterationStatement
|
|
328
|
+
* ContinueStatement
|
|
329
|
+
* BreakStatement
|
|
330
|
+
* ReturnStatement
|
|
331
|
+
* WithStatement
|
|
332
|
+
* LabelledStatement
|
|
333
|
+
* SwitchStatement
|
|
334
|
+
* ThrowStatement
|
|
335
|
+
* TryStatement
|
|
336
|
+
* DebuggerStatement
|
|
337
|
+
*/
|
|
338
|
+
parseStatement(allowFunction = AllowLabelledFunctionStatement.DisallowLabelledFunctionStatement) {
|
|
339
|
+
switch (this.peek().token) {
|
|
340
|
+
case Token.LBRACE:
|
|
341
|
+
return this.parseBlock();
|
|
342
|
+
case Token.SEMICOLON:
|
|
343
|
+
this.consume(Token.SEMICOLON);
|
|
344
|
+
return EmptyStatement.INSTANCE;
|
|
345
|
+
case Token.IF:
|
|
346
|
+
return this.parseIfStatement();
|
|
347
|
+
case Token.DO:
|
|
348
|
+
return this.parseDoWhileStatement();
|
|
349
|
+
case Token.WHILE:
|
|
350
|
+
return this.parseWhileStatement();
|
|
351
|
+
case Token.FOR:
|
|
352
|
+
if (this.isAwaitAllowed() && this.peekAhead().isType(Token.AWAIT)) {
|
|
353
|
+
return this.parseForAwaitStatement();
|
|
354
|
+
}
|
|
355
|
+
return this.parseForStatement();
|
|
356
|
+
case Token.CONTINUE:
|
|
357
|
+
return this.parseContinueStatement();
|
|
358
|
+
case Token.BREAK:
|
|
359
|
+
return this.parseBreakStatement();
|
|
360
|
+
case Token.RETURN:
|
|
361
|
+
return this.parseReturnStatement();
|
|
362
|
+
case Token.THROW:
|
|
363
|
+
return this.parseThrowStatement();
|
|
364
|
+
case Token.TRY:
|
|
365
|
+
return this.parseTryStatement();
|
|
366
|
+
case Token.SWITCH:
|
|
367
|
+
return this.parseSwitchStatement();
|
|
368
|
+
case Token.FUNCTION:
|
|
369
|
+
throw new SyntaxError(this.errorMessage(`FunctionDeclaration only allowed as a StatementListItem not in an arbitrary Statement position.`));
|
|
370
|
+
case Token.DEBUGGER:
|
|
371
|
+
return this.parseDebuggerStatement();
|
|
372
|
+
case Token.VAR:
|
|
373
|
+
return this.parseVariableDeclarations(VariableDeclarationContext.Statement);
|
|
374
|
+
case Token.ASYNC:
|
|
375
|
+
if (!this.scanner.hasLineTerminatorAfterNext() && this.peekAhead().isType(Token.FUNCTION)) {
|
|
376
|
+
throw new SyntaxError(this.errorMessage(`async function in single statement context.`));
|
|
377
|
+
}
|
|
378
|
+
default:
|
|
379
|
+
return this.parseExpressionOrLabelledStatement(allowFunction);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
parseDebuggerStatement() {
|
|
383
|
+
this.consume(Token.DEBUGGER);
|
|
384
|
+
this.expectSemicolon();
|
|
385
|
+
return DebuggerStatement.INSTANCE;
|
|
386
|
+
}
|
|
387
|
+
parseTryStatement() {
|
|
388
|
+
// TryStatement ::
|
|
389
|
+
// 'try' Block Catch
|
|
390
|
+
// 'try' Block Finally
|
|
391
|
+
// 'try' Block Catch Finally
|
|
392
|
+
//
|
|
393
|
+
// Catch ::
|
|
394
|
+
// 'catch' '(' Identifier ')' Block
|
|
395
|
+
//
|
|
396
|
+
// Finally ::
|
|
397
|
+
// 'finally' Block
|
|
398
|
+
this.consume(Token.TRY);
|
|
399
|
+
const tryBlock = this.parseBlock();
|
|
400
|
+
let peek = this.peek();
|
|
401
|
+
if (peek.isNotType(Token.CATCH) && peek.isNotType(Token.FINALLY)) {
|
|
402
|
+
throw new Error(this.errorMessage(`Uncaught SyntaxError: Missing catch or finally after try`));
|
|
403
|
+
}
|
|
404
|
+
let catchBlock;
|
|
405
|
+
if (this.check(Token.CATCH)) {
|
|
406
|
+
let identifier;
|
|
407
|
+
const hasBinding = this.check(Token.LPAREN);
|
|
408
|
+
if (hasBinding) {
|
|
409
|
+
if (this.peekAnyIdentifier()) {
|
|
410
|
+
identifier = this.parseNonRestrictedIdentifier();
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
identifier = this.parseBindingPattern(true);
|
|
414
|
+
}
|
|
415
|
+
this.expect(Token.RPAREN);
|
|
416
|
+
}
|
|
417
|
+
const block = this.parseBlock();
|
|
418
|
+
catchBlock = new CatchClauseNode(block, identifier);
|
|
419
|
+
}
|
|
420
|
+
let finallyBlock;
|
|
421
|
+
if (this.check(Token.FINALLY)) {
|
|
422
|
+
finallyBlock = this.parseBlock();
|
|
423
|
+
}
|
|
424
|
+
return new TryCatchNode(tryBlock, catchBlock, finallyBlock);
|
|
425
|
+
}
|
|
426
|
+
parseNonRestrictedIdentifier() {
|
|
427
|
+
const result = this.parseIdentifier();
|
|
428
|
+
if (isStrict(this.languageMode) && this.isEvalOrArguments(result)) {
|
|
429
|
+
throw new SyntaxError(this.errorMessage('Strict Eval/Arguments '));
|
|
430
|
+
}
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
parseBlock() {
|
|
434
|
+
this.expect(Token.LBRACE);
|
|
435
|
+
const statements = [];
|
|
436
|
+
const block = new BlockStatement(statements);
|
|
437
|
+
while (this.peek().isNotType(Token.RBRACE)) {
|
|
438
|
+
const stat = this.parseStatementListItem();
|
|
439
|
+
if (!stat) {
|
|
440
|
+
return block;
|
|
441
|
+
}
|
|
442
|
+
else if (stat instanceof EmptyStatement) {
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
statements.push(stat);
|
|
446
|
+
}
|
|
447
|
+
this.expect(Token.RBRACE);
|
|
448
|
+
return block;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* ECMA 262 6th Edition
|
|
452
|
+
* StatementListItem[Yield, Return] :
|
|
453
|
+
* Statement[?Yield, ?Return]
|
|
454
|
+
* Declaration[?Yield]
|
|
455
|
+
* //
|
|
456
|
+
* Declaration[Yield] :
|
|
457
|
+
* HoistableDeclaration[?Yield]
|
|
458
|
+
* ClassDeclaration[?Yield]
|
|
459
|
+
* LexicalDeclaration[In, ?Yield]
|
|
460
|
+
* //
|
|
461
|
+
* HoistableDeclaration[Yield, Default] :
|
|
462
|
+
* FunctionDeclaration[?Yield, ?Default]
|
|
463
|
+
* GeneratorDeclaration[?Yield, ?Default]
|
|
464
|
+
* //
|
|
465
|
+
* LexicalDeclaration[In, Yield] :
|
|
466
|
+
* LetOrConst BindingList[?In, ?Yield] ;
|
|
467
|
+
*/
|
|
468
|
+
parseStatementListItem() {
|
|
469
|
+
switch (this.peek().token) {
|
|
470
|
+
case Token.FUNCTION:
|
|
471
|
+
return this.parseHoistableDeclaration(undefined, false);
|
|
472
|
+
case Token.CLASS:
|
|
473
|
+
this.consume(Token.CLASS);
|
|
474
|
+
return this.parseClassDeclaration(undefined, false);
|
|
475
|
+
case Token.VAR:
|
|
476
|
+
case Token.CONST:
|
|
477
|
+
return this.parseVariableDeclarations(VariableDeclarationContext.StatementListItem);
|
|
478
|
+
case Token.LET:
|
|
479
|
+
if (this.isNextLetKeyword()) {
|
|
480
|
+
return this.parseVariableDeclarations(VariableDeclarationContext.StatementListItem);
|
|
481
|
+
}
|
|
482
|
+
break;
|
|
483
|
+
case Token.ASYNC:
|
|
484
|
+
if (this.peekAhead().isType(Token.FUNCTION) && !this.scanner.hasLineTerminatorAfterNext()) {
|
|
485
|
+
this.consume(Token.ASYNC);
|
|
486
|
+
return this.parseAsyncFunctionDeclaration(undefined, false);
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
489
|
+
default:
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
return this.parseStatement(AllowLabelledFunctionStatement.AllowLabelledFunctionStatement);
|
|
493
|
+
}
|
|
494
|
+
parseFunctionExpression() {
|
|
495
|
+
this.consume(Token.FUNCTION);
|
|
496
|
+
const functionKind = this.check(Token.MUL) ? FunctionKind.GeneratorFunction : FunctionKind.NormalFunction;
|
|
497
|
+
let name;
|
|
498
|
+
let functionSyntaxKind = FunctionSyntaxKind.AnonymousExpression;
|
|
499
|
+
const peek = this.peek();
|
|
500
|
+
if (peek.isNotType(Token.LPAREN)) {
|
|
501
|
+
name = this.parseIdentifier(this.getLastFunctionKind());
|
|
502
|
+
functionSyntaxKind = FunctionSyntaxKind.NamedExpression;
|
|
503
|
+
}
|
|
504
|
+
return this.parseFunctionLiteral(functionKind, functionSyntaxKind, name);
|
|
505
|
+
}
|
|
506
|
+
parseAsyncFunctionDeclaration(names, defaultExport) {
|
|
507
|
+
// AsyncFunctionDeclaration ::
|
|
508
|
+
// async [no LineTerminator here] function BindingIdentifier[Await]
|
|
509
|
+
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
|
510
|
+
if (this.scanner.hasLineTerminatorBeforeNext()) {
|
|
511
|
+
throw new SyntaxError(this.errorMessage('Line Terminator Before `function` parsing `async function`.'));
|
|
512
|
+
}
|
|
513
|
+
this.consume(Token.FUNCTION);
|
|
514
|
+
return this.parseHoistableDeclaration01(FunctionKind.AsyncFunction, names, defaultExport);
|
|
515
|
+
}
|
|
516
|
+
parseIfStatement() {
|
|
517
|
+
this.consume(Token.IF);
|
|
518
|
+
this.consume(Token.LPAREN);
|
|
519
|
+
const condition = this.parseExpression();
|
|
520
|
+
this.consume(Token.RPAREN);
|
|
521
|
+
const thenStatement = this.parseScopedStatement();
|
|
522
|
+
let elseStatement;
|
|
523
|
+
if (this.peek().isType(Token.ELSE)) {
|
|
524
|
+
this.consume(Token.ELSE);
|
|
525
|
+
elseStatement = this.parseScopedStatement();
|
|
526
|
+
}
|
|
527
|
+
return new IfStatement(condition, thenStatement, elseStatement);
|
|
528
|
+
}
|
|
529
|
+
parseScopedStatement() {
|
|
530
|
+
if (isStrict(this.languageMode) || this.peek().isNotType(Token.FUNCTION)) {
|
|
531
|
+
return this.parseStatement();
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
return this.parseFunctionDeclaration();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
parseDoWhileStatement() {
|
|
538
|
+
// DoStatement ::
|
|
539
|
+
// 'do' Statement 'while' '(' Expression ')' ';'
|
|
540
|
+
this.consume(Token.DO);
|
|
541
|
+
const body = this.parseStatement();
|
|
542
|
+
this.expect(Token.WHILE);
|
|
543
|
+
this.expect(Token.LPAREN);
|
|
544
|
+
const condition = this.parseExpression();
|
|
545
|
+
this.expect(Token.RPAREN);
|
|
546
|
+
this.check(Token.SEMICOLON);
|
|
547
|
+
return new DoWhileNode(condition, body);
|
|
548
|
+
}
|
|
549
|
+
parseWhileStatement() {
|
|
550
|
+
// WhileStatement ::
|
|
551
|
+
// 'while' '(' Expression ')' Statement
|
|
552
|
+
this.consume(Token.WHILE);
|
|
553
|
+
this.expect(Token.LPAREN);
|
|
554
|
+
const condition = this.parseExpression();
|
|
555
|
+
this.expect(Token.RPAREN);
|
|
556
|
+
const body = this.parseStatement();
|
|
557
|
+
return new WhileNode(condition, body);
|
|
558
|
+
}
|
|
559
|
+
parseThrowStatement() {
|
|
560
|
+
// ThrowStatement ::
|
|
561
|
+
// 'throw' Expression ';'
|
|
562
|
+
this.consume(Token.THROW);
|
|
563
|
+
if (this.scanner.hasLineTerminatorBeforeNext()) {
|
|
564
|
+
throw new Error(this.scanner.createError(`New line After Throw`));
|
|
565
|
+
}
|
|
566
|
+
const exception = this.parseExpression();
|
|
567
|
+
this.expectSemicolon();
|
|
568
|
+
return new ThrowStatement(exception);
|
|
569
|
+
}
|
|
570
|
+
parseSwitchStatement() {
|
|
571
|
+
// SwitchStatement ::
|
|
572
|
+
// 'switch' '(' Expression ')' '{' CaseClause* '}'
|
|
573
|
+
// CaseClause ::
|
|
574
|
+
// 'case' Expression ':' StatementList
|
|
575
|
+
// 'default' ':' StatementList
|
|
576
|
+
this.consume(Token.SWITCH);
|
|
577
|
+
this.expect(Token.LPAREN);
|
|
578
|
+
const tag = this.parseExpression();
|
|
579
|
+
this.expect(Token.RPAREN);
|
|
580
|
+
const cases = [];
|
|
581
|
+
const switchStatement = new SwitchStatement(tag, cases);
|
|
582
|
+
let defaultSeen = false;
|
|
583
|
+
this.expect(Token.LBRACE);
|
|
584
|
+
while (this.peek().isNotType(Token.RBRACE)) {
|
|
585
|
+
const statements = [];
|
|
586
|
+
let label;
|
|
587
|
+
if (this.check(Token.CASE)) {
|
|
588
|
+
label = this.parseExpression();
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
this.expect(Token.DEFAULT);
|
|
592
|
+
if (defaultSeen) {
|
|
593
|
+
throw new Error(this.errorMessage(`Multiple Defaults In Switch`));
|
|
594
|
+
}
|
|
595
|
+
defaultSeen = true;
|
|
596
|
+
}
|
|
597
|
+
this.expect(Token.COLON);
|
|
598
|
+
while (this.peek().isNotType(Token.CASE)
|
|
599
|
+
&& this.peek().isNotType(Token.DEFAULT)
|
|
600
|
+
&& this.peek().isNotType(Token.RBRACE)) {
|
|
601
|
+
const statement = this.parseStatementListItem();
|
|
602
|
+
if (!statement || this.isEmptyStatement(statement)) {
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
statements.push(statement);
|
|
606
|
+
}
|
|
607
|
+
const block = new BlockStatement(statements);
|
|
608
|
+
const clause = defaultSeen ? new DefaultExpression(block) : new SwitchCase(label, block);
|
|
609
|
+
cases.push(clause);
|
|
610
|
+
}
|
|
611
|
+
this.expect(Token.RBRACE);
|
|
612
|
+
return switchStatement;
|
|
613
|
+
}
|
|
614
|
+
parseForStatement() {
|
|
615
|
+
// Either a standard for loop
|
|
616
|
+
// for (<init>; <cond>; <next>) { ... }
|
|
617
|
+
// or a for-each loop
|
|
618
|
+
// for (<each> of|in <iterable>) { ... }
|
|
619
|
+
//
|
|
620
|
+
// We parse a declaration/expression after the 'for (' and then read the first
|
|
621
|
+
// expression/declaration before we know if this is a for or a for-each.
|
|
622
|
+
// typename FunctionState::LoopScope loop_scope(function_state_);
|
|
623
|
+
this.consume(Token.FOR);
|
|
624
|
+
this.expect(Token.LPAREN);
|
|
625
|
+
const peek = this.peek();
|
|
626
|
+
const starts_with_let = peek.isType(Token.LET);
|
|
627
|
+
if (peek.isType(Token.CONST) || (starts_with_let && this.isNextLetKeyword())) {
|
|
628
|
+
// The initializer contains lexical declarations,
|
|
629
|
+
// so create an in-between scope.
|
|
630
|
+
// Also record whether inner functions or evals are found inside
|
|
631
|
+
// this loop, as this information is used to simplify the desugaring
|
|
632
|
+
// if none are found.
|
|
633
|
+
// typename FunctionState::FunctionOrEvalRecordingScope recording_scope(function_state_);
|
|
634
|
+
const initializer = this.parseVariableDeclarations(VariableDeclarationContext.ForStatement);
|
|
635
|
+
const forMode = this.checkInOrOf();
|
|
636
|
+
if (forMode) {
|
|
637
|
+
return this.parseForEachStatementWithDeclarations(initializer, forMode);
|
|
638
|
+
}
|
|
639
|
+
this.expect(Token.SEMICOLON);
|
|
640
|
+
// Parse the remaining code in the inner block scope since the declaration
|
|
641
|
+
// above was parsed there. We'll finalize the unnecessary outer block scope
|
|
642
|
+
// after parsing the rest of the loop.
|
|
643
|
+
return this.parseStandardForLoopWithLexicalDeclarations(initializer);
|
|
644
|
+
}
|
|
645
|
+
let initializer;
|
|
646
|
+
if (peek.isType(Token.VAR)) {
|
|
647
|
+
initializer = this.parseVariableDeclarations(VariableDeclarationContext.ForStatement);
|
|
648
|
+
// ParseVariableDeclarations(kForStatement, & for_info.parsing_result,& for_info.bound_names);
|
|
649
|
+
// DCHECK_EQ(for_info.parsing_result.descriptor.mode, VariableMode:: kVar);
|
|
650
|
+
// for_info.position = scanner() -> location().beg_pos;
|
|
651
|
+
const forMode = this.checkInOrOf();
|
|
652
|
+
if (forMode) {
|
|
653
|
+
return this.parseForEachStatementWithDeclarations(initializer, forMode);
|
|
654
|
+
}
|
|
655
|
+
// init = impl() -> BuildInitializationBlock(& for_info.parsing_result);
|
|
656
|
+
}
|
|
657
|
+
else if (this.peek().isNotType(Token.SEMICOLON)) {
|
|
658
|
+
// The initializer does not contain declarations.
|
|
659
|
+
this.setAcceptIN(false);
|
|
660
|
+
initializer = this.parseExpressionCoverGrammar();
|
|
661
|
+
this.restoreAcceptIN();
|
|
662
|
+
// ExpressionParsingScope parsing_scope(impl());
|
|
663
|
+
// AcceptINScope scope(this, false);
|
|
664
|
+
// `for (async of` is disallowed but `for (async.x of` is allowed, so
|
|
665
|
+
// check if the token is ASYNC after parsing the expression.
|
|
666
|
+
// Initializer is reference followed by in/of.
|
|
667
|
+
const expression_is_async = this.current().isType(Token.ASYNC);
|
|
668
|
+
const forMode = this.checkInOrOf();
|
|
669
|
+
if (forMode) {
|
|
670
|
+
if (forMode === 'OF' && starts_with_let || expression_is_async) {
|
|
671
|
+
throw new SyntaxError(this.errorMessage(starts_with_let ? 'For Of Let' : 'For Of Async'));
|
|
672
|
+
}
|
|
673
|
+
return this.parseForEachStatementWithoutDeclarations(initializer, forMode);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
this.expect(Token.SEMICOLON);
|
|
677
|
+
return this.parseStandardForLoop(initializer);
|
|
678
|
+
}
|
|
679
|
+
parseStandardForLoopWithLexicalDeclarations(initializer) {
|
|
680
|
+
// The condition and the next statement of the for loop must be parsed
|
|
681
|
+
// in a new scope.
|
|
682
|
+
return this.parseStandardForLoop(initializer);
|
|
683
|
+
}
|
|
684
|
+
parseForEachStatementWithDeclarations(initializer, forMode) {
|
|
685
|
+
// Just one declaration followed by in/of.
|
|
686
|
+
if (initializer.getDeclarations().length != 1) {
|
|
687
|
+
throw new SyntaxError(this.errorMessage('For In/Of loop Multi Bindings'));
|
|
688
|
+
}
|
|
689
|
+
return this.parseForEachStatementWithoutDeclarations(initializer, forMode);
|
|
690
|
+
}
|
|
691
|
+
parseForEachStatementWithoutDeclarations(initializer, forMode) {
|
|
692
|
+
let enumerable;
|
|
693
|
+
if (forMode == 'OF') {
|
|
694
|
+
this.setAcceptIN(true);
|
|
695
|
+
enumerable = this.parseAssignmentExpression();
|
|
696
|
+
this.restoreAcceptIN();
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
enumerable = this.parseExpression();
|
|
700
|
+
}
|
|
701
|
+
this.expect(Token.RPAREN);
|
|
702
|
+
const body = this.parseStatement();
|
|
703
|
+
if (forMode === 'OF') {
|
|
704
|
+
return new ForOfNode(initializer, enumerable, body);
|
|
705
|
+
}
|
|
706
|
+
else if (forMode === 'IN') {
|
|
707
|
+
return new ForInNode(initializer, enumerable, body);
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
throw new Error(this.errorMessage(`parsing for loop: ${this.position()}`));
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
parseStandardForLoop(initializer) {
|
|
714
|
+
// CheckStackOverflow();
|
|
715
|
+
// ForStatementT loop = factory() -> NewForStatement(stmt_pos);
|
|
716
|
+
// Target target(this, loop, labels, own_labels, Target:: TARGET_FOR_ANONYMOUS);
|
|
717
|
+
let cond = new EmptyStatement();
|
|
718
|
+
if (this.peek().isNotType(Token.SEMICOLON)) {
|
|
719
|
+
cond = this.parseExpression();
|
|
720
|
+
}
|
|
721
|
+
this.expect(Token.SEMICOLON);
|
|
722
|
+
let next = new EmptyStatement();
|
|
723
|
+
if (this.peek().isNotType(Token.RPAREN)) {
|
|
724
|
+
next = this.parseExpression();
|
|
725
|
+
}
|
|
726
|
+
this.expect(Token.RPAREN);
|
|
727
|
+
const body = this.parseStatement();
|
|
728
|
+
return new ForNode(body, initializer, cond, next);
|
|
729
|
+
}
|
|
730
|
+
parseForAwaitStatement() {
|
|
731
|
+
// for await '(' ForDeclaration of AssignmentExpression ')'
|
|
732
|
+
// Create an in-between scope for let-bound iteration variables.
|
|
733
|
+
// BlockState for_state(zone(), & scope_);
|
|
734
|
+
if (!this.isAwaitAllowed()) {
|
|
735
|
+
throw new SyntaxError(this.errorMessage('"await" is not allowed'));
|
|
736
|
+
}
|
|
737
|
+
this.expect(Token.FOR);
|
|
738
|
+
this.expect(Token.AWAIT);
|
|
739
|
+
this.expect(Token.LPAREN);
|
|
740
|
+
let hasDeclarations = false;
|
|
741
|
+
// Scope * inner_block_scope = NewScope(BLOCK_SCOPE);
|
|
742
|
+
let eachVariable;
|
|
743
|
+
let peek = this.peek();
|
|
744
|
+
let startsWithLet = peek.isType(Token.LET);
|
|
745
|
+
if (peek.isType(Token.VAR) || peek.isType(Token.CONST)
|
|
746
|
+
|| (startsWithLet && this.isNextLetKeyword())) {
|
|
747
|
+
// The initializer contains declarations
|
|
748
|
+
// 'for' 'await' '(' ForDeclaration 'of' AssignmentExpression ')'
|
|
749
|
+
// Statement
|
|
750
|
+
// 'for' 'await' '(' 'var' ForBinding 'of' AssignmentExpression ')'
|
|
751
|
+
// Statement
|
|
752
|
+
hasDeclarations = true;
|
|
753
|
+
const initializer = this.parseVariableDeclarations(VariableDeclarationContext.ForStatement);
|
|
754
|
+
if (initializer.getDeclarations().length != 1) {
|
|
755
|
+
throw new SyntaxError(this.errorMessage('For In/Of Loop MultiBindings, "for-await-of"'));
|
|
756
|
+
}
|
|
757
|
+
eachVariable = initializer;
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
// The initializer does not contain declarations.
|
|
761
|
+
// 'for' 'await' '(' LeftHandSideExpression 'of' AssignmentExpression ')'
|
|
762
|
+
// Statement
|
|
763
|
+
if (startsWithLet) {
|
|
764
|
+
throw new SyntaxError(this.errorMessage('The initializer does not contain declarations, For Of Let, "for-await-of"'));
|
|
765
|
+
}
|
|
766
|
+
eachVariable = this.parseLeftHandSideExpression();
|
|
767
|
+
}
|
|
768
|
+
this.expectContextualKeyword('of');
|
|
769
|
+
this.setAcceptIN(true);
|
|
770
|
+
const iterable = this.parseAssignmentExpression();
|
|
771
|
+
this.restoreAcceptIN();
|
|
772
|
+
this.expect(Token.RPAREN);
|
|
773
|
+
const body = this.parseStatement();
|
|
774
|
+
return new ForAwaitOfNode(eachVariable, iterable, body);
|
|
775
|
+
}
|
|
776
|
+
parseVariableDeclarations(varContext) {
|
|
777
|
+
// VariableDeclarations ::
|
|
778
|
+
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
|
|
779
|
+
// var converted into ==> 'let' by parser
|
|
780
|
+
let mode;
|
|
781
|
+
const token = this.peek().token;
|
|
782
|
+
switch (token) {
|
|
783
|
+
case Token.CONST:
|
|
784
|
+
this.consume(token);
|
|
785
|
+
mode = 'const';
|
|
786
|
+
break;
|
|
787
|
+
case Token.VAR:
|
|
788
|
+
this.consume(token);
|
|
789
|
+
mode = 'var';
|
|
790
|
+
break;
|
|
791
|
+
case Token.LET:
|
|
792
|
+
default:
|
|
793
|
+
this.consume(token);
|
|
794
|
+
mode = 'let';
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
const variables = [];
|
|
798
|
+
do {
|
|
799
|
+
let name;
|
|
800
|
+
let value;
|
|
801
|
+
// Check for an identifier first, so that we can elide the pattern in cases
|
|
802
|
+
// where there is no initializer (and so no proxy needs to be created).
|
|
803
|
+
if (Token.isAnyIdentifier(this.peek().token)) {
|
|
804
|
+
name = this.parseAndClassifyIdentifier(this.next());
|
|
805
|
+
if (isStrict(this.languageMode) && this.isEvalOrArguments(name)) {
|
|
806
|
+
throw new Error(this.errorMessage(`Strict Eval Arguments`));
|
|
807
|
+
}
|
|
808
|
+
// if (this.peekInOrOf()) {
|
|
809
|
+
// // // Assignments need the variable expression for the assignment LHS, and
|
|
810
|
+
// // // for of/in will need it later, so create the expression now.
|
|
811
|
+
// }
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
name = this.parseBindingPattern(true);
|
|
815
|
+
}
|
|
816
|
+
if (this.check(Token.ASSIGN)) {
|
|
817
|
+
this.setAcceptIN(varContext !== VariableDeclarationContext.ForStatement);
|
|
818
|
+
value = this.parseAssignmentExpression();
|
|
819
|
+
this.restoreAcceptIN();
|
|
820
|
+
}
|
|
821
|
+
else if (!this.peekInOrOf()) {
|
|
822
|
+
// ES6 'const' and binding patterns require initializers.
|
|
823
|
+
if (mode === 'const' && (name === undefined || value === undefined)) {
|
|
824
|
+
throw new Error(this.errorMessage(`Declaration Missing Initializer`));
|
|
825
|
+
}
|
|
826
|
+
// value = undefined;
|
|
827
|
+
}
|
|
828
|
+
variables.push(new VariableDeclarator(name, value));
|
|
829
|
+
} while (this.check(Token.COMMA));
|
|
830
|
+
return new VariableDeclarationNode(variables, mode);
|
|
831
|
+
}
|
|
832
|
+
parseBindingPattern(isPattern) {
|
|
833
|
+
// Pattern ::
|
|
834
|
+
// Identifier
|
|
835
|
+
// ArrayLiteral
|
|
836
|
+
// ObjectLiteral
|
|
837
|
+
const token = this.peek().token;
|
|
838
|
+
if (Token.isAnyIdentifier(token)) {
|
|
839
|
+
const name = this.parseAndClassifyIdentifier(this.next());
|
|
840
|
+
if (isStrict(this.languageMode) && this.isEvalOrArguments(name)) {
|
|
841
|
+
throw new Error(this.errorMessage(`Strict Eval Arguments`));
|
|
842
|
+
}
|
|
843
|
+
return name;
|
|
844
|
+
}
|
|
845
|
+
if (token == Token.LBRACK) {
|
|
846
|
+
return this.parseArrayLiteral(isPattern);
|
|
847
|
+
}
|
|
848
|
+
else if (token == Token.LBRACE) {
|
|
849
|
+
return this.parseObjectLiteral(isPattern);
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${this.next().getValue()}`));
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
parseAndClassifyIdentifier(next) {
|
|
856
|
+
// Updates made here must be reflected on ClassifyPropertyIdentifier.
|
|
857
|
+
if (Token.isInRangeIdentifierAndAsync(next.token)) {
|
|
858
|
+
const name = next.getValue();
|
|
859
|
+
if (this.isArguments(name) && this.shouldBanArguments()) {
|
|
860
|
+
throw new SyntaxError(this.errorMessage('Arguments Disallowed In Initializer And Static Block'));
|
|
861
|
+
}
|
|
862
|
+
return name;
|
|
863
|
+
}
|
|
864
|
+
if (!Token.isValidIdentifier(next.token, this.languageMode, this.isGenerator(), this.isAwaitAsIdentifierDisallowed())) {
|
|
865
|
+
throw new SyntaxError(this.errorMessage('Invalid Identifier'));
|
|
866
|
+
}
|
|
867
|
+
if (next.isType(Token.AWAIT)) {
|
|
868
|
+
return next.getValue();
|
|
869
|
+
}
|
|
870
|
+
return next.getValue();
|
|
871
|
+
}
|
|
872
|
+
parseContinueStatement() {
|
|
873
|
+
// ContinueStatement ::
|
|
874
|
+
// 'continue' ';'
|
|
875
|
+
// Identifier? is not supported
|
|
876
|
+
this.consume(Token.CONTINUE);
|
|
877
|
+
let label;
|
|
878
|
+
if (!this.scanner.hasLineTerminatorBeforeNext() &&
|
|
879
|
+
!Token.isAutoSemicolon(this.peek().token)) {
|
|
880
|
+
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
|
881
|
+
label = this.parseIdentifier();
|
|
882
|
+
}
|
|
883
|
+
this.expectSemicolon();
|
|
884
|
+
return label ? new ContinueStatement(label) : ContinueStatement.CONTINUE_INSTANCE;
|
|
885
|
+
}
|
|
886
|
+
parseBreakStatement() {
|
|
887
|
+
// BreakStatement ::
|
|
888
|
+
// 'break' ';'
|
|
889
|
+
// Identifier? is not supported
|
|
890
|
+
this.consume(Token.BREAK);
|
|
891
|
+
let label;
|
|
892
|
+
if (!this.scanner.hasLineTerminatorBeforeNext() &&
|
|
893
|
+
!Token.isAutoSemicolon(this.peek().token)) {
|
|
894
|
+
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
|
895
|
+
label = this.parseIdentifier();
|
|
896
|
+
}
|
|
897
|
+
this.expectSemicolon();
|
|
898
|
+
return label ? new BreakStatement(label) : BreakStatement.BREAK_INSTANCE;
|
|
899
|
+
}
|
|
900
|
+
parseReturnStatement() {
|
|
901
|
+
// ReturnStatement ::
|
|
902
|
+
// 'return' [no line terminator] Expression? ';'
|
|
903
|
+
// Consume the return token. It is necessary to do that before
|
|
904
|
+
// reporting any errors on it, because of the way errors are
|
|
905
|
+
// reported (underlining).
|
|
906
|
+
this.consume(Token.RETURN);
|
|
907
|
+
const tokenExp = this.peek();
|
|
908
|
+
let returnValue;
|
|
909
|
+
// ExpressionT return_value = impl() -> NullExpression();
|
|
910
|
+
if (this.scanner.hasLineTerminatorBeforeNext() || Token.isAutoSemicolon(tokenExp.token)) {
|
|
911
|
+
// check if this scope is belong to 'constructor' method to return this at the end;
|
|
912
|
+
// if (this.isDerivedConstructor(this.functionKind)) {
|
|
913
|
+
// returnValue = ThisNode;
|
|
914
|
+
// }
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
returnValue = this.parseExpression();
|
|
918
|
+
}
|
|
919
|
+
this.expectSemicolon();
|
|
920
|
+
return new ReturnStatement(returnValue);
|
|
921
|
+
}
|
|
922
|
+
parseExpressionOrLabelledStatement(allowFunction) {
|
|
923
|
+
// ExpressionStatement | LabelledStatement ::
|
|
924
|
+
// Expression ';'
|
|
925
|
+
// Identifier ':' Statement
|
|
926
|
+
//
|
|
927
|
+
// ExpressionStatement[Yield] :
|
|
928
|
+
// [lookahead notin {{, function, class, let [}] Expression[In, ?Yield] ;
|
|
929
|
+
switch (this.peek().token) {
|
|
930
|
+
case Token.FUNCTION:
|
|
931
|
+
case Token.LBRACE:
|
|
932
|
+
throw new Error(this.errorMessage(`Unreachable state`));
|
|
933
|
+
case Token.CLASS:
|
|
934
|
+
throw new Error(this.errorMessage(`Unexpected Token ${this.next().getValue().toString()}`));
|
|
935
|
+
case Token.LET: {
|
|
936
|
+
const nextNext = this.peekAhead();
|
|
937
|
+
// "let" followed by either "[", "{" or an identifier means a lexical
|
|
938
|
+
// declaration, which should not appear here.
|
|
939
|
+
// However, ASI may insert a line break before an identifier or a brace.
|
|
940
|
+
if (nextNext.isNotType(Token.LBRACK) &&
|
|
941
|
+
((nextNext.isNotType(Token.LBRACE) && nextNext.isNotType(Token.IDENTIFIER)))) {
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
944
|
+
throw new Error(this.errorMessage(`Unexpected Lexical Declaration ${this.position()}`));
|
|
945
|
+
}
|
|
946
|
+
default:
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
const startsWithIdentifier = Token.isAnyIdentifier(this.peek().token);
|
|
950
|
+
this.setAcceptIN(true);
|
|
951
|
+
const expression = this.parseExpressionCoverGrammar();
|
|
952
|
+
if (this.peek().isType(Token.COLON) && startsWithIdentifier && this.isIdentifier(expression)) {
|
|
953
|
+
// The whole expression was a single identifier, and not, e.g.,
|
|
954
|
+
// something starting with an identifier or a parenthesized identifier.
|
|
955
|
+
// Remove the "ghost" variable that turned out to be a label from the top
|
|
956
|
+
// scope. This way, we don't try to resolve it during the scope
|
|
957
|
+
// processing.
|
|
958
|
+
this.consume(Token.COLON);
|
|
959
|
+
// ES#sec-labelled-function-declarations Labelled Function Declarations
|
|
960
|
+
if (this.peek().isType(Token.FUNCTION)
|
|
961
|
+
&& isSloppy(this.languageMode)
|
|
962
|
+
&& allowFunction == AllowLabelledFunctionStatement.AllowLabelledFunctionStatement) {
|
|
963
|
+
const result = this.parseFunctionDeclaration();
|
|
964
|
+
this.restoreAcceptIN();
|
|
965
|
+
return new LabeledStatement(expression, result);
|
|
966
|
+
}
|
|
967
|
+
const result = this.parseStatement(allowFunction);
|
|
968
|
+
this.restoreAcceptIN();
|
|
969
|
+
return new LabeledStatement(expression, result);
|
|
970
|
+
}
|
|
971
|
+
this.restoreAcceptIN();
|
|
972
|
+
// Parsed expression statement, followed by semicolon.
|
|
973
|
+
this.expectSemicolon();
|
|
974
|
+
return expression;
|
|
975
|
+
}
|
|
976
|
+
parseExpression() {
|
|
977
|
+
this.setAcceptIN(true);
|
|
978
|
+
const result = this.parseExpressionCoverGrammar();
|
|
979
|
+
this.restoreAcceptIN();
|
|
980
|
+
return result;
|
|
981
|
+
}
|
|
982
|
+
parseFunctionDeclaration() {
|
|
983
|
+
this.consume(Token.FUNCTION);
|
|
984
|
+
if (this.check(Token.MUL)) {
|
|
985
|
+
throw new Error(this.errorMessage(`Error Generator In Single Statement Context`));
|
|
986
|
+
}
|
|
987
|
+
return this.parseHoistableDeclaration01(FunctionKind.NormalFunction, undefined, false);
|
|
988
|
+
}
|
|
989
|
+
parseAsyncFunctionLiteral() {
|
|
990
|
+
// AsyncFunctionLiteral ::
|
|
991
|
+
// async [no LineTerminator here] function ( FormalParameters[Await] )
|
|
992
|
+
// { AsyncFunctionBody }
|
|
993
|
+
//
|
|
994
|
+
// async [no LineTerminator here] function BindingIdentifier[Await]
|
|
995
|
+
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
|
996
|
+
if (this.current().isNotType(Token.ASYNC)) {
|
|
997
|
+
throw new SyntaxError(this.errorMessage('invalid token'));
|
|
998
|
+
}
|
|
999
|
+
this.consume(Token.FUNCTION);
|
|
1000
|
+
let name;
|
|
1001
|
+
let syntaxKind = FunctionSyntaxKind.AnonymousExpression;
|
|
1002
|
+
let flags = FunctionKind.AsyncFunction;
|
|
1003
|
+
if (this.check(Token.MUL)) {
|
|
1004
|
+
flags = FunctionKind.AsyncGeneratorFunction;
|
|
1005
|
+
}
|
|
1006
|
+
if (this.peekAnyIdentifier()) {
|
|
1007
|
+
syntaxKind = FunctionSyntaxKind.NamedExpression;
|
|
1008
|
+
name = this.parseIdentifier(this.getLastFunctionKind());
|
|
1009
|
+
}
|
|
1010
|
+
return this.parseFunctionLiteral(flags, syntaxKind, name);
|
|
1011
|
+
}
|
|
1012
|
+
parseHoistableDeclaration(names, defaultExport) {
|
|
1013
|
+
this.consume(Token.FUNCTION);
|
|
1014
|
+
let flags = FunctionKind.NormalFunction;
|
|
1015
|
+
if (this.check(Token.MUL)) {
|
|
1016
|
+
flags = FunctionKind.GeneratorFunction;
|
|
1017
|
+
}
|
|
1018
|
+
return this.parseHoistableDeclaration01(flags, names, defaultExport);
|
|
1019
|
+
}
|
|
1020
|
+
parseHoistableDeclaration01(flag, names, defaultExport) {
|
|
1021
|
+
// FunctionDeclaration ::
|
|
1022
|
+
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
|
1023
|
+
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
|
|
1024
|
+
// GeneratorDeclaration ::
|
|
1025
|
+
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
|
|
1026
|
+
// 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
|
|
1027
|
+
//
|
|
1028
|
+
// The anonymous forms are allowed iff [default_export] is true.
|
|
1029
|
+
//
|
|
1030
|
+
// 'function' and '*' (if present) have been consumed by the caller.
|
|
1031
|
+
// (FunctionType.ASYNC === flag || FunctionType.GENERATOR === flag);
|
|
1032
|
+
if ((flag & ParseFunctionFlag.IsAsync) != 0 && this.check(Token.MUL)) {
|
|
1033
|
+
// Async generator
|
|
1034
|
+
flag |= ParseFunctionFlag.IsGenerator;
|
|
1035
|
+
}
|
|
1036
|
+
let name;
|
|
1037
|
+
if (this.peek().isType(Token.LPAREN)) {
|
|
1038
|
+
if (defaultExport) {
|
|
1039
|
+
name = new Identifier('default');
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
throw new SyntaxError(this.errorMessage('Missing Function Name'));
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
else {
|
|
1046
|
+
name = this.parseIdentifier(this.getLastFunctionKind());
|
|
1047
|
+
}
|
|
1048
|
+
names?.push(name.toString());
|
|
1049
|
+
return this.parseFunctionLiteral(flag, FunctionSyntaxKind.Declaration, name);
|
|
1050
|
+
}
|
|
1051
|
+
parseIdentifier(kind) {
|
|
1052
|
+
kind ?? (kind = this.functionKind);
|
|
1053
|
+
const next = this.next();
|
|
1054
|
+
if (!Token.isValidIdentifier(next.token, this.languageMode, isGeneratorFunction(kind), isAwaitAsIdentifierDisallowed(kind))) {
|
|
1055
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${next.getValue()}`));
|
|
1056
|
+
}
|
|
1057
|
+
if (next.isType(Token.IDENTIFIER)) {
|
|
1058
|
+
return next.getValue();
|
|
1059
|
+
}
|
|
1060
|
+
return this.getIdentifier();
|
|
1061
|
+
}
|
|
1062
|
+
getIdentifier() {
|
|
1063
|
+
const current = this.current();
|
|
1064
|
+
switch (current.token) {
|
|
1065
|
+
case Token.AWAIT:
|
|
1066
|
+
return AwaitIdentifier;
|
|
1067
|
+
case Token.ASYNC:
|
|
1068
|
+
return AsyncIdentifier;
|
|
1069
|
+
case Token.IDENTIFIER:
|
|
1070
|
+
case Token.PRIVATE_NAME:
|
|
1071
|
+
return current.getValue();
|
|
1072
|
+
default:
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
const name = current.getValue().toString();
|
|
1076
|
+
if (name == 'constructor') {
|
|
1077
|
+
return ConstructorIdentifier;
|
|
1078
|
+
}
|
|
1079
|
+
if (name == 'name') {
|
|
1080
|
+
return NameIdentifier;
|
|
1081
|
+
}
|
|
1082
|
+
if (name == 'eval') {
|
|
1083
|
+
return EvalIdentifier;
|
|
1084
|
+
}
|
|
1085
|
+
else if (name == 'arguments') {
|
|
1086
|
+
return ArgumentsIdentifier;
|
|
1087
|
+
}
|
|
1088
|
+
return current.getValue();
|
|
1089
|
+
}
|
|
1090
|
+
parseFunctionLiteral(flag, functionSyntaxKind, name) {
|
|
1091
|
+
// Function ::
|
|
1092
|
+
// '(' FormalParameterList? ')' '{' FunctionBody '}'
|
|
1093
|
+
this.setFunctionKind(flag);
|
|
1094
|
+
const functionInfo = {};
|
|
1095
|
+
this.expect(Token.LPAREN);
|
|
1096
|
+
const formals = this.parseFormalParameterList(functionInfo);
|
|
1097
|
+
this.expect(Token.RPAREN);
|
|
1098
|
+
this.expect(Token.LBRACE);
|
|
1099
|
+
this.setAcceptIN(true);
|
|
1100
|
+
const body = this.parseFunctionBody(flag, FunctionBodyType.BLOCK, functionSyntaxKind);
|
|
1101
|
+
this.restoreAcceptIN();
|
|
1102
|
+
this.restoreFunctionKind();
|
|
1103
|
+
const bodyBlock = new BlockStatement(body);
|
|
1104
|
+
if (name) {
|
|
1105
|
+
return new FunctionDeclaration(formals, bodyBlock, isAsyncFunction(flag), isGeneratorFunction(flag), name);
|
|
1106
|
+
}
|
|
1107
|
+
return new FunctionExpression(formals, bodyBlock, isAsyncFunction(flag), isGeneratorFunction(flag));
|
|
1108
|
+
}
|
|
1109
|
+
parseFunctionBody(kind, bodyType, functionSyntaxKind) {
|
|
1110
|
+
// Building the parameter initialization block declares the parameters.
|
|
1111
|
+
// TODO(verwaest): Rely on ArrowHeadParsingScope instead.
|
|
1112
|
+
let innerBody;
|
|
1113
|
+
if (bodyType == FunctionBodyType.EXPRESSION) {
|
|
1114
|
+
innerBody = this.parseAssignmentExpression();
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
// DCHECK(accept_IN_);
|
|
1118
|
+
// DCHECK_EQ(FunctionBodyType:: kBlock, body_type);
|
|
1119
|
+
// If we are parsing the source as if it is wrapped in a function, the
|
|
1120
|
+
// source ends without a closing brace.
|
|
1121
|
+
const closing_token = functionSyntaxKind == FunctionSyntaxKind.Wrapped ? Token.EOS : Token.RBRACE;
|
|
1122
|
+
if (isAsyncGeneratorFunction(kind)) {
|
|
1123
|
+
innerBody = this.parseAndRewriteAsyncGeneratorFunctionBody(kind);
|
|
1124
|
+
}
|
|
1125
|
+
else if (isGeneratorFunction(kind)) {
|
|
1126
|
+
innerBody = this.parseAndRewriteGeneratorFunctionBody(kind);
|
|
1127
|
+
}
|
|
1128
|
+
else if (isAsyncFunction(kind)) {
|
|
1129
|
+
innerBody = this.parseAsyncFunctionBody();
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
innerBody = this.parseStatementList(closing_token);
|
|
1133
|
+
}
|
|
1134
|
+
this.expect(closing_token);
|
|
1135
|
+
}
|
|
1136
|
+
return innerBody;
|
|
1137
|
+
}
|
|
1138
|
+
parseAndRewriteAsyncGeneratorFunctionBody(kind) {
|
|
1139
|
+
return this.parseStatementList(Token.RBRACE);
|
|
1140
|
+
}
|
|
1141
|
+
parseAndRewriteGeneratorFunctionBody(kind) {
|
|
1142
|
+
return this.parseStatementList(Token.RBRACE);
|
|
1143
|
+
}
|
|
1144
|
+
parseAsyncFunctionBody() {
|
|
1145
|
+
return this.parseStatementList(Token.RBRACE);
|
|
1146
|
+
}
|
|
1147
|
+
parseStatementList(endToken) {
|
|
1148
|
+
// StatementList ::
|
|
1149
|
+
// (StatementListItem)* <end_token>
|
|
1150
|
+
if (this.peek().test((token, value) => Token.STRING === token && 'use strict' === value.getValue())) {
|
|
1151
|
+
this.languageMode = LanguageMode.Strict;
|
|
1152
|
+
}
|
|
1153
|
+
const list = [];
|
|
1154
|
+
while (this.peek().isNotType(endToken)) {
|
|
1155
|
+
const stat = this.parseStatementListItem();
|
|
1156
|
+
if (!stat) {
|
|
1157
|
+
break;
|
|
1158
|
+
}
|
|
1159
|
+
if (this.isEmptyStatement(stat)) {
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
list.push(stat);
|
|
1163
|
+
}
|
|
1164
|
+
return list;
|
|
1165
|
+
}
|
|
1166
|
+
parseFormalParameterList(functionInfo) {
|
|
1167
|
+
// FormalParameters[Yield] :
|
|
1168
|
+
// [empty]
|
|
1169
|
+
// FunctionRestParameter[?Yield]
|
|
1170
|
+
// FormalParameterList[?Yield]
|
|
1171
|
+
// FormalParameterList[?Yield] ,
|
|
1172
|
+
// FormalParameterList[?Yield] , FunctionRestParameter[?Yield]
|
|
1173
|
+
//
|
|
1174
|
+
// FormalParameterList[Yield] :
|
|
1175
|
+
// FormalParameter[?Yield]
|
|
1176
|
+
// FormalParameterList[?Yield] , FormalParameter[?Yield]
|
|
1177
|
+
const parameters = [];
|
|
1178
|
+
if (this.peek().isNotType(Token.RPAREN)) {
|
|
1179
|
+
while (true) {
|
|
1180
|
+
const param = this.parseFormalParameter(functionInfo);
|
|
1181
|
+
parameters.push(param);
|
|
1182
|
+
if (functionInfo.rest) {
|
|
1183
|
+
if (this.peek().isType(Token.COMMA)) {
|
|
1184
|
+
throw new Error(this.errorMessage(`Param After Rest`));
|
|
1185
|
+
}
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
if (!this.check(Token.COMMA))
|
|
1189
|
+
break;
|
|
1190
|
+
if (this.peek().isType(Token.RPAREN)) {
|
|
1191
|
+
// allow the trailing comma
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
return parameters;
|
|
1197
|
+
}
|
|
1198
|
+
parseFormalParameter(functionInfo) {
|
|
1199
|
+
// FormalParameter[Yield,GeneratorParameter] :
|
|
1200
|
+
// BindingElement[?Yield, ?GeneratorParameter]
|
|
1201
|
+
functionInfo.rest = this.check(Token.ELLIPSIS);
|
|
1202
|
+
let pattern = this.parseBindingPattern(true);
|
|
1203
|
+
let initializer;
|
|
1204
|
+
if (this.check(Token.ASSIGN)) {
|
|
1205
|
+
if (functionInfo.rest) {
|
|
1206
|
+
throw new Error(this.errorMessage(`Rest Default Initializer`));
|
|
1207
|
+
}
|
|
1208
|
+
this.setAcceptIN(true);
|
|
1209
|
+
const value = this.parseAssignmentExpression();
|
|
1210
|
+
this.restoreAcceptIN();
|
|
1211
|
+
initializer = new Param(pattern, value);
|
|
1212
|
+
}
|
|
1213
|
+
else {
|
|
1214
|
+
initializer = new Param(pattern);
|
|
1215
|
+
}
|
|
1216
|
+
return initializer;
|
|
1217
|
+
}
|
|
1218
|
+
parseExpressionCoverGrammar() {
|
|
1219
|
+
// Expression ::
|
|
1220
|
+
// AssignmentExpression
|
|
1221
|
+
// Expression ',' AssignmentExpression
|
|
1222
|
+
const list = [];
|
|
1223
|
+
let expression;
|
|
1224
|
+
while (true) {
|
|
1225
|
+
if (this.peek().isType(Token.ELLIPSIS)) {
|
|
1226
|
+
return this.parseArrowParametersWithRest(list);
|
|
1227
|
+
}
|
|
1228
|
+
expression = this.parseAssignmentExpressionCoverGrammar();
|
|
1229
|
+
list.push(expression);
|
|
1230
|
+
if (!this.check(Token.COMMA))
|
|
1231
|
+
break;
|
|
1232
|
+
if (this.peek().isType(Token.RPAREN) && this.peekAhead().isType(Token.ARROW)) {
|
|
1233
|
+
// a trailing comma is allowed at the end of an arrow parameter list
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if (list.length == 1)
|
|
1238
|
+
return expression;
|
|
1239
|
+
return this.expressionListToExpression(list);
|
|
1240
|
+
}
|
|
1241
|
+
parseArrowParametersWithRest(list) {
|
|
1242
|
+
this.consume(Token.ELLIPSIS);
|
|
1243
|
+
const pattern = this.parseBindingPattern(true);
|
|
1244
|
+
if (this.peek().isType(Token.ASSIGN)) {
|
|
1245
|
+
throw new Error(this.errorMessage(`Error A rest parameter cannot have an initializer`));
|
|
1246
|
+
}
|
|
1247
|
+
if (this.peek().isType(Token.COMMA)) {
|
|
1248
|
+
throw new Error(this.errorMessage(`Error A rest parameter or binding pattern may not have a trailing comma`));
|
|
1249
|
+
}
|
|
1250
|
+
// 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
|
|
1251
|
+
// as the formal parameters of'(x, y, ...z) => foo', and is not itself a
|
|
1252
|
+
// valid expression.
|
|
1253
|
+
if (this.peek().isNotType(Token.RPAREN) || this.peekAhead().isNotType(Token.ARROW)) {
|
|
1254
|
+
throw new Error(this.errorMessage(`Error Unexpected Token At ${this.position()}`));
|
|
1255
|
+
}
|
|
1256
|
+
list.push(new SpreadElement(pattern));
|
|
1257
|
+
return this.expressionListToExpression(list);
|
|
1258
|
+
}
|
|
1259
|
+
expressionListToExpression(list) {
|
|
1260
|
+
const first = list[0];
|
|
1261
|
+
if (list.length === 1) {
|
|
1262
|
+
return first;
|
|
1263
|
+
}
|
|
1264
|
+
if (first instanceof SequenceExpression) {
|
|
1265
|
+
first.getExpressions().push(...list.slice(1));
|
|
1266
|
+
return first;
|
|
1267
|
+
}
|
|
1268
|
+
return new SequenceExpression(list);
|
|
1269
|
+
}
|
|
1270
|
+
parseMemberExpression() {
|
|
1271
|
+
// MemberExpression ::
|
|
1272
|
+
// (PrimaryExpression | FunctionLiteral | ClassLiteral)
|
|
1273
|
+
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
|
1274
|
+
//
|
|
1275
|
+
// CallExpression ::
|
|
1276
|
+
// (SuperCall | ImportCall)
|
|
1277
|
+
// ('[' Expression ']' | '.' Identifier | Arguments | TemplateLiteral)*
|
|
1278
|
+
//
|
|
1279
|
+
// The '[' Expression ']' and '.' Identifier parts are parsed by
|
|
1280
|
+
// ParseMemberExpressionContinuation, and everything preceeding it is merged
|
|
1281
|
+
// into ParsePrimaryExpression.
|
|
1282
|
+
// Parse the initial primary or function expression.
|
|
1283
|
+
const result = this.parsePrimaryExpression();
|
|
1284
|
+
return this.parseMemberExpressionContinuation(result);
|
|
1285
|
+
}
|
|
1286
|
+
toParamNode(expression) {
|
|
1287
|
+
if (expression instanceof AssignmentExpression) {
|
|
1288
|
+
return new Param(expression.getLeft(), expression.getRight());
|
|
1289
|
+
}
|
|
1290
|
+
if (expression instanceof GroupingExpression) {
|
|
1291
|
+
return new Param(expression.getNode());
|
|
1292
|
+
}
|
|
1293
|
+
return new Param(expression);
|
|
1294
|
+
}
|
|
1295
|
+
parsePrimaryExpression() {
|
|
1296
|
+
// PrimaryExpression ::
|
|
1297
|
+
// 'this'
|
|
1298
|
+
// 'null'
|
|
1299
|
+
// 'true'
|
|
1300
|
+
// 'false'
|
|
1301
|
+
// Identifier
|
|
1302
|
+
// Number
|
|
1303
|
+
// String
|
|
1304
|
+
// ArrayLiteral
|
|
1305
|
+
// ObjectLiteral
|
|
1306
|
+
// RegExpLiteral
|
|
1307
|
+
// '(' Expression ')'
|
|
1308
|
+
// do Block
|
|
1309
|
+
// AsyncFunctionLiteral
|
|
1310
|
+
let token = this.peek();
|
|
1311
|
+
if (Token.isAnyIdentifier(token.token)) {
|
|
1312
|
+
this.consume(token.token);
|
|
1313
|
+
let kind = FunctionKind.NormalFunction;
|
|
1314
|
+
if (token.isType(Token.ASYNC) && !this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1315
|
+
// async function ...
|
|
1316
|
+
if (this.peek().isType(Token.FUNCTION)) {
|
|
1317
|
+
return this.parseAsyncFunctionLiteral();
|
|
1318
|
+
}
|
|
1319
|
+
;
|
|
1320
|
+
// async Identifier => ...
|
|
1321
|
+
if (Token.isAnyIdentifier(this.peek().token) && this.peekAhead().isType(Token.ARROW)) {
|
|
1322
|
+
token = this.next();
|
|
1323
|
+
kind = FunctionKind.AsyncFunction;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
if (this.peek().isType(Token.ARROW)) {
|
|
1327
|
+
this.setFunctionKind(kind);
|
|
1328
|
+
const name = this.parseAndClassifyIdentifier(token);
|
|
1329
|
+
const params = [];
|
|
1330
|
+
if (name instanceof SequenceExpression) {
|
|
1331
|
+
params.push(...name.getExpressions().map(this.toParamNode));
|
|
1332
|
+
}
|
|
1333
|
+
else {
|
|
1334
|
+
params.push(this.toParamNode(name));
|
|
1335
|
+
}
|
|
1336
|
+
const arrow = this.parseArrowFunctionLiteral(params, kind);
|
|
1337
|
+
this.restoreFunctionKind();
|
|
1338
|
+
return arrow;
|
|
1339
|
+
}
|
|
1340
|
+
return this.parseAndClassifyIdentifier(token);
|
|
1341
|
+
}
|
|
1342
|
+
if (Token.isLiteral(token.token)) {
|
|
1343
|
+
return expressionFromLiteral(this.next());
|
|
1344
|
+
}
|
|
1345
|
+
switch (token.token) {
|
|
1346
|
+
case Token.NEW:
|
|
1347
|
+
return this.parseMemberWithPresentNewPrefixesExpression();
|
|
1348
|
+
case Token.THIS:
|
|
1349
|
+
this.consume(Token.THIS);
|
|
1350
|
+
return ThisNode;
|
|
1351
|
+
case Token.DIV:
|
|
1352
|
+
case Token.DIV_ASSIGN:
|
|
1353
|
+
// case Token.REGEXP_LITERAL:
|
|
1354
|
+
// this.consume(Token.REGEXP_LITERAL);
|
|
1355
|
+
// return token.value!;
|
|
1356
|
+
return this.parseRegExpLiteral();
|
|
1357
|
+
case Token.FUNCTION:
|
|
1358
|
+
return this.parseFunctionExpression();
|
|
1359
|
+
case Token.SUPER: {
|
|
1360
|
+
return this.parseSuperExpression();
|
|
1361
|
+
}
|
|
1362
|
+
case Token.IMPORT:
|
|
1363
|
+
return this.parseImportExpressions();
|
|
1364
|
+
case Token.LBRACK:
|
|
1365
|
+
return this.parseArrayLiteral(false);
|
|
1366
|
+
case Token.LBRACE:
|
|
1367
|
+
return this.parseObjectLiteral(false);
|
|
1368
|
+
case Token.LPAREN: {
|
|
1369
|
+
this.consume(Token.LPAREN);
|
|
1370
|
+
if (this.check(Token.RPAREN)) {
|
|
1371
|
+
// ()=>x. The continuation that consumes the => is in
|
|
1372
|
+
// ParseAssignmentExpressionCoverGrammar.
|
|
1373
|
+
if (!this.peek().isType(Token.ARROW)) {
|
|
1374
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${Token.RPAREN.getName()}`));
|
|
1375
|
+
}
|
|
1376
|
+
const result = new SequenceExpression([]);
|
|
1377
|
+
this.markParenthesized(result);
|
|
1378
|
+
return result;
|
|
1379
|
+
}
|
|
1380
|
+
// Heuristically try to detect immediately called functions before
|
|
1381
|
+
// seeing the call parentheses.
|
|
1382
|
+
this.setAcceptIN(true);
|
|
1383
|
+
const expression = this.parseExpressionCoverGrammar();
|
|
1384
|
+
this.markParenthesized(expression);
|
|
1385
|
+
this.expect(Token.RPAREN);
|
|
1386
|
+
this.restoreAcceptIN();
|
|
1387
|
+
return expression;
|
|
1388
|
+
}
|
|
1389
|
+
case Token.CLASS: {
|
|
1390
|
+
return this.parseClassExpression();
|
|
1391
|
+
}
|
|
1392
|
+
case Token.TEMPLATE_SPAN:
|
|
1393
|
+
case Token.TEMPLATE_TAIL:
|
|
1394
|
+
return this.parseTemplateLiteral();
|
|
1395
|
+
default:
|
|
1396
|
+
break;
|
|
1397
|
+
}
|
|
1398
|
+
throw new Error(this.errorMessage(`Unexpected Token: ${JSON.stringify(this.next())}`));
|
|
1399
|
+
}
|
|
1400
|
+
parseTemplateLiteral(tag) {
|
|
1401
|
+
// A TemplateLiteral is made up of 0 or more TEMPLATE_SPAN tokens (literal
|
|
1402
|
+
// text followed by a substitution expression), finalized by a single
|
|
1403
|
+
// TEMPLATE_TAIL.
|
|
1404
|
+
//
|
|
1405
|
+
// In terms of draft language, TEMPLATE_SPAN may be either the TemplateHead or
|
|
1406
|
+
// TemplateMiddle productions, while TEMPLATE_TAIL is either TemplateTail, or
|
|
1407
|
+
// NoSubstitutionTemplate.
|
|
1408
|
+
//
|
|
1409
|
+
// When parsing a TemplateLiteral, we must have scanned either an initial
|
|
1410
|
+
// TEMPLATE_SPAN, or a TEMPLATE_TAIL.
|
|
1411
|
+
let next = this.peek();
|
|
1412
|
+
if (!Token.isTemplate(next.token)) {
|
|
1413
|
+
throw new SyntaxError(this.errorMessage(`Unexpected Token: ${JSON.stringify(this.next())}`));
|
|
1414
|
+
}
|
|
1415
|
+
// If we reach a TEMPLATE_TAIL first, we are parsing a NoSubstitutionTemplate.
|
|
1416
|
+
// In this case we may simply consume the token and build a template with a
|
|
1417
|
+
// single TEMPLATE_SPAN and no expressions.
|
|
1418
|
+
if (next.isType(Token.TEMPLATE_TAIL)) {
|
|
1419
|
+
this.consume(Token.TEMPLATE_TAIL);
|
|
1420
|
+
const string = next.getValue().string;
|
|
1421
|
+
return this.createTemplateLiteralExpressionNode([string], [], tag);
|
|
1422
|
+
}
|
|
1423
|
+
this.consume(Token.TEMPLATE_SPAN);
|
|
1424
|
+
const expressions = [];
|
|
1425
|
+
const strings = [];
|
|
1426
|
+
strings.push(next.getValue().string);
|
|
1427
|
+
// If we open with a TEMPLATE_SPAN, we must scan the subsequent expression,
|
|
1428
|
+
// and repeat if the following token is a TEMPLATE_SPAN as well (in this
|
|
1429
|
+
// case, representing a TemplateMiddle).
|
|
1430
|
+
do {
|
|
1431
|
+
this.setAcceptIN(true);
|
|
1432
|
+
const expression = this.parseExpressionCoverGrammar();
|
|
1433
|
+
expressions.push(expression);
|
|
1434
|
+
next = this.next();
|
|
1435
|
+
if (next.isNotType(Token.RBRACE)) {
|
|
1436
|
+
this.restoreAcceptIN();
|
|
1437
|
+
throw new SyntaxError(this.errorMessage('Unterminated Template Expr'));
|
|
1438
|
+
}
|
|
1439
|
+
// If we didn't die parsing that expression, our next token should be a
|
|
1440
|
+
// TEMPLATE_SPAN or TEMPLATE_TAIL.
|
|
1441
|
+
next = this.scanner.scanTemplateContinuation();
|
|
1442
|
+
strings.push(next.getValue().string);
|
|
1443
|
+
this.restoreAcceptIN();
|
|
1444
|
+
} while (next.isType(Token.TEMPLATE_SPAN));
|
|
1445
|
+
if (next.isNotType(Token.TEMPLATE_TAIL)) {
|
|
1446
|
+
throw new SyntaxError(this.errorMessage(`Unexpected Token: ${JSON.stringify(next)}`));
|
|
1447
|
+
}
|
|
1448
|
+
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
|
1449
|
+
return this.createTemplateLiteralExpressionNode(strings, expressions, tag);
|
|
1450
|
+
}
|
|
1451
|
+
createTemplateLiteralExpressionNode(strings, expressions, tag) {
|
|
1452
|
+
if (tag) {
|
|
1453
|
+
return new TaggedTemplateExpression(tag, strings, expressions);
|
|
1454
|
+
}
|
|
1455
|
+
else {
|
|
1456
|
+
return new TemplateLiteral(strings, expressions);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
parseMemberWithPresentNewPrefixesExpression() {
|
|
1460
|
+
// NewExpression ::
|
|
1461
|
+
// ('new')+ MemberExpression
|
|
1462
|
+
//
|
|
1463
|
+
// NewTarget ::
|
|
1464
|
+
// 'new' '.' 'target'
|
|
1465
|
+
// The grammar for new expressions is pretty warped. We can have several 'new'
|
|
1466
|
+
// keywords following each other, and then a MemberExpression. When we see '('
|
|
1467
|
+
// after the MemberExpression, it's associated with the rightmost unassociated
|
|
1468
|
+
// 'new' to create a NewExpression with arguments. However, a NewExpression
|
|
1469
|
+
// can also occur without arguments.
|
|
1470
|
+
// Examples of new expression:
|
|
1471
|
+
// new foo.bar().baz means (new (foo.bar)()).baz
|
|
1472
|
+
// new foo()() means (new foo())()
|
|
1473
|
+
// new new foo()() means (new (new foo())())
|
|
1474
|
+
// new new foo means new (new foo)
|
|
1475
|
+
// new new foo() means new (new foo())
|
|
1476
|
+
// new new foo().bar().baz means (new (new foo()).bar()).baz
|
|
1477
|
+
// new super.x means new (super.x)
|
|
1478
|
+
this.consume(Token.NEW);
|
|
1479
|
+
let result;
|
|
1480
|
+
// CheckStackOverflow();
|
|
1481
|
+
if (this.peek().isType(Token.IMPORT) && this.peekAhead().isType(Token.LPAREN)) {
|
|
1482
|
+
throw new SyntaxError(this.errorMessage(`Import Call Not New Expression`));
|
|
1483
|
+
}
|
|
1484
|
+
else if (this.peek().isType(Token.PERIOD)) {
|
|
1485
|
+
result = this.parseNewTargetExpression();
|
|
1486
|
+
return this.parseMemberExpressionContinuation(result);
|
|
1487
|
+
}
|
|
1488
|
+
else {
|
|
1489
|
+
result = this.parseMemberExpression();
|
|
1490
|
+
if (result === SuperIdentifier) {
|
|
1491
|
+
// new super() is never allowed
|
|
1492
|
+
throw new SyntaxError(this.errorMessage(`Unexpected Super, new super() is never allowed`));
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
if (this.peek().isType(Token.LPAREN)) {
|
|
1496
|
+
// NewExpression with arguments.
|
|
1497
|
+
const args = this.parseArguments();
|
|
1498
|
+
result = new NewExpression(result, args);
|
|
1499
|
+
// The expression can still continue with . or [ after the arguments.
|
|
1500
|
+
return this.parseMemberExpressionContinuation(result);
|
|
1501
|
+
}
|
|
1502
|
+
if (this.peek().isType(Token.QUESTION_PERIOD)) {
|
|
1503
|
+
throw new SyntaxError(this.errorMessage(`Optional Chaining with New not allowed, new x?.y()`));
|
|
1504
|
+
}
|
|
1505
|
+
return new NewExpression(result);
|
|
1506
|
+
}
|
|
1507
|
+
parseArguments(maybeArrow) {
|
|
1508
|
+
// Arguments ::
|
|
1509
|
+
// '(' (AssignmentExpression)*[','] ')'
|
|
1510
|
+
this.consume(Token.LPAREN);
|
|
1511
|
+
const args = [];
|
|
1512
|
+
while (this.peek().isNotType(Token.RPAREN)) {
|
|
1513
|
+
const isSpread = this.check(Token.ELLIPSIS);
|
|
1514
|
+
this.setAcceptIN(true);
|
|
1515
|
+
let argument = this.parseAssignmentExpressionCoverGrammar();
|
|
1516
|
+
if (ParsingArrowHeadFlag.MaybeArrowHead === maybeArrow) {
|
|
1517
|
+
if (isSpread) {
|
|
1518
|
+
if (argument instanceof AssignmentExpression) {
|
|
1519
|
+
this.restoreAcceptIN();
|
|
1520
|
+
throw new Error(this.errorMessage(` Rest parameter may not have a default initializer'`));
|
|
1521
|
+
}
|
|
1522
|
+
if (this.peek().isType(Token.COMMA)) {
|
|
1523
|
+
this.restoreAcceptIN();
|
|
1524
|
+
throw new Error(this.errorMessage(`parsing '...spread,arg =>'`));
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
if (isSpread) {
|
|
1529
|
+
argument = new SpreadElement(argument);
|
|
1530
|
+
}
|
|
1531
|
+
args.push(argument);
|
|
1532
|
+
this.restoreAcceptIN();
|
|
1533
|
+
if (!this.check(Token.COMMA))
|
|
1534
|
+
break;
|
|
1535
|
+
}
|
|
1536
|
+
if (!this.check(Token.RPAREN)) {
|
|
1537
|
+
throw new Error(this.errorMessage(`parsing arguments call, expecting ')'`));
|
|
1538
|
+
}
|
|
1539
|
+
return args;
|
|
1540
|
+
}
|
|
1541
|
+
parseAssignmentExpressionCoverGrammar() {
|
|
1542
|
+
// AssignmentExpression ::
|
|
1543
|
+
// ConditionalExpression
|
|
1544
|
+
// ArrowFunction
|
|
1545
|
+
// YieldExpression
|
|
1546
|
+
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
|
1547
|
+
if (this.peek().isType(Token.YIELD) && isGeneratorFunction(this.functionKind)) {
|
|
1548
|
+
return this.parseYieldExpression();
|
|
1549
|
+
}
|
|
1550
|
+
let expression = this.parseConditionalExpression();
|
|
1551
|
+
const op = this.peek().token;
|
|
1552
|
+
if (!Token.isArrowOrAssignmentOp(op)) {
|
|
1553
|
+
this.clearParenthesized(expression);
|
|
1554
|
+
return expression;
|
|
1555
|
+
}
|
|
1556
|
+
;
|
|
1557
|
+
// Arrow functions.
|
|
1558
|
+
if (op === Token.ARROW) {
|
|
1559
|
+
if (!this.isIdentifier(expression) && !this.isParenthesized(expression)) {
|
|
1560
|
+
throw new Error(this.errorMessage(`Malformed Arrow Fun Param List`));
|
|
1561
|
+
}
|
|
1562
|
+
const kind = FunctionKind.NormalFunction;
|
|
1563
|
+
this.setFunctionKind(kind);
|
|
1564
|
+
let arrow;
|
|
1565
|
+
if (expression instanceof SequenceExpression) {
|
|
1566
|
+
const params = expression.getExpressions().map(expr => new Param(expr));
|
|
1567
|
+
const last = params.at(-1)?.getIdentifier();
|
|
1568
|
+
if (last instanceof SpreadElement) {
|
|
1569
|
+
const arg = last.getArgument();
|
|
1570
|
+
let param = arg;
|
|
1571
|
+
if (arg instanceof ArrayExpression) {
|
|
1572
|
+
param = new ArrayPattern(arg.getElements());
|
|
1573
|
+
}
|
|
1574
|
+
else if (arg instanceof ObjectExpression) {
|
|
1575
|
+
param = new ObjectPattern(arg.getProperties());
|
|
1576
|
+
}
|
|
1577
|
+
params[params.length - 1] = new Param(new RestElement(param));
|
|
1578
|
+
}
|
|
1579
|
+
arrow = this.parseArrowFunctionLiteral(params, FunctionKind.NormalFunction);
|
|
1580
|
+
}
|
|
1581
|
+
else if (expression instanceof GroupingExpression) {
|
|
1582
|
+
arrow = this.parseArrowFunctionLiteral([new Param(expression.getNode())], FunctionKind.NormalFunction);
|
|
1583
|
+
}
|
|
1584
|
+
else {
|
|
1585
|
+
this.clearParenthesized(expression);
|
|
1586
|
+
arrow = this.parseArrowFunctionLiteral([new Param(expression)], FunctionKind.NormalFunction);
|
|
1587
|
+
}
|
|
1588
|
+
this.restoreFunctionKind();
|
|
1589
|
+
return arrow;
|
|
1590
|
+
}
|
|
1591
|
+
if (this.isAssignableIdentifier(expression)) {
|
|
1592
|
+
}
|
|
1593
|
+
else if (this.isProperty(expression)) {
|
|
1594
|
+
}
|
|
1595
|
+
else if (this.isPattern(expression) && Token.isAssignment(op)) {
|
|
1596
|
+
// Destructuring assignment.
|
|
1597
|
+
expression = expression instanceof ObjectExpression
|
|
1598
|
+
? new ObjectPattern(expression.getProperties())
|
|
1599
|
+
: new ArrayPattern(expression.getElements());
|
|
1600
|
+
// expression_scope() -> ValidateAsPattern(expression, lhs_beg_pos, end_position());
|
|
1601
|
+
}
|
|
1602
|
+
else {
|
|
1603
|
+
if (!this.isValidReferenceExpression(expression)) {
|
|
1604
|
+
throw new Error(this.errorMessage(`Invalid Reference Expression`));
|
|
1605
|
+
}
|
|
1606
|
+
if (Token.isLogicalAssignmentOp(op)) {
|
|
1607
|
+
throw new Error(this.errorMessage(`Invalid Lhs In Assignment`));
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
this.consume(op);
|
|
1611
|
+
// const opPosition = this.position();
|
|
1612
|
+
const right = this.parseAssignmentExpression();
|
|
1613
|
+
// Anonymous function name inference applies to =, ||=, &&=, and ??=.
|
|
1614
|
+
if (!Token.isAssignment(op)) {
|
|
1615
|
+
throw new Error(this.errorMessage(`Invalid Destructuring Target`));
|
|
1616
|
+
}
|
|
1617
|
+
return new AssignmentExpression(op.getName(), expression, right);
|
|
1618
|
+
}
|
|
1619
|
+
parseAssignmentExpression() {
|
|
1620
|
+
return this.parseAssignmentExpressionCoverGrammar();
|
|
1621
|
+
}
|
|
1622
|
+
parseArrowFunctionLiteral(parameters, kind) {
|
|
1623
|
+
if (this.peek().isNotType(Token.ARROW)) {
|
|
1624
|
+
throw new SyntaxError(this.errorMessage('SyntaxError Expecting Arrow Token'));
|
|
1625
|
+
}
|
|
1626
|
+
if (this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1627
|
+
throw new SyntaxError(this.errorMessage('Unexpected Token "\n" a line terminator after arrow token"'));
|
|
1628
|
+
}
|
|
1629
|
+
let body;
|
|
1630
|
+
let has_braces = true;
|
|
1631
|
+
this.consume(Token.ARROW);
|
|
1632
|
+
if (this.peek().isType(Token.LBRACE)) {
|
|
1633
|
+
this.consume(Token.LBRACE);
|
|
1634
|
+
this.setStatue(true, kind);
|
|
1635
|
+
body = this.parseFunctionBody(kind, FunctionBodyType.BLOCK, FunctionSyntaxKind.AnonymousExpression);
|
|
1636
|
+
this.restoreStatue();
|
|
1637
|
+
}
|
|
1638
|
+
else {
|
|
1639
|
+
has_braces = false;
|
|
1640
|
+
body = this.parseFunctionBody(kind, FunctionBodyType.EXPRESSION, FunctionSyntaxKind.AnonymousExpression);
|
|
1641
|
+
}
|
|
1642
|
+
return new ArrowFunctionExpression(parameters, body, !has_braces, isAsyncFunction(kind));
|
|
1643
|
+
}
|
|
1644
|
+
parseRegExpLiteral() {
|
|
1645
|
+
if (!this.scanner.scanRegExpPattern()) {
|
|
1646
|
+
throw new Error('Unterminated RegExp');
|
|
1647
|
+
}
|
|
1648
|
+
return this.scanner.currentToken().getValue();
|
|
1649
|
+
}
|
|
1650
|
+
parseArrayLiteral(isPattern) {
|
|
1651
|
+
// ArrayLiteral ::
|
|
1652
|
+
// '[' Expression? (',' Expression?)* ']'
|
|
1653
|
+
this.consume(Token.LBRACK);
|
|
1654
|
+
let first_spread_index = -1;
|
|
1655
|
+
const values = [];
|
|
1656
|
+
while (!this.check(Token.RBRACK)) {
|
|
1657
|
+
let elem;
|
|
1658
|
+
if (this.peek().isType(Token.COMMA)) {
|
|
1659
|
+
elem = null;
|
|
1660
|
+
}
|
|
1661
|
+
else if (this.check(Token.ELLIPSIS)) {
|
|
1662
|
+
this.setAcceptIN(true);
|
|
1663
|
+
const argument = this.parsePossibleDestructuringSubPattern();
|
|
1664
|
+
this.restoreAcceptIN();
|
|
1665
|
+
elem = new SpreadElement(argument);
|
|
1666
|
+
if (first_spread_index < 0) {
|
|
1667
|
+
first_spread_index = values.length;
|
|
1668
|
+
}
|
|
1669
|
+
if (argument instanceof AssignmentExpression && isPattern) {
|
|
1670
|
+
throw new SyntaxError(this.errorMessage('Invalid Destructuring Target'));
|
|
1671
|
+
}
|
|
1672
|
+
if (this.peek().isType(Token.COMMA)) {
|
|
1673
|
+
throw new SyntaxError(this.errorMessage('Element After Rest'));
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
this.setAcceptIN(true);
|
|
1678
|
+
elem = this.parsePossibleDestructuringSubPattern();
|
|
1679
|
+
this.restoreAcceptIN();
|
|
1680
|
+
}
|
|
1681
|
+
values.push(elem);
|
|
1682
|
+
if (this.peek().isNotType(Token.RBRACK)) {
|
|
1683
|
+
this.expect(Token.COMMA);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
return new (isPattern ? ArrayPattern : ArrayExpression)(values);
|
|
1687
|
+
}
|
|
1688
|
+
parsePossibleDestructuringSubPattern() {
|
|
1689
|
+
return this.parseAssignmentExpressionCoverGrammar();
|
|
1690
|
+
}
|
|
1691
|
+
parseObjectLiteral(isPattern) {
|
|
1692
|
+
// ObjectLiteral ::
|
|
1693
|
+
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
|
|
1694
|
+
this.consume(Token.LBRACE);
|
|
1695
|
+
const properties = [];
|
|
1696
|
+
while (!this.check(Token.RBRACE)) {
|
|
1697
|
+
const property = this.parseObjectPropertyDefinition(isPattern);
|
|
1698
|
+
properties.push(property);
|
|
1699
|
+
if (this.peek().isNotType(Token.RBRACE)) {
|
|
1700
|
+
this.expect(Token.COMMA);
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
if (isPattern) {
|
|
1704
|
+
return new ObjectPattern(properties);
|
|
1705
|
+
}
|
|
1706
|
+
return new ObjectExpression(properties);
|
|
1707
|
+
}
|
|
1708
|
+
parseObjectPropertyDefinition(isPattern) {
|
|
1709
|
+
const propInfo = new PropertyKindInfo();
|
|
1710
|
+
const nameExpression = this.parseProperty(propInfo);
|
|
1711
|
+
switch (propInfo.kind) {
|
|
1712
|
+
case PropertyKind.Spread:
|
|
1713
|
+
let value = nameExpression;
|
|
1714
|
+
if (isPattern) {
|
|
1715
|
+
value = new RestElement(value.getArgument());
|
|
1716
|
+
}
|
|
1717
|
+
return new Property(value.getArgument(), value, 'init', false, false, propInfo.isComputedName);
|
|
1718
|
+
case PropertyKind.Value: {
|
|
1719
|
+
this.consume(Token.COLON);
|
|
1720
|
+
this.setAcceptIN(true);
|
|
1721
|
+
const value = this.parsePossibleDestructuringSubPattern();
|
|
1722
|
+
this.restoreAcceptIN();
|
|
1723
|
+
return new Property(nameExpression, value, 'init', false, false, propInfo.isComputedName);
|
|
1724
|
+
}
|
|
1725
|
+
case PropertyKind.Assign:
|
|
1726
|
+
case PropertyKind.ShorthandOrClassField:
|
|
1727
|
+
case PropertyKind.Shorthand: {
|
|
1728
|
+
// PropertyDefinition
|
|
1729
|
+
// IdentifierReference
|
|
1730
|
+
// CoverInitializedName
|
|
1731
|
+
//
|
|
1732
|
+
// CoverInitializedName
|
|
1733
|
+
// IdentifierReference Initializer?
|
|
1734
|
+
const lhs = new Identifier(propInfo.name);
|
|
1735
|
+
if (!this.isAssignableIdentifier(lhs)) {
|
|
1736
|
+
throw new Error(this.errorMessage('Strict Eval Arguments'));
|
|
1737
|
+
}
|
|
1738
|
+
let value;
|
|
1739
|
+
if (this.peek().isType(Token.ASSIGN)) {
|
|
1740
|
+
this.consume(Token.ASSIGN);
|
|
1741
|
+
this.setAcceptIN(true);
|
|
1742
|
+
const rhs = this.parseAssignmentExpression();
|
|
1743
|
+
this.restoreAcceptIN();
|
|
1744
|
+
value = new AssignmentExpression(Token.ASSIGN.getName(), lhs, rhs);
|
|
1745
|
+
}
|
|
1746
|
+
else {
|
|
1747
|
+
value = lhs;
|
|
1748
|
+
}
|
|
1749
|
+
return new Property(nameExpression, value, 'init', false, propInfo.kind !== PropertyKind.Assign, propInfo.isComputedName);
|
|
1750
|
+
}
|
|
1751
|
+
case PropertyKind.Method: {
|
|
1752
|
+
// MethodDefinition
|
|
1753
|
+
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
|
1754
|
+
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
|
1755
|
+
const kind = this.methodKindFor(propInfo.isStatic, propInfo.funcFlag);
|
|
1756
|
+
const value = this.parseFunctionLiteral(kind, FunctionSyntaxKind.AccessorOrMethod, propInfo.name ? new Identifier(propInfo.name) : undefined);
|
|
1757
|
+
return new Property(nameExpression, value, 'init', true, false, propInfo.isComputedName);
|
|
1758
|
+
}
|
|
1759
|
+
case PropertyKind.AccessorGetter:
|
|
1760
|
+
case PropertyKind.AccessorSetter: {
|
|
1761
|
+
const isGet = propInfo.kind == PropertyKind.AccessorGetter;
|
|
1762
|
+
const kind = this.methodKindFor(propInfo.isStatic, propInfo.funcFlag);
|
|
1763
|
+
const value = this.parseFunctionLiteral(kind, FunctionSyntaxKind.AccessorOrMethod, propInfo.name ? new Identifier(propInfo.name) : undefined);
|
|
1764
|
+
return new Property(nameExpression, value, isGet ? 'get' : 'set', false, false, propInfo.isComputedName);
|
|
1765
|
+
}
|
|
1766
|
+
case PropertyKind.ClassField:
|
|
1767
|
+
case PropertyKind.NotSet:
|
|
1768
|
+
return NullNode;
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
parseProperty(propInfo) {
|
|
1772
|
+
let nextToken = this.peek();
|
|
1773
|
+
if (this.check(Token.ASYNC)) {
|
|
1774
|
+
// async
|
|
1775
|
+
nextToken = this.peek();
|
|
1776
|
+
if (nextToken.isNotType(Token.MUL)
|
|
1777
|
+
&& propInfo.parsePropertyKindFromToken(nextToken.token)
|
|
1778
|
+
|| this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1779
|
+
return AsyncIdentifier;
|
|
1780
|
+
}
|
|
1781
|
+
propInfo.kind = PropertyKind.Method;
|
|
1782
|
+
propInfo.funcFlag = ParseFunctionFlag.IsAsync;
|
|
1783
|
+
}
|
|
1784
|
+
if (this.check(Token.MUL)) {
|
|
1785
|
+
// async*
|
|
1786
|
+
propInfo.kind = PropertyKind.Method;
|
|
1787
|
+
propInfo.funcFlag = ParseFunctionFlag.IsGenerator;
|
|
1788
|
+
}
|
|
1789
|
+
nextToken = this.peek();
|
|
1790
|
+
if (propInfo.kind == PropertyKind.NotSet && nextToken.isType(Token.GET) || nextToken.isType(Token.SET)) {
|
|
1791
|
+
const token = this.next();
|
|
1792
|
+
if (propInfo.parsePropertyKindFromToken(this.peek().token)) {
|
|
1793
|
+
return nextToken.isType(Token.GET) ? GetIdentifier : SetIdentifier;
|
|
1794
|
+
}
|
|
1795
|
+
if (token.isType(Token.GET)) {
|
|
1796
|
+
propInfo.kind = PropertyKind.AccessorGetter;
|
|
1797
|
+
}
|
|
1798
|
+
else if (token.isType(Token.SET)) {
|
|
1799
|
+
propInfo.kind = PropertyKind.AccessorSetter;
|
|
1800
|
+
}
|
|
1801
|
+
nextToken = this.peek();
|
|
1802
|
+
}
|
|
1803
|
+
let propertyName;
|
|
1804
|
+
switch (nextToken.token) {
|
|
1805
|
+
case Token.PRIVATE_NAME:
|
|
1806
|
+
propInfo.isPrivate = true;
|
|
1807
|
+
this.consume(Token.PRIVATE_NAME);
|
|
1808
|
+
if (propInfo.kind == PropertyKind.NotSet) {
|
|
1809
|
+
propInfo.parsePropertyKindFromToken(this.peek().token);
|
|
1810
|
+
}
|
|
1811
|
+
propertyName = this.getIdentifier();
|
|
1812
|
+
propInfo.name = propertyName.getName();
|
|
1813
|
+
if (propInfo.position == PropertyPosition.ObjectLiteral) {
|
|
1814
|
+
throw new TypeError(this.errorMessage('UnexpectedToken PRIVATE_NAME'));
|
|
1815
|
+
}
|
|
1816
|
+
break;
|
|
1817
|
+
case Token.STRING:
|
|
1818
|
+
case Token.NUMBER:
|
|
1819
|
+
case Token.BIGINT:
|
|
1820
|
+
// "12" -> 12
|
|
1821
|
+
// 12.3 -> "12.3"
|
|
1822
|
+
// 12.30 -> "12.3"
|
|
1823
|
+
this.consume(nextToken.token);
|
|
1824
|
+
propertyName = nextToken.getValue();
|
|
1825
|
+
propInfo.name = propertyName.getValue();
|
|
1826
|
+
break;
|
|
1827
|
+
case Token.LBRACK:
|
|
1828
|
+
// [Symbol.iterator]
|
|
1829
|
+
this.consume(Token.LBRACK);
|
|
1830
|
+
this.setAcceptIN(true);
|
|
1831
|
+
propertyName = this.parseAssignmentExpression();
|
|
1832
|
+
this.expect(Token.RBRACK);
|
|
1833
|
+
if (propInfo.kind === PropertyKind.NotSet) {
|
|
1834
|
+
propInfo.parsePropertyKindFromToken(this.peek().token);
|
|
1835
|
+
}
|
|
1836
|
+
propInfo.name = propertyName.toString();
|
|
1837
|
+
this.restoreAcceptIN();
|
|
1838
|
+
return propertyName;
|
|
1839
|
+
case Token.ELLIPSIS:
|
|
1840
|
+
if (propInfo.kind == PropertyKind.NotSet) {
|
|
1841
|
+
this.consume(Token.ELLIPSIS);
|
|
1842
|
+
this.setAcceptIN(true);
|
|
1843
|
+
propertyName = this.parsePossibleDestructuringSubPattern();
|
|
1844
|
+
propInfo.kind = PropertyKind.Spread;
|
|
1845
|
+
if (!this.isValidReferenceExpression(propertyName)) {
|
|
1846
|
+
throw new Error(this.errorMessage('Invalid Rest Binding/Assignment Pattern'));
|
|
1847
|
+
}
|
|
1848
|
+
if (this.peek().isNotType(Token.RBRACE)) {
|
|
1849
|
+
throw new Error(this.errorMessage('Element After Rest'));
|
|
1850
|
+
}
|
|
1851
|
+
propInfo.name = propertyName.toString();
|
|
1852
|
+
this.restoreAcceptIN();
|
|
1853
|
+
return new SpreadElement(propertyName);
|
|
1854
|
+
}
|
|
1855
|
+
default:
|
|
1856
|
+
propertyName = this.parsePropertyOrPrivatePropertyName();
|
|
1857
|
+
propInfo.name = propertyName.toString();
|
|
1858
|
+
break;
|
|
1859
|
+
}
|
|
1860
|
+
if (propInfo.kind === PropertyKind.NotSet) {
|
|
1861
|
+
propInfo.parsePropertyKindFromToken(this.peek().token);
|
|
1862
|
+
}
|
|
1863
|
+
return propertyName;
|
|
1864
|
+
}
|
|
1865
|
+
parseMemberExpressionContinuation(expression) {
|
|
1866
|
+
if (!Token.isMember(this.peek().token))
|
|
1867
|
+
return expression;
|
|
1868
|
+
return this.doParseMemberExpressionContinuation(expression);
|
|
1869
|
+
}
|
|
1870
|
+
doParseMemberExpressionContinuation(expression) {
|
|
1871
|
+
if (!Token.isMember(this.peek().token)) {
|
|
1872
|
+
throw new Error(this.errorMessage(`Parsing member expression`));
|
|
1873
|
+
}
|
|
1874
|
+
// Parses this part of MemberExpression:
|
|
1875
|
+
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
|
1876
|
+
do {
|
|
1877
|
+
switch (this.peek().token) {
|
|
1878
|
+
case Token.LBRACK: {
|
|
1879
|
+
this.consume(Token.LBRACK);
|
|
1880
|
+
this.setAcceptIN(true);
|
|
1881
|
+
const index = this.parseExpressionCoverGrammar();
|
|
1882
|
+
expression = new MemberExpression(expression, index, true);
|
|
1883
|
+
this.expect(Token.RBRACK);
|
|
1884
|
+
this.restoreAcceptIN();
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
case Token.PERIOD: {
|
|
1888
|
+
this.consume(Token.PERIOD);
|
|
1889
|
+
const key = this.parsePropertyOrPrivatePropertyName();
|
|
1890
|
+
expression = new MemberExpression(expression, key, false);
|
|
1891
|
+
break;
|
|
1892
|
+
}
|
|
1893
|
+
case Token.TEMPLATE_SPAN:
|
|
1894
|
+
case Token.TEMPLATE_TAIL: {
|
|
1895
|
+
expression = this.parseTemplateLiteral(expression);
|
|
1896
|
+
break;
|
|
1897
|
+
}
|
|
1898
|
+
default:
|
|
1899
|
+
throw new SyntaxError(this.errorMessage('unknown token position'));
|
|
1900
|
+
}
|
|
1901
|
+
} while (Token.isMember(this.peek().token));
|
|
1902
|
+
return expression;
|
|
1903
|
+
}
|
|
1904
|
+
parsePropertyOrPrivatePropertyName() {
|
|
1905
|
+
const next = this.next();
|
|
1906
|
+
if (next.isType(Token.IDENTIFIER) || next.isType(Token.PRIVATE_NAME)) {
|
|
1907
|
+
return next.getValue();
|
|
1908
|
+
}
|
|
1909
|
+
// check keyword as identifier
|
|
1910
|
+
if (Token.isPropertyName(next.token) && next.isNotType(Token.EOS)) {
|
|
1911
|
+
return new Identifier(next.token.getName());
|
|
1912
|
+
}
|
|
1913
|
+
throw new SyntaxError(this.errorMessage(`Parsing property expression: Unexpected Token`));
|
|
1914
|
+
}
|
|
1915
|
+
parsePipelineExpression(expression) {
|
|
1916
|
+
// ConditionalExpression ::
|
|
1917
|
+
// LogicalExpression
|
|
1918
|
+
// expression '|>' function [':' expression [':'? expression] ] *
|
|
1919
|
+
// expression '|>' function '('[expression ','?]* ')'
|
|
1920
|
+
//
|
|
1921
|
+
// expression '|>' function ':' expression [':' expression | '?']*]
|
|
1922
|
+
// expression '|>' function '(' expression [',' expression | '?']* ')'
|
|
1923
|
+
//
|
|
1924
|
+
// [~Await]PipelineExpression[?In, ?Yield, ?Await] |> LogicalORExpression[?In, ?Yield, ?Await]
|
|
1925
|
+
// [+Await]PipelineExpression[? In, ? Yield, ? Await] |> [lookahead ∉ { await }]LogicalORExpression[? In, ? Yield, ? Await]
|
|
1926
|
+
let token;
|
|
1927
|
+
while (Token.isPipelineOperator(token = this.peek().token)) {
|
|
1928
|
+
this.consume(token);
|
|
1929
|
+
expression = this.parsePipelineBody(expression);
|
|
1930
|
+
}
|
|
1931
|
+
return expression;
|
|
1932
|
+
}
|
|
1933
|
+
parsePipelineBody(lhs) {
|
|
1934
|
+
let body;
|
|
1935
|
+
let token = this.peek();
|
|
1936
|
+
// parse function
|
|
1937
|
+
switch (token.token) {
|
|
1938
|
+
case Token.FUNCTION:
|
|
1939
|
+
body = this.parseFunctionExpression();
|
|
1940
|
+
break;
|
|
1941
|
+
case Token.ASYNC:
|
|
1942
|
+
if (this.peekAhead().isType(Token.FUNCTION) && !this.scanner.hasLineTerminatorAfterNext()) {
|
|
1943
|
+
this.consume(Token.ASYNC);
|
|
1944
|
+
body = this.parseAsyncFunctionLiteral();
|
|
1945
|
+
}
|
|
1946
|
+
break;
|
|
1947
|
+
default:
|
|
1948
|
+
break;
|
|
1949
|
+
}
|
|
1950
|
+
if (body) {
|
|
1951
|
+
return new PipelineExpression(lhs, body);
|
|
1952
|
+
}
|
|
1953
|
+
if (token.isType(Token.LPAREN)) {
|
|
1954
|
+
// parse arrow function
|
|
1955
|
+
// x |> ( y => y+1 )
|
|
1956
|
+
body = this.parsePrimaryExpression();
|
|
1957
|
+
return new PipelineExpression(lhs, body);
|
|
1958
|
+
}
|
|
1959
|
+
// parse angular-like and f# and partial operator syntax
|
|
1960
|
+
const func = this.parseMemberExpression(); //this.parseLogicalExpression();
|
|
1961
|
+
let args = [];
|
|
1962
|
+
switch (this.peek().token) {
|
|
1963
|
+
case Token.COLON:
|
|
1964
|
+
// support angular pipeline syntax
|
|
1965
|
+
do {
|
|
1966
|
+
this.consume(Token.COLON);
|
|
1967
|
+
const isSpread = this.check(Token.ELLIPSIS);
|
|
1968
|
+
if (this.peek().isType(Token.CONDITIONAL)) {
|
|
1969
|
+
this.consume(Token.CONDITIONAL);
|
|
1970
|
+
if (isSpread) {
|
|
1971
|
+
args.push('...?');
|
|
1972
|
+
}
|
|
1973
|
+
else {
|
|
1974
|
+
args.push('?');
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
else {
|
|
1978
|
+
const arg = this.parseAssignmentExpressionCoverGrammar();
|
|
1979
|
+
if (isSpread) {
|
|
1980
|
+
args.push(new SpreadElement(arg));
|
|
1981
|
+
}
|
|
1982
|
+
else {
|
|
1983
|
+
args.push(arg);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
} while (this.peek().isType(Token.COLON));
|
|
1987
|
+
break;
|
|
1988
|
+
case Token.LPAREN:
|
|
1989
|
+
// es2022 syntax, F# & partial operator
|
|
1990
|
+
this.consume(Token.LPAREN);
|
|
1991
|
+
let indexed = false;
|
|
1992
|
+
while (this.peek().isNotType(Token.RPAREN)) {
|
|
1993
|
+
const isSpread = this.check(Token.ELLIPSIS);
|
|
1994
|
+
if (this.peek().isType(Token.CONDITIONAL)) {
|
|
1995
|
+
this.consume(Token.CONDITIONAL);
|
|
1996
|
+
indexed = true;
|
|
1997
|
+
if (isSpread) {
|
|
1998
|
+
args.push('...?');
|
|
1999
|
+
}
|
|
2000
|
+
else {
|
|
2001
|
+
args.push('?');
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
else {
|
|
2005
|
+
const arg = this.parseAssignmentExpressionCoverGrammar();
|
|
2006
|
+
if (isSpread) {
|
|
2007
|
+
args.push(new SpreadElement(arg));
|
|
2008
|
+
}
|
|
2009
|
+
else {
|
|
2010
|
+
args.push(arg);
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
this.check(Token.COMMA);
|
|
2014
|
+
}
|
|
2015
|
+
this.expect(Token.RPAREN);
|
|
2016
|
+
// should be indexed, has partial operator
|
|
2017
|
+
if (!indexed) {
|
|
2018
|
+
// z |> method(x, y) === method(x, y)(z)
|
|
2019
|
+
body = new CallExpression(func, args);
|
|
2020
|
+
return new PipelineExpression(lhs, body);
|
|
2021
|
+
}
|
|
2022
|
+
break;
|
|
2023
|
+
default:
|
|
2024
|
+
break;
|
|
2025
|
+
}
|
|
2026
|
+
return new PipelineExpression(lhs, func, args);
|
|
2027
|
+
}
|
|
2028
|
+
parseConditionalExpression() {
|
|
2029
|
+
// ConditionalExpression ::
|
|
2030
|
+
// LogicalExpression
|
|
2031
|
+
// LogicalExpression '?' AssignmentExpression ':' AssignmentExpression
|
|
2032
|
+
//
|
|
2033
|
+
let expression = this.parseLogicalExpression();
|
|
2034
|
+
expression = this.parsePipelineExpression(expression);
|
|
2035
|
+
return this.peek().isType(Token.CONDITIONAL) ? this.parseConditionalContinuation(expression) : expression;
|
|
2036
|
+
}
|
|
2037
|
+
parseLogicalExpression() {
|
|
2038
|
+
// LogicalExpression ::
|
|
2039
|
+
// LogicalORExpression
|
|
2040
|
+
// CoalesceExpression
|
|
2041
|
+
// Both LogicalORExpression and CoalesceExpression start with BitwiseOR.
|
|
2042
|
+
// Parse for binary expressions >= 6 (BitwiseOR);
|
|
2043
|
+
let expression = this.parseBinaryExpression(6);
|
|
2044
|
+
const peek = this.peek();
|
|
2045
|
+
if (peek.isType(Token.AND) || peek.isType(Token.OR)) {
|
|
2046
|
+
// LogicalORExpression, pickup parsing where we left off.
|
|
2047
|
+
const precedence = Token.precedence(peek.token, this.acceptIN);
|
|
2048
|
+
expression = this.parseBinaryContinuation(expression, 4, precedence);
|
|
2049
|
+
}
|
|
2050
|
+
else if (peek.isType(Token.NULLISH)) {
|
|
2051
|
+
expression = this.parseNullishExpression(expression);
|
|
2052
|
+
}
|
|
2053
|
+
return expression;
|
|
2054
|
+
}
|
|
2055
|
+
parseBinaryContinuation(x, prec, prec1) {
|
|
2056
|
+
do {
|
|
2057
|
+
// prec1 >= 4
|
|
2058
|
+
while (Token.precedence(this.peek().token, this.acceptIN) === prec1) {
|
|
2059
|
+
let y;
|
|
2060
|
+
let op = this.next();
|
|
2061
|
+
const is_right_associative = op.isType(Token.EXP);
|
|
2062
|
+
const next_prec = is_right_associative ? prec1 : prec1 + 1;
|
|
2063
|
+
y = this.parseBinaryExpression(next_prec);
|
|
2064
|
+
// For now we distinguish between comparisons and other binary
|
|
2065
|
+
// operations. (We could combine the two and get rid of this
|
|
2066
|
+
// code and AST node eventually.)
|
|
2067
|
+
if (Token.isCompare(op.token)) {
|
|
2068
|
+
// We have a comparison.
|
|
2069
|
+
let cmp = op.token;
|
|
2070
|
+
switch (op.token) {
|
|
2071
|
+
case Token.NE:
|
|
2072
|
+
cmp = Token.EQ;
|
|
2073
|
+
break;
|
|
2074
|
+
case Token.NE_STRICT:
|
|
2075
|
+
cmp = Token.EQ_STRICT;
|
|
2076
|
+
break;
|
|
2077
|
+
default: break;
|
|
2078
|
+
}
|
|
2079
|
+
x = shortcutNumericLiteralBinaryExpression(x, y, cmp);
|
|
2080
|
+
if (op.isNotType(cmp)) {
|
|
2081
|
+
// The comparison was negated - add a NOT.
|
|
2082
|
+
x = buildUnaryExpression(x, Token.NOT);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
else {
|
|
2086
|
+
x = shortcutNumericLiteralBinaryExpression(x, y, op.token);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
--prec1;
|
|
2090
|
+
} while (prec1 >= prec);
|
|
2091
|
+
return x;
|
|
2092
|
+
}
|
|
2093
|
+
// Precedence >= 4
|
|
2094
|
+
parseBinaryExpression(precedence) {
|
|
2095
|
+
// "#foo in ShiftExpression" needs to be parsed separately, since private
|
|
2096
|
+
// identifiers are not valid PrimaryExpressions.
|
|
2097
|
+
if (this.peek().isType(Token.PRIVATE_NAME)) {
|
|
2098
|
+
const x = this.parsePropertyOrPrivatePropertyName();
|
|
2099
|
+
const precedence1 = Token.precedence(this.peek().token, this.acceptIN);
|
|
2100
|
+
if (this.peek().isNotType(Token.IN) || precedence1 < precedence) {
|
|
2101
|
+
throw new SyntaxError(this.errorMessage('Unexpected Token Token.PRIVATE_NAME "#name"'));
|
|
2102
|
+
}
|
|
2103
|
+
return this.parseBinaryContinuation(x, precedence, precedence1);
|
|
2104
|
+
}
|
|
2105
|
+
const x = this.parseUnaryExpression();
|
|
2106
|
+
const precedence1 = Token.precedence(this.peek().token, this.acceptIN);
|
|
2107
|
+
if (precedence1 >= precedence) {
|
|
2108
|
+
return this.parseBinaryContinuation(x, precedence, precedence1);
|
|
2109
|
+
}
|
|
2110
|
+
return x;
|
|
2111
|
+
}
|
|
2112
|
+
parseUnaryExpression() {
|
|
2113
|
+
// UnaryExpression ::
|
|
2114
|
+
// PostfixExpression
|
|
2115
|
+
// 'delete' UnaryExpression
|
|
2116
|
+
// 'void' UnaryExpression
|
|
2117
|
+
// 'typeof' UnaryExpression
|
|
2118
|
+
// '++' UnaryExpression
|
|
2119
|
+
// '--' UnaryExpression
|
|
2120
|
+
// '+' UnaryExpression
|
|
2121
|
+
// '-' UnaryExpression
|
|
2122
|
+
// '~' UnaryExpression
|
|
2123
|
+
// '!' UnaryExpression
|
|
2124
|
+
// [+Await] AwaitExpression[?Yield]
|
|
2125
|
+
const op = this.peek();
|
|
2126
|
+
if (Token.isUnaryOrCount(op.token)) {
|
|
2127
|
+
return this.parseUnaryOrPrefixExpression();
|
|
2128
|
+
}
|
|
2129
|
+
if (op.isType(Token.AWAIT) && this.isAwaitAllowed()) {
|
|
2130
|
+
return this.parseAwaitExpression();
|
|
2131
|
+
}
|
|
2132
|
+
return this.parsePostfixExpression();
|
|
2133
|
+
}
|
|
2134
|
+
parseUnaryOrPrefixExpression() {
|
|
2135
|
+
const op = this.next();
|
|
2136
|
+
const expression = this.parseUnaryExpression();
|
|
2137
|
+
if (Token.isUnary(op.token)) {
|
|
2138
|
+
if (op.isType(Token.DELETE)) {
|
|
2139
|
+
if (this.isIdentifier(expression) && isStrict(this.languageMode)) {
|
|
2140
|
+
// "delete identifier" is a syntax error in strict mode.
|
|
2141
|
+
throw new Error(this.errorMessage(`"delete identifier" is a syntax error in strict mode`));
|
|
2142
|
+
}
|
|
2143
|
+
if (expression instanceof MemberExpression && expression.getProperty().toString().startsWith('#')) {
|
|
2144
|
+
throw new Error(this.errorMessage(`"Delete Private Field" is a syntax error`));
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
if (this.peek().isType(Token.EXP)) {
|
|
2148
|
+
throw new Error(this.errorMessage(`Unexpected Token Unary Exponentiation`));
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
if (Token.isCount(op.token) || Token.isUnary(op.token)) {
|
|
2152
|
+
// Allow the parser to rewrite the expression.
|
|
2153
|
+
return buildUnaryExpression(expression, op.token);
|
|
2154
|
+
}
|
|
2155
|
+
throw new Error(this.errorMessage(`while rewrite unary operation`));
|
|
2156
|
+
}
|
|
2157
|
+
parsePostfixExpression() {
|
|
2158
|
+
// PostfixExpression ::
|
|
2159
|
+
// LeftHandSideExpression ('++' | '--')?
|
|
2160
|
+
const expression = this.parseLeftHandSideExpression();
|
|
2161
|
+
if (!Token.isCount(this.peek().token) || this.scanner.hasLineTerminatorBeforeNext()) {
|
|
2162
|
+
return expression;
|
|
2163
|
+
}
|
|
2164
|
+
return this.parsePostfixContinuation(expression);
|
|
2165
|
+
}
|
|
2166
|
+
parsePostfixContinuation(expression) {
|
|
2167
|
+
if (!this.isValidReferenceExpression(expression)) {
|
|
2168
|
+
throw new Error(this.errorMessage(`Invalid LHS In Postfix Op.`));
|
|
2169
|
+
}
|
|
2170
|
+
const op = this.next();
|
|
2171
|
+
return buildPostfixExpression(expression, op.token);
|
|
2172
|
+
}
|
|
2173
|
+
parseLeftHandSideExpression() {
|
|
2174
|
+
// LeftHandSideExpression ::
|
|
2175
|
+
// (NewExpression | MemberExpression) ...
|
|
2176
|
+
const result = this.parseMemberExpression();
|
|
2177
|
+
if (!Token.isPropertyOrCall(this.peek().token))
|
|
2178
|
+
return result;
|
|
2179
|
+
return this.parseLeftHandSideContinuation(result);
|
|
2180
|
+
}
|
|
2181
|
+
parseLeftHandSideContinuation(result) {
|
|
2182
|
+
if (this.peek().isType(Token.LPAREN)
|
|
2183
|
+
&& this.isIdentifier(result)
|
|
2184
|
+
&& this.scanner.currentToken().isType(Token.ASYNC)
|
|
2185
|
+
&& !this.scanner.hasLineTerminatorBeforeNext()) {
|
|
2186
|
+
const args = this.parseArguments(ParsingArrowHeadFlag.AsyncArrowFunction);
|
|
2187
|
+
if (this.peek().isType(Token.ARROW)) {
|
|
2188
|
+
// async () => ...
|
|
2189
|
+
if (!args.length)
|
|
2190
|
+
return new EmptyStatement;
|
|
2191
|
+
// async ( Arguments ) => ...
|
|
2192
|
+
return this.expressionListToExpression(args);
|
|
2193
|
+
}
|
|
2194
|
+
result = new CallExpression(result, args);
|
|
2195
|
+
if (!Token.isPropertyOrCall(this.peek().token))
|
|
2196
|
+
return result;
|
|
2197
|
+
}
|
|
2198
|
+
let optionalChaining = false;
|
|
2199
|
+
let isOptional = false;
|
|
2200
|
+
do {
|
|
2201
|
+
switch (this.peek().token) {
|
|
2202
|
+
// chain
|
|
2203
|
+
case Token.QUESTION_PERIOD: {
|
|
2204
|
+
if (isOptional) {
|
|
2205
|
+
throw new Error(this.errorMessage(`Failure Expression`));
|
|
2206
|
+
}
|
|
2207
|
+
this.consume(Token.QUESTION_PERIOD);
|
|
2208
|
+
isOptional = true;
|
|
2209
|
+
optionalChaining = true;
|
|
2210
|
+
if (Token.isPropertyOrCall(this.peek().token))
|
|
2211
|
+
continue;
|
|
2212
|
+
const key = this.parsePropertyOrPrivatePropertyName();
|
|
2213
|
+
result = new MemberExpression(result, key, false, isOptional);
|
|
2214
|
+
break;
|
|
2215
|
+
}
|
|
2216
|
+
/* Property */
|
|
2217
|
+
case Token.LBRACK: {
|
|
2218
|
+
this.consume(Token.LBRACK);
|
|
2219
|
+
this.setAcceptIN(true);
|
|
2220
|
+
const index = this.parseExpressionCoverGrammar();
|
|
2221
|
+
this.restoreAcceptIN();
|
|
2222
|
+
result = new MemberExpression(result, index, true, isOptional);
|
|
2223
|
+
this.expect(Token.RBRACK);
|
|
2224
|
+
break;
|
|
2225
|
+
}
|
|
2226
|
+
/* Property */
|
|
2227
|
+
case Token.PERIOD: {
|
|
2228
|
+
if (isOptional) {
|
|
2229
|
+
throw new Error(this.errorMessage(`Unexpected Token:${this.position()}`));
|
|
2230
|
+
}
|
|
2231
|
+
this.consume(Token.PERIOD);
|
|
2232
|
+
const key = this.parsePropertyOrPrivatePropertyName();
|
|
2233
|
+
result = new MemberExpression(result, key, false, isOptional);
|
|
2234
|
+
break;
|
|
2235
|
+
}
|
|
2236
|
+
/* Call */
|
|
2237
|
+
case Token.LPAREN: {
|
|
2238
|
+
const args = this.parseArguments();
|
|
2239
|
+
result = new CallExpression(result, args, isOptional);
|
|
2240
|
+
break;
|
|
2241
|
+
}
|
|
2242
|
+
/* bind call */
|
|
2243
|
+
case Token.BIND: {
|
|
2244
|
+
if (isOptional) {
|
|
2245
|
+
throw new Error(this.errorMessage(`Unexpected Token:${this.position()}`));
|
|
2246
|
+
}
|
|
2247
|
+
this.consume(Token.BIND);
|
|
2248
|
+
const key = this.parsePropertyOrPrivatePropertyName();
|
|
2249
|
+
result = new BindExpression(result, key, false, isOptional);
|
|
2250
|
+
break;
|
|
2251
|
+
}
|
|
2252
|
+
/* chain bind call */
|
|
2253
|
+
case Token.QUESTION_BIND: {
|
|
2254
|
+
if (isOptional) {
|
|
2255
|
+
throw new Error(this.errorMessage(`Failure Expression`));
|
|
2256
|
+
}
|
|
2257
|
+
this.consume(Token.QUESTION_BIND);
|
|
2258
|
+
isOptional = true;
|
|
2259
|
+
optionalChaining = true;
|
|
2260
|
+
const key = this.parsePropertyOrPrivatePropertyName();
|
|
2261
|
+
result = new BindExpression(result, key, true, isOptional);
|
|
2262
|
+
break;
|
|
2263
|
+
}
|
|
2264
|
+
default:
|
|
2265
|
+
// Template literals in/after an Optional Chain not supported:
|
|
2266
|
+
if (optionalChaining) {
|
|
2267
|
+
throw new Error(this.errorMessage(`Optional Chaining No Template support`));
|
|
2268
|
+
}
|
|
2269
|
+
/* Tagged Template */
|
|
2270
|
+
result = this.parseTemplateLiteral(result);
|
|
2271
|
+
break;
|
|
2272
|
+
}
|
|
2273
|
+
if (isOptional) {
|
|
2274
|
+
isOptional = false;
|
|
2275
|
+
}
|
|
2276
|
+
} while (Token.isPropertyOrCall(this.peek().token));
|
|
2277
|
+
if (optionalChaining) {
|
|
2278
|
+
result = new ChainExpression(result);
|
|
2279
|
+
}
|
|
2280
|
+
return result;
|
|
2281
|
+
}
|
|
2282
|
+
parseAwaitExpression() {
|
|
2283
|
+
this.consume(Token.AWAIT);
|
|
2284
|
+
const value = this.parseUnaryExpression();
|
|
2285
|
+
if (this.peek().isType(Token.EXP)) {
|
|
2286
|
+
throw new Error(this.scanner.createError(`Unexpected Token Unary Exponentiation`));
|
|
2287
|
+
}
|
|
2288
|
+
return buildUnaryExpression(value, Token.AWAIT);
|
|
2289
|
+
}
|
|
2290
|
+
parseNullishExpression(expression) {
|
|
2291
|
+
// CoalesceExpression ::
|
|
2292
|
+
// CoalesceExpressionHead ?? BitwiseORExpression
|
|
2293
|
+
//
|
|
2294
|
+
// CoalesceExpressionHead ::
|
|
2295
|
+
// CoalesceExpression
|
|
2296
|
+
// BitwiseORExpression
|
|
2297
|
+
// We create a binary operation for the first nullish, otherwise collapse
|
|
2298
|
+
// into an nary expression.
|
|
2299
|
+
const list = [];
|
|
2300
|
+
list.push(expression);
|
|
2301
|
+
while (this.peek().isType(Token.NULLISH)) {
|
|
2302
|
+
this.consume(Token.NULLISH);
|
|
2303
|
+
// Parse BitwiseOR or higher.
|
|
2304
|
+
expression = this.parseBinaryExpression(6);
|
|
2305
|
+
list.push(expression);
|
|
2306
|
+
}
|
|
2307
|
+
expression = list.pop();
|
|
2308
|
+
expression = list.reverse()
|
|
2309
|
+
.reduce((previous, current) => new LogicalExpression(Token.NULLISH.getName(), current, previous), expression);
|
|
2310
|
+
return expression;
|
|
2311
|
+
}
|
|
2312
|
+
parseConditionalContinuation(expression) {
|
|
2313
|
+
this.consume(Token.CONDITIONAL);
|
|
2314
|
+
this.setAcceptIN(true);
|
|
2315
|
+
const left = this.parseAssignmentExpression();
|
|
2316
|
+
this.restoreAcceptIN();
|
|
2317
|
+
this.expect(Token.COLON);
|
|
2318
|
+
const right = this.parseAssignmentExpression();
|
|
2319
|
+
return new ConditionalExpression(expression, left, right);
|
|
2320
|
+
}
|
|
2321
|
+
parseYieldExpression() {
|
|
2322
|
+
// YieldExpression ::
|
|
2323
|
+
// 'yield' ([no line terminator] '*'? AssignmentExpression)?
|
|
2324
|
+
this.consume(Token.YIELD);
|
|
2325
|
+
let delegating = false; // yield*
|
|
2326
|
+
let expression;
|
|
2327
|
+
if (!this.scanner.hasLineTerminatorBeforeNext()) {
|
|
2328
|
+
if (this.check(Token.MUL)) {
|
|
2329
|
+
delegating = true;
|
|
2330
|
+
}
|
|
2331
|
+
switch (this.peek().token) {
|
|
2332
|
+
case Token.EOS:
|
|
2333
|
+
case Token.SEMICOLON:
|
|
2334
|
+
case Token.RBRACE:
|
|
2335
|
+
case Token.RBRACK:
|
|
2336
|
+
case Token.RPAREN:
|
|
2337
|
+
case Token.COLON:
|
|
2338
|
+
case Token.COMMA:
|
|
2339
|
+
case Token.IN:
|
|
2340
|
+
// The above set of tokens is the complete set of tokens that can appear
|
|
2341
|
+
// after an AssignmentExpression, and none of them can start an
|
|
2342
|
+
// AssignmentExpression. This allows us to avoid looking for an RHS for
|
|
2343
|
+
// a regular yield, given only one look-ahead token.
|
|
2344
|
+
if (!delegating)
|
|
2345
|
+
break;
|
|
2346
|
+
// Delegating yields require an RHS; fall through.
|
|
2347
|
+
// V8_FALLTHROUGH;
|
|
2348
|
+
throw new Error(this.errorMessage(`Delegating yields require an RHS`));
|
|
2349
|
+
default:
|
|
2350
|
+
expression = this.parseAssignmentExpressionCoverGrammar();
|
|
2351
|
+
break;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
return new YieldExpression(delegating, expression);
|
|
2355
|
+
}
|
|
2356
|
+
parseNewTargetExpression() {
|
|
2357
|
+
throw new Error(this.errorMessage('Expression (new.target) not supported.'));
|
|
2358
|
+
}
|
|
2359
|
+
parseClassExpression() {
|
|
2360
|
+
throw new Error(this.errorMessage(`Expression (class) not supported.`));
|
|
2361
|
+
}
|
|
2362
|
+
parseClassDeclaration(names, defaultExport) {
|
|
2363
|
+
throw new Error(this.errorMessage(`Expression (class) not supported.`));
|
|
2364
|
+
}
|
|
2365
|
+
parseClassLiteral(name, isStrictReserved) {
|
|
2366
|
+
throw new Error(this.errorMessage(`Expression (class) not supported.`));
|
|
2367
|
+
}
|
|
2368
|
+
parseSuperExpression() {
|
|
2369
|
+
throw new Error(this.errorMessage('Expression (supper) not supported.'));
|
|
2370
|
+
}
|
|
2371
|
+
parseImportExpressions() {
|
|
2372
|
+
throw new Error(this.errorMessage('Expression (import) not supported.'));
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
//# sourceMappingURL=inline.js.map
|