@ibyar/expressions 0.5.6 → 0.6.1
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/api/abstract.js +5 -0
- package/api/abstract.js.map +1 -1
- package/api/class/class.d.ts +28 -13
- package/api/class/class.js +46 -41
- package/api/class/class.js.map +1 -1
- package/api/computing/return.d.ts +4 -0
- package/api/computing/return.js +5 -0
- package/api/computing/return.js.map +1 -1
- package/api/computing/throw.d.ts +4 -0
- package/api/computing/throw.js +4 -0
- package/api/computing/throw.js.map +1 -1
- package/api/definition/bind.d.ts +6 -0
- package/api/definition/bind.js +6 -0
- package/api/definition/bind.js.map +1 -1
- package/api/definition/function.js +6 -5
- package/api/definition/function.js.map +1 -1
- package/api/definition/member.js.map +1 -1
- package/api/definition/object.js +1 -1
- package/api/definition/object.js.map +1 -1
- package/api/definition/values.d.ts +12 -3
- package/api/definition/values.js +25 -4
- package/api/definition/values.js.map +1 -1
- package/api/deserialize/deserialize.d.ts +5 -0
- package/api/deserialize/deserialize.js +5 -0
- package/api/deserialize/deserialize.js.map +1 -1
- package/api/expression.d.ts +151 -5
- package/api/expression.js.map +1 -1
- package/api/module/export.d.ts +63 -0
- package/api/module/export.js +64 -1
- package/api/module/export.js.map +1 -1
- package/api/module/import.d.ts +53 -0
- package/api/module/import.js +53 -0
- package/api/module/import.js.map +1 -1
- package/api/operators/grouping.d.ts +7 -0
- package/api/operators/grouping.js +7 -0
- package/api/operators/grouping.js.map +1 -1
- package/api/operators/pipeline.d.ts +12 -0
- package/api/operators/pipeline.js +12 -0
- package/api/operators/pipeline.js.map +1 -1
- package/api/operators/unary.js +3 -0
- package/api/operators/unary.js.map +1 -1
- package/api/program.d.ts +2 -2
- package/api/program.js.map +1 -1
- package/api/statement/control/block.d.ts +4 -0
- package/api/statement/control/block.js +4 -0
- package/api/statement/control/block.js.map +1 -1
- package/api/statement/control/empty.d.ts +7 -0
- package/api/statement/control/empty.js +7 -0
- package/api/statement/control/empty.js.map +1 -1
- package/api/statement/control/if.d.ts +5 -0
- package/api/statement/control/if.js +5 -0
- package/api/statement/control/if.js.map +1 -1
- package/api/statement/control/switch.d.ts +6 -0
- package/api/statement/control/switch.js +9 -0
- package/api/statement/control/switch.js.map +1 -1
- package/api/statement/control/terminate.d.ts +8 -0
- package/api/statement/control/terminate.js +8 -0
- package/api/statement/control/terminate.js.map +1 -1
- package/api/statement/iterations/for.d.ts +5 -0
- package/api/statement/iterations/for.js +13 -0
- package/api/statement/iterations/for.js.map +1 -1
- package/api/statement/iterations/while.d.ts +6 -0
- package/api/statement/iterations/while.js +10 -0
- package/api/statement/iterations/while.js.map +1 -1
- package/package.json +5 -3
- package/scope/event.d.ts +3 -3
- package/scope/event.js +2 -2
- package/scope/event.js.map +1 -1
- package/scope/pool.d.ts +7 -0
- package/scope/pool.js +29 -0
- package/scope/pool.js.map +1 -0
- package/scope/proxy.d.ts +6 -9
- package/scope/proxy.js +22 -31
- package/scope/proxy.js.map +1 -1
- package/scope/scope.d.ts +161 -38
- package/scope/scope.js +260 -106
- package/scope/scope.js.map +1 -1
- package/scope/stack.d.ts +95 -19
- package/scope/stack.js +13 -0
- package/scope/stack.js.map +1 -1
- package/v8/enums.js +31 -0
- package/v8/enums.js.map +1 -1
- package/v8/inline.d.ts +36 -0
- package/v8/inline.js +407 -5
- package/v8/inline.js.map +1 -1
- package/v8/nodes.js +2 -1
- package/v8/nodes.js.map +1 -1
- package/v8/parser.d.ts +8 -0
- package/v8/parser.js +304 -1
- package/v8/parser.js.map +1 -1
- package/v8/stream.d.ts +4 -0
- package/v8/stream.js +79 -17
- package/v8/stream.js.map +1 -1
- package/v8/token.d.ts +229 -0
- package/v8/token.js +236 -1
- package/v8/token.js.map +1 -1
- package/visit/visitor.d.ts +3 -0
package/v8/inline.js
CHANGED
|
@@ -172,7 +172,11 @@ export class AbstractParser {
|
|
|
172
172
|
case Token.LBRACK:
|
|
173
173
|
case Token.IDENTIFIER:
|
|
174
174
|
case Token.STATIC:
|
|
175
|
-
case Token.LET:
|
|
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.
|
|
176
180
|
case Token.YIELD:
|
|
177
181
|
case Token.AWAIT:
|
|
178
182
|
case Token.GET:
|
|
@@ -196,6 +200,7 @@ export class AbstractParser {
|
|
|
196
200
|
return Reflect.get(expression, 'parenthesized') === true;
|
|
197
201
|
}
|
|
198
202
|
isAssignableIdentifier(expression) {
|
|
203
|
+
// return expression instanceof AssignmentNode;
|
|
199
204
|
if (!(expression instanceof Identifier)) {
|
|
200
205
|
return false;
|
|
201
206
|
}
|
|
@@ -312,6 +317,24 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
312
317
|
}
|
|
313
318
|
return new ExpressionStatement(list);
|
|
314
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
|
+
*/
|
|
315
338
|
parseStatement(allowFunction = AllowLabelledFunctionStatement.DisallowLabelledFunctionStatement) {
|
|
316
339
|
switch (this.peek().token) {
|
|
317
340
|
case Token.LBRACE:
|
|
@@ -362,6 +385,16 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
362
385
|
return DebuggerStatement.INSTANCE;
|
|
363
386
|
}
|
|
364
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
|
|
365
398
|
this.consume(Token.TRY);
|
|
366
399
|
const tryBlock = this.parseBlock();
|
|
367
400
|
let peek = this.peek();
|
|
@@ -414,6 +447,24 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
414
447
|
this.expect(Token.RBRACE);
|
|
415
448
|
return block;
|
|
416
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
|
+
*/
|
|
417
468
|
parseStatementListItem() {
|
|
418
469
|
switch (this.peek().token) {
|
|
419
470
|
case Token.FUNCTION:
|
|
@@ -453,6 +504,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
453
504
|
return this.parseFunctionLiteral(functionKind, functionSyntaxKind, name);
|
|
454
505
|
}
|
|
455
506
|
parseAsyncFunctionDeclaration(names, defaultExport) {
|
|
507
|
+
// AsyncFunctionDeclaration ::
|
|
508
|
+
// async [no LineTerminator here] function BindingIdentifier[Await]
|
|
509
|
+
// ( FormalParameters[Await] ) { AsyncFunctionBody }
|
|
456
510
|
if (this.scanner.hasLineTerminatorBeforeNext()) {
|
|
457
511
|
throw new SyntaxError(this.errorMessage('Line Terminator Before `function` parsing `async function`.'));
|
|
458
512
|
}
|
|
@@ -481,6 +535,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
481
535
|
}
|
|
482
536
|
}
|
|
483
537
|
parseDoWhileStatement() {
|
|
538
|
+
// DoStatement ::
|
|
539
|
+
// 'do' Statement 'while' '(' Expression ')' ';'
|
|
484
540
|
this.consume(Token.DO);
|
|
485
541
|
const body = this.parseStatement();
|
|
486
542
|
this.expect(Token.WHILE);
|
|
@@ -491,6 +547,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
491
547
|
return new DoWhileNode(condition, body);
|
|
492
548
|
}
|
|
493
549
|
parseWhileStatement() {
|
|
550
|
+
// WhileStatement ::
|
|
551
|
+
// 'while' '(' Expression ')' Statement
|
|
494
552
|
this.consume(Token.WHILE);
|
|
495
553
|
this.expect(Token.LPAREN);
|
|
496
554
|
const condition = this.parseExpression();
|
|
@@ -499,6 +557,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
499
557
|
return new WhileNode(condition, body);
|
|
500
558
|
}
|
|
501
559
|
parseThrowStatement() {
|
|
560
|
+
// ThrowStatement ::
|
|
561
|
+
// 'throw' Expression ';'
|
|
502
562
|
this.consume(Token.THROW);
|
|
503
563
|
if (this.scanner.hasLineTerminatorBeforeNext()) {
|
|
504
564
|
throw new Error(this.scanner.createError(`New line After Throw`));
|
|
@@ -508,6 +568,11 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
508
568
|
return new ThrowStatement(exception);
|
|
509
569
|
}
|
|
510
570
|
parseSwitchStatement() {
|
|
571
|
+
// SwitchStatement ::
|
|
572
|
+
// 'switch' '(' Expression ')' '{' CaseClause* '}'
|
|
573
|
+
// CaseClause ::
|
|
574
|
+
// 'case' Expression ':' StatementList
|
|
575
|
+
// 'default' ':' StatementList
|
|
511
576
|
this.consume(Token.SWITCH);
|
|
512
577
|
this.expect(Token.LPAREN);
|
|
513
578
|
const tag = this.parseExpression();
|
|
@@ -547,31 +612,58 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
547
612
|
return switchStatement;
|
|
548
613
|
}
|
|
549
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_);
|
|
550
623
|
this.consume(Token.FOR);
|
|
551
624
|
this.expect(Token.LPAREN);
|
|
552
625
|
const peek = this.peek();
|
|
553
626
|
const starts_with_let = peek.isType(Token.LET);
|
|
554
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_);
|
|
555
634
|
const initializer = this.parseVariableDeclarations(VariableDeclarationContext.ForStatement);
|
|
556
635
|
const forMode = this.checkInOrOf();
|
|
557
636
|
if (forMode) {
|
|
558
637
|
return this.parseForEachStatementWithDeclarations(initializer, forMode);
|
|
559
638
|
}
|
|
560
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.
|
|
561
643
|
return this.parseStandardForLoopWithLexicalDeclarations(initializer);
|
|
562
644
|
}
|
|
563
645
|
let initializer;
|
|
564
646
|
if (peek.isType(Token.VAR)) {
|
|
565
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;
|
|
566
651
|
const forMode = this.checkInOrOf();
|
|
567
652
|
if (forMode) {
|
|
568
653
|
return this.parseForEachStatementWithDeclarations(initializer, forMode);
|
|
569
654
|
}
|
|
655
|
+
// init = impl() -> BuildInitializationBlock(& for_info.parsing_result);
|
|
570
656
|
}
|
|
571
657
|
else if (this.peek().isNotType(Token.SEMICOLON)) {
|
|
658
|
+
// The initializer does not contain declarations.
|
|
572
659
|
this.setAcceptIN(false);
|
|
573
660
|
initializer = this.parseExpressionCoverGrammar();
|
|
574
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.
|
|
575
667
|
const expression_is_async = this.current().isType(Token.ASYNC);
|
|
576
668
|
const forMode = this.checkInOrOf();
|
|
577
669
|
if (forMode) {
|
|
@@ -585,9 +677,12 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
585
677
|
return this.parseStandardForLoop(initializer);
|
|
586
678
|
}
|
|
587
679
|
parseStandardForLoopWithLexicalDeclarations(initializer) {
|
|
680
|
+
// The condition and the next statement of the for loop must be parsed
|
|
681
|
+
// in a new scope.
|
|
588
682
|
return this.parseStandardForLoop(initializer);
|
|
589
683
|
}
|
|
590
684
|
parseForEachStatementWithDeclarations(initializer, forMode) {
|
|
685
|
+
// Just one declaration followed by in/of.
|
|
591
686
|
if (initializer.getDeclarations().length != 1) {
|
|
592
687
|
throw new SyntaxError(this.errorMessage('For In/Of loop Multi Bindings'));
|
|
593
688
|
}
|
|
@@ -616,6 +711,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
616
711
|
}
|
|
617
712
|
}
|
|
618
713
|
parseStandardForLoop(initializer) {
|
|
714
|
+
// CheckStackOverflow();
|
|
715
|
+
// ForStatementT loop = factory() -> NewForStatement(stmt_pos);
|
|
716
|
+
// Target target(this, loop, labels, own_labels, Target:: TARGET_FOR_ANONYMOUS);
|
|
619
717
|
let cond = new EmptyStatement();
|
|
620
718
|
if (this.peek().isNotType(Token.SEMICOLON)) {
|
|
621
719
|
cond = this.parseExpression();
|
|
@@ -630,6 +728,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
630
728
|
return new ForNode(body, initializer, cond, next);
|
|
631
729
|
}
|
|
632
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_);
|
|
633
734
|
if (!this.isAwaitAllowed()) {
|
|
634
735
|
throw new SyntaxError(this.errorMessage('"await" is not allowed'));
|
|
635
736
|
}
|
|
@@ -637,11 +738,17 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
637
738
|
this.expect(Token.AWAIT);
|
|
638
739
|
this.expect(Token.LPAREN);
|
|
639
740
|
let hasDeclarations = false;
|
|
741
|
+
// Scope * inner_block_scope = NewScope(BLOCK_SCOPE);
|
|
640
742
|
let eachVariable;
|
|
641
743
|
let peek = this.peek();
|
|
642
744
|
let startsWithLet = peek.isType(Token.LET);
|
|
643
745
|
if (peek.isType(Token.VAR) || peek.isType(Token.CONST)
|
|
644
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
|
|
645
752
|
hasDeclarations = true;
|
|
646
753
|
const initializer = this.parseVariableDeclarations(VariableDeclarationContext.ForStatement);
|
|
647
754
|
if (initializer.getDeclarations().length != 1) {
|
|
@@ -650,6 +757,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
650
757
|
eachVariable = initializer;
|
|
651
758
|
}
|
|
652
759
|
else {
|
|
760
|
+
// The initializer does not contain declarations.
|
|
761
|
+
// 'for' 'await' '(' LeftHandSideExpression 'of' AssignmentExpression ')'
|
|
762
|
+
// Statement
|
|
653
763
|
if (startsWithLet) {
|
|
654
764
|
throw new SyntaxError(this.errorMessage('The initializer does not contain declarations, For Of Let, "for-await-of"'));
|
|
655
765
|
}
|
|
@@ -664,6 +774,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
664
774
|
return new ForAwaitOfNode(eachVariable, iterable, body);
|
|
665
775
|
}
|
|
666
776
|
parseVariableDeclarations(varContext) {
|
|
777
|
+
// VariableDeclarations ::
|
|
778
|
+
// ('var' | 'const' | 'let') (Identifier ('=' AssignmentExpression)?)+[',']
|
|
779
|
+
// var converted into ==> 'let' by parser
|
|
667
780
|
let mode;
|
|
668
781
|
const token = this.peek().token;
|
|
669
782
|
switch (token) {
|
|
@@ -685,11 +798,17 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
685
798
|
do {
|
|
686
799
|
let name;
|
|
687
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).
|
|
688
803
|
if (Token.isAnyIdentifier(this.peek().token)) {
|
|
689
804
|
name = this.parseAndClassifyIdentifier(this.next());
|
|
690
805
|
if (isStrict(this.languageMode) && this.isEvalOrArguments(name)) {
|
|
691
806
|
throw new Error(this.errorMessage(`Strict Eval Arguments`));
|
|
692
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
|
+
// }
|
|
693
812
|
}
|
|
694
813
|
else {
|
|
695
814
|
name = this.parseBindingPattern(true);
|
|
@@ -700,15 +819,21 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
700
819
|
this.restoreAcceptIN();
|
|
701
820
|
}
|
|
702
821
|
else if (!this.peekInOrOf()) {
|
|
822
|
+
// ES6 'const' and binding patterns require initializers.
|
|
703
823
|
if (mode === 'const' && (name === undefined || value === undefined)) {
|
|
704
824
|
throw new Error(this.errorMessage(`Declaration Missing Initializer`));
|
|
705
825
|
}
|
|
826
|
+
// value = undefined;
|
|
706
827
|
}
|
|
707
828
|
variables.push(new VariableDeclarator(name, value));
|
|
708
829
|
} while (this.check(Token.COMMA));
|
|
709
830
|
return new VariableDeclarationNode(variables, mode);
|
|
710
831
|
}
|
|
711
832
|
parseBindingPattern(isPattern) {
|
|
833
|
+
// Pattern ::
|
|
834
|
+
// Identifier
|
|
835
|
+
// ArrayLiteral
|
|
836
|
+
// ObjectLiteral
|
|
712
837
|
const token = this.peek().token;
|
|
713
838
|
if (Token.isAnyIdentifier(token)) {
|
|
714
839
|
const name = this.parseAndClassifyIdentifier(this.next());
|
|
@@ -728,6 +853,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
728
853
|
}
|
|
729
854
|
}
|
|
730
855
|
parseAndClassifyIdentifier(next) {
|
|
856
|
+
// Updates made here must be reflected on ClassifyPropertyIdentifier.
|
|
731
857
|
if (Token.isInRangeIdentifierAndAsync(next.token)) {
|
|
732
858
|
const name = next.getValue();
|
|
733
859
|
if (this.isArguments(name) && this.shouldBanArguments()) {
|
|
@@ -744,30 +870,48 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
744
870
|
return next.getValue();
|
|
745
871
|
}
|
|
746
872
|
parseContinueStatement() {
|
|
873
|
+
// ContinueStatement ::
|
|
874
|
+
// 'continue' ';'
|
|
875
|
+
// Identifier? is not supported
|
|
747
876
|
this.consume(Token.CONTINUE);
|
|
748
877
|
let label;
|
|
749
878
|
if (!this.scanner.hasLineTerminatorBeforeNext() &&
|
|
750
879
|
!Token.isAutoSemicolon(this.peek().token)) {
|
|
880
|
+
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
|
751
881
|
label = this.parseIdentifier();
|
|
752
882
|
}
|
|
753
883
|
this.expectSemicolon();
|
|
754
884
|
return label ? new ContinueStatement(label) : ContinueStatement.CONTINUE_INSTANCE;
|
|
755
885
|
}
|
|
756
886
|
parseBreakStatement() {
|
|
887
|
+
// BreakStatement ::
|
|
888
|
+
// 'break' ';'
|
|
889
|
+
// Identifier? is not supported
|
|
757
890
|
this.consume(Token.BREAK);
|
|
758
891
|
let label;
|
|
759
892
|
if (!this.scanner.hasLineTerminatorBeforeNext() &&
|
|
760
893
|
!Token.isAutoSemicolon(this.peek().token)) {
|
|
894
|
+
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
|
761
895
|
label = this.parseIdentifier();
|
|
762
896
|
}
|
|
763
897
|
this.expectSemicolon();
|
|
764
898
|
return label ? new BreakStatement(label) : BreakStatement.BREAK_INSTANCE;
|
|
765
899
|
}
|
|
766
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).
|
|
767
906
|
this.consume(Token.RETURN);
|
|
768
907
|
const tokenExp = this.peek();
|
|
769
908
|
let returnValue;
|
|
909
|
+
// ExpressionT return_value = impl() -> NullExpression();
|
|
770
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
|
+
// }
|
|
771
915
|
}
|
|
772
916
|
else {
|
|
773
917
|
returnValue = this.parseExpression();
|
|
@@ -776,6 +920,12 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
776
920
|
return new ReturnStatement(returnValue);
|
|
777
921
|
}
|
|
778
922
|
parseExpressionOrLabelledStatement(allowFunction) {
|
|
923
|
+
// ExpressionStatement | LabelledStatement ::
|
|
924
|
+
// Expression ';'
|
|
925
|
+
// Identifier ':' Statement
|
|
926
|
+
//
|
|
927
|
+
// ExpressionStatement[Yield] :
|
|
928
|
+
// [lookahead notin {{, function, class, let [}] Expression[In, ?Yield] ;
|
|
779
929
|
switch (this.peek().token) {
|
|
780
930
|
case Token.FUNCTION:
|
|
781
931
|
case Token.LBRACE:
|
|
@@ -784,6 +934,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
784
934
|
throw new Error(this.errorMessage(`Unexpected Token ${this.next().getValue().toString()}`));
|
|
785
935
|
case Token.LET: {
|
|
786
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.
|
|
787
940
|
if (nextNext.isNotType(Token.LBRACK) &&
|
|
788
941
|
((nextNext.isNotType(Token.LBRACE) && nextNext.isNotType(Token.IDENTIFIER)))) {
|
|
789
942
|
break;
|
|
@@ -797,7 +950,13 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
797
950
|
this.setAcceptIN(true);
|
|
798
951
|
const expression = this.parseExpressionCoverGrammar();
|
|
799
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.
|
|
800
958
|
this.consume(Token.COLON);
|
|
959
|
+
// ES#sec-labelled-function-declarations Labelled Function Declarations
|
|
801
960
|
if (this.peek().isType(Token.FUNCTION)
|
|
802
961
|
&& isSloppy(this.languageMode)
|
|
803
962
|
&& allowFunction == AllowLabelledFunctionStatement.AllowLabelledFunctionStatement) {
|
|
@@ -810,6 +969,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
810
969
|
return new LabeledStatement(expression, result);
|
|
811
970
|
}
|
|
812
971
|
this.restoreAcceptIN();
|
|
972
|
+
// Parsed expression statement, followed by semicolon.
|
|
813
973
|
this.expectSemicolon();
|
|
814
974
|
return expression;
|
|
815
975
|
}
|
|
@@ -827,6 +987,12 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
827
987
|
return this.parseHoistableDeclaration01(FunctionKind.NormalFunction, undefined, false);
|
|
828
988
|
}
|
|
829
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 }
|
|
830
996
|
if (this.current().isNotType(Token.ASYNC)) {
|
|
831
997
|
throw new SyntaxError(this.errorMessage('invalid token'));
|
|
832
998
|
}
|
|
@@ -852,7 +1018,19 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
852
1018
|
return this.parseHoistableDeclaration01(flags, names, defaultExport);
|
|
853
1019
|
}
|
|
854
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);
|
|
855
1032
|
if ((flag & ParseFunctionFlag.IsAsync) != 0 && this.check(Token.MUL)) {
|
|
1033
|
+
// Async generator
|
|
856
1034
|
flag |= ParseFunctionFlag.IsGenerator;
|
|
857
1035
|
}
|
|
858
1036
|
let name;
|
|
@@ -910,6 +1088,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
910
1088
|
return current.getValue();
|
|
911
1089
|
}
|
|
912
1090
|
parseFunctionLiteral(flag, functionSyntaxKind, name) {
|
|
1091
|
+
// Function ::
|
|
1092
|
+
// '(' FormalParameterList? ')' '{' FunctionBody '}'
|
|
913
1093
|
this.setFunctionKind(flag);
|
|
914
1094
|
const functionInfo = {};
|
|
915
1095
|
this.expect(Token.LPAREN);
|
|
@@ -927,11 +1107,17 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
927
1107
|
return new FunctionExpression(formals, bodyBlock, isAsyncFunction(flag), isGeneratorFunction(flag));
|
|
928
1108
|
}
|
|
929
1109
|
parseFunctionBody(kind, bodyType, functionSyntaxKind) {
|
|
1110
|
+
// Building the parameter initialization block declares the parameters.
|
|
1111
|
+
// TODO(verwaest): Rely on ArrowHeadParsingScope instead.
|
|
930
1112
|
let innerBody;
|
|
931
1113
|
if (bodyType == FunctionBodyType.EXPRESSION) {
|
|
932
1114
|
innerBody = this.parseAssignmentExpression();
|
|
933
1115
|
}
|
|
934
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.
|
|
935
1121
|
const closing_token = functionSyntaxKind == FunctionSyntaxKind.Wrapped ? Token.EOS : Token.RBRACE;
|
|
936
1122
|
if (isAsyncGeneratorFunction(kind)) {
|
|
937
1123
|
innerBody = this.parseAndRewriteAsyncGeneratorFunctionBody(kind);
|
|
@@ -959,6 +1145,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
959
1145
|
return this.parseStatementList(Token.RBRACE);
|
|
960
1146
|
}
|
|
961
1147
|
parseStatementList(endToken) {
|
|
1148
|
+
// StatementList ::
|
|
1149
|
+
// (StatementListItem)* <end_token>
|
|
962
1150
|
if (this.peek().test((token, value) => Token.STRING === token && 'use strict' === value.getValue())) {
|
|
963
1151
|
this.languageMode = LanguageMode.Strict;
|
|
964
1152
|
}
|
|
@@ -976,6 +1164,16 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
976
1164
|
return list;
|
|
977
1165
|
}
|
|
978
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]
|
|
979
1177
|
const parameters = [];
|
|
980
1178
|
if (this.peek().isNotType(Token.RPAREN)) {
|
|
981
1179
|
while (true) {
|
|
@@ -990,6 +1188,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
990
1188
|
if (!this.check(Token.COMMA))
|
|
991
1189
|
break;
|
|
992
1190
|
if (this.peek().isType(Token.RPAREN)) {
|
|
1191
|
+
// allow the trailing comma
|
|
993
1192
|
break;
|
|
994
1193
|
}
|
|
995
1194
|
}
|
|
@@ -997,6 +1196,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
997
1196
|
return parameters;
|
|
998
1197
|
}
|
|
999
1198
|
parseFormalParameter(functionInfo) {
|
|
1199
|
+
// FormalParameter[Yield,GeneratorParameter] :
|
|
1200
|
+
// BindingElement[?Yield, ?GeneratorParameter]
|
|
1000
1201
|
functionInfo.rest = this.check(Token.ELLIPSIS);
|
|
1001
1202
|
let pattern = this.parseBindingPattern(true);
|
|
1002
1203
|
let initializer;
|
|
@@ -1015,6 +1216,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1015
1216
|
return initializer;
|
|
1016
1217
|
}
|
|
1017
1218
|
parseExpressionCoverGrammar() {
|
|
1219
|
+
// Expression ::
|
|
1220
|
+
// AssignmentExpression
|
|
1221
|
+
// Expression ',' AssignmentExpression
|
|
1018
1222
|
const list = [];
|
|
1019
1223
|
let expression;
|
|
1020
1224
|
while (true) {
|
|
@@ -1026,6 +1230,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1026
1230
|
if (!this.check(Token.COMMA))
|
|
1027
1231
|
break;
|
|
1028
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
|
|
1029
1234
|
break;
|
|
1030
1235
|
}
|
|
1031
1236
|
}
|
|
@@ -1042,6 +1247,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1042
1247
|
if (this.peek().isType(Token.COMMA)) {
|
|
1043
1248
|
throw new Error(this.errorMessage(`Error A rest parameter or binding pattern may not have a trailing comma`));
|
|
1044
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.
|
|
1045
1253
|
if (this.peek().isNotType(Token.RPAREN) || this.peekAhead().isNotType(Token.ARROW)) {
|
|
1046
1254
|
throw new Error(this.errorMessage(`Error Unexpected Token At ${this.position()}`));
|
|
1047
1255
|
}
|
|
@@ -1060,6 +1268,18 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1060
1268
|
return new SequenceExpression(list);
|
|
1061
1269
|
}
|
|
1062
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.
|
|
1063
1283
|
const result = this.parsePrimaryExpression();
|
|
1064
1284
|
return this.parseMemberExpressionContinuation(result);
|
|
1065
1285
|
}
|
|
@@ -1073,15 +1293,31 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1073
1293
|
return new Param(expression);
|
|
1074
1294
|
}
|
|
1075
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
|
|
1076
1310
|
let token = this.peek();
|
|
1077
1311
|
if (Token.isAnyIdentifier(token.token)) {
|
|
1078
1312
|
this.consume(token.token);
|
|
1079
1313
|
let kind = FunctionKind.NormalFunction;
|
|
1080
1314
|
if (token.isType(Token.ASYNC) && !this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1315
|
+
// async function ...
|
|
1081
1316
|
if (this.peek().isType(Token.FUNCTION)) {
|
|
1082
1317
|
return this.parseAsyncFunctionLiteral();
|
|
1083
1318
|
}
|
|
1084
1319
|
;
|
|
1320
|
+
// async Identifier => ...
|
|
1085
1321
|
if (Token.isAnyIdentifier(this.peek().token) && this.peekAhead().isType(Token.ARROW)) {
|
|
1086
1322
|
token = this.next();
|
|
1087
1323
|
kind = FunctionKind.AsyncFunction;
|
|
@@ -1114,6 +1350,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1114
1350
|
return ThisNode;
|
|
1115
1351
|
case Token.DIV:
|
|
1116
1352
|
case Token.DIV_ASSIGN:
|
|
1353
|
+
// case Token.REGEXP_LITERAL:
|
|
1354
|
+
// this.consume(Token.REGEXP_LITERAL);
|
|
1355
|
+
// return token.value!;
|
|
1117
1356
|
return this.parseRegExpLiteral();
|
|
1118
1357
|
case Token.FUNCTION:
|
|
1119
1358
|
return this.parseFunctionExpression();
|
|
@@ -1129,6 +1368,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1129
1368
|
case Token.LPAREN: {
|
|
1130
1369
|
this.consume(Token.LPAREN);
|
|
1131
1370
|
if (this.check(Token.RPAREN)) {
|
|
1371
|
+
// ()=>x. The continuation that consumes the => is in
|
|
1372
|
+
// ParseAssignmentExpressionCoverGrammar.
|
|
1132
1373
|
if (!this.peek().isType(Token.ARROW)) {
|
|
1133
1374
|
throw new Error(this.errorMessage(`Unexpected Token: ${Token.RPAREN.getName()}`));
|
|
1134
1375
|
}
|
|
@@ -1136,6 +1377,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1136
1377
|
this.markParenthesized(result);
|
|
1137
1378
|
return result;
|
|
1138
1379
|
}
|
|
1380
|
+
// Heuristically try to detect immediately called functions before
|
|
1381
|
+
// seeing the call parentheses.
|
|
1139
1382
|
this.setAcceptIN(true);
|
|
1140
1383
|
const expression = this.parseExpressionCoverGrammar();
|
|
1141
1384
|
this.markParenthesized(expression);
|
|
@@ -1155,10 +1398,23 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1155
1398
|
throw new Error(this.errorMessage(`Unexpected Token: ${JSON.stringify(this.next())}`));
|
|
1156
1399
|
}
|
|
1157
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.
|
|
1158
1411
|
let next = this.peek();
|
|
1159
1412
|
if (!Token.isTemplate(next.token)) {
|
|
1160
1413
|
throw new SyntaxError(this.errorMessage(`Unexpected Token: ${JSON.stringify(this.next())}`));
|
|
1161
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.
|
|
1162
1418
|
if (next.isType(Token.TEMPLATE_TAIL)) {
|
|
1163
1419
|
this.consume(Token.TEMPLATE_TAIL);
|
|
1164
1420
|
const string = next.getValue().string;
|
|
@@ -1168,6 +1424,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1168
1424
|
const expressions = [];
|
|
1169
1425
|
const strings = [];
|
|
1170
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).
|
|
1171
1430
|
do {
|
|
1172
1431
|
this.setAcceptIN(true);
|
|
1173
1432
|
const expression = this.parseExpressionCoverGrammar();
|
|
@@ -1177,6 +1436,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1177
1436
|
this.restoreAcceptIN();
|
|
1178
1437
|
throw new SyntaxError(this.errorMessage('Unterminated Template Expr'));
|
|
1179
1438
|
}
|
|
1439
|
+
// If we didn't die parsing that expression, our next token should be a
|
|
1440
|
+
// TEMPLATE_SPAN or TEMPLATE_TAIL.
|
|
1180
1441
|
next = this.scanner.scanTemplateContinuation();
|
|
1181
1442
|
strings.push(next.getValue().string);
|
|
1182
1443
|
this.restoreAcceptIN();
|
|
@@ -1184,6 +1445,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1184
1445
|
if (next.isNotType(Token.TEMPLATE_TAIL)) {
|
|
1185
1446
|
throw new SyntaxError(this.errorMessage(`Unexpected Token: ${JSON.stringify(next)}`));
|
|
1186
1447
|
}
|
|
1448
|
+
// Once we've reached a TEMPLATE_TAIL, we can close the TemplateLiteral.
|
|
1187
1449
|
return this.createTemplateLiteralExpressionNode(strings, expressions, tag);
|
|
1188
1450
|
}
|
|
1189
1451
|
createTemplateLiteralExpressionNode(strings, expressions, tag) {
|
|
@@ -1195,8 +1457,27 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1195
1457
|
}
|
|
1196
1458
|
}
|
|
1197
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)
|
|
1198
1478
|
this.consume(Token.NEW);
|
|
1199
1479
|
let result;
|
|
1480
|
+
// CheckStackOverflow();
|
|
1200
1481
|
if (this.peek().isType(Token.IMPORT) && this.peekAhead().isType(Token.LPAREN)) {
|
|
1201
1482
|
throw new SyntaxError(this.errorMessage(`Import Call Not New Expression`));
|
|
1202
1483
|
}
|
|
@@ -1207,12 +1488,15 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1207
1488
|
else {
|
|
1208
1489
|
result = this.parseMemberExpression();
|
|
1209
1490
|
if (result === SuperIdentifier) {
|
|
1491
|
+
// new super() is never allowed
|
|
1210
1492
|
throw new SyntaxError(this.errorMessage(`Unexpected Super, new super() is never allowed`));
|
|
1211
1493
|
}
|
|
1212
1494
|
}
|
|
1213
1495
|
if (this.peek().isType(Token.LPAREN)) {
|
|
1496
|
+
// NewExpression with arguments.
|
|
1214
1497
|
const args = this.parseArguments();
|
|
1215
1498
|
result = new NewExpression(result, args);
|
|
1499
|
+
// The expression can still continue with . or [ after the arguments.
|
|
1216
1500
|
return this.parseMemberExpressionContinuation(result);
|
|
1217
1501
|
}
|
|
1218
1502
|
if (this.peek().isType(Token.QUESTION_PERIOD)) {
|
|
@@ -1221,6 +1505,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1221
1505
|
return new NewExpression(result);
|
|
1222
1506
|
}
|
|
1223
1507
|
parseArguments(maybeArrow) {
|
|
1508
|
+
// Arguments ::
|
|
1509
|
+
// '(' (AssignmentExpression)*[','] ')'
|
|
1224
1510
|
this.consume(Token.LPAREN);
|
|
1225
1511
|
const args = [];
|
|
1226
1512
|
while (this.peek().isNotType(Token.RPAREN)) {
|
|
@@ -1253,6 +1539,11 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1253
1539
|
return args;
|
|
1254
1540
|
}
|
|
1255
1541
|
parseAssignmentExpressionCoverGrammar() {
|
|
1542
|
+
// AssignmentExpression ::
|
|
1543
|
+
// ConditionalExpression
|
|
1544
|
+
// ArrowFunction
|
|
1545
|
+
// YieldExpression
|
|
1546
|
+
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
|
1256
1547
|
if (this.peek().isType(Token.YIELD) && isGeneratorFunction(this.functionKind)) {
|
|
1257
1548
|
return this.parseYieldExpression();
|
|
1258
1549
|
}
|
|
@@ -1263,6 +1554,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1263
1554
|
return expression;
|
|
1264
1555
|
}
|
|
1265
1556
|
;
|
|
1557
|
+
// Arrow functions.
|
|
1266
1558
|
if (op === Token.ARROW) {
|
|
1267
1559
|
if (!this.isIdentifier(expression) && !this.isParenthesized(expression)) {
|
|
1268
1560
|
throw new Error(this.errorMessage(`Malformed Arrow Fun Param List`));
|
|
@@ -1301,9 +1593,11 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1301
1593
|
else if (this.isProperty(expression)) {
|
|
1302
1594
|
}
|
|
1303
1595
|
else if (this.isPattern(expression) && Token.isAssignment(op)) {
|
|
1596
|
+
// Destructuring assignment.
|
|
1304
1597
|
expression = expression instanceof ObjectExpression
|
|
1305
1598
|
? new ObjectPattern(expression.getProperties())
|
|
1306
1599
|
: new ArrayPattern(expression.getElements());
|
|
1600
|
+
// expression_scope() -> ValidateAsPattern(expression, lhs_beg_pos, end_position());
|
|
1307
1601
|
}
|
|
1308
1602
|
else {
|
|
1309
1603
|
if (!this.isValidReferenceExpression(expression)) {
|
|
@@ -1314,7 +1608,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1314
1608
|
}
|
|
1315
1609
|
}
|
|
1316
1610
|
this.consume(op);
|
|
1611
|
+
// const opPosition = this.position();
|
|
1317
1612
|
const right = this.parseAssignmentExpression();
|
|
1613
|
+
// Anonymous function name inference applies to =, ||=, &&=, and ??=.
|
|
1318
1614
|
if (!Token.isAssignment(op)) {
|
|
1319
1615
|
throw new Error(this.errorMessage(`Invalid Destructuring Target`));
|
|
1320
1616
|
}
|
|
@@ -1352,6 +1648,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1352
1648
|
return this.scanner.currentToken().getValue();
|
|
1353
1649
|
}
|
|
1354
1650
|
parseArrayLiteral(isPattern) {
|
|
1651
|
+
// ArrayLiteral ::
|
|
1652
|
+
// '[' Expression? (',' Expression?)* ']'
|
|
1355
1653
|
this.consume(Token.LBRACK);
|
|
1356
1654
|
let first_spread_index = -1;
|
|
1357
1655
|
const values = [];
|
|
@@ -1391,6 +1689,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1391
1689
|
return this.parseAssignmentExpressionCoverGrammar();
|
|
1392
1690
|
}
|
|
1393
1691
|
parseObjectLiteral(isPattern) {
|
|
1692
|
+
// ObjectLiteral ::
|
|
1693
|
+
// '{' (PropertyDefinition (',' PropertyDefinition)* ','? )? '}'
|
|
1394
1694
|
this.consume(Token.LBRACE);
|
|
1395
1695
|
const properties = [];
|
|
1396
1696
|
while (!this.check(Token.RBRACE)) {
|
|
@@ -1425,6 +1725,12 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1425
1725
|
case PropertyKind.Assign:
|
|
1426
1726
|
case PropertyKind.ShorthandOrClassField:
|
|
1427
1727
|
case PropertyKind.Shorthand: {
|
|
1728
|
+
// PropertyDefinition
|
|
1729
|
+
// IdentifierReference
|
|
1730
|
+
// CoverInitializedName
|
|
1731
|
+
//
|
|
1732
|
+
// CoverInitializedName
|
|
1733
|
+
// IdentifierReference Initializer?
|
|
1428
1734
|
const lhs = new Identifier(propInfo.name);
|
|
1429
1735
|
if (!this.isAssignableIdentifier(lhs)) {
|
|
1430
1736
|
throw new Error(this.errorMessage('Strict Eval Arguments'));
|
|
@@ -1443,6 +1749,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1443
1749
|
return new Property(nameExpression, value, 'init', false, propInfo.kind !== PropertyKind.Assign, propInfo.isComputedName);
|
|
1444
1750
|
}
|
|
1445
1751
|
case PropertyKind.Method: {
|
|
1752
|
+
// MethodDefinition
|
|
1753
|
+
// PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
|
1754
|
+
// '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}'
|
|
1446
1755
|
const kind = this.methodKindFor(propInfo.isStatic, propInfo.funcFlag);
|
|
1447
1756
|
const value = this.parseFunctionLiteral(kind, FunctionSyntaxKind.AccessorOrMethod, propInfo.name ? new Identifier(propInfo.name) : undefined);
|
|
1448
1757
|
return new Property(nameExpression, value, 'init', true, false, propInfo.isComputedName);
|
|
@@ -1462,6 +1771,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1462
1771
|
parseProperty(propInfo) {
|
|
1463
1772
|
let nextToken = this.peek();
|
|
1464
1773
|
if (this.check(Token.ASYNC)) {
|
|
1774
|
+
// async
|
|
1465
1775
|
nextToken = this.peek();
|
|
1466
1776
|
if (nextToken.isNotType(Token.MUL)
|
|
1467
1777
|
&& propInfo.parsePropertyKindFromToken(nextToken.token)
|
|
@@ -1472,6 +1782,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1472
1782
|
propInfo.funcFlag = ParseFunctionFlag.IsAsync;
|
|
1473
1783
|
}
|
|
1474
1784
|
if (this.check(Token.MUL)) {
|
|
1785
|
+
// async*
|
|
1475
1786
|
propInfo.kind = PropertyKind.Method;
|
|
1476
1787
|
propInfo.funcFlag = ParseFunctionFlag.IsGenerator;
|
|
1477
1788
|
}
|
|
@@ -1506,11 +1817,15 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1506
1817
|
case Token.STRING:
|
|
1507
1818
|
case Token.NUMBER:
|
|
1508
1819
|
case Token.BIGINT:
|
|
1820
|
+
// "12" -> 12
|
|
1821
|
+
// 12.3 -> "12.3"
|
|
1822
|
+
// 12.30 -> "12.3"
|
|
1509
1823
|
this.consume(nextToken.token);
|
|
1510
1824
|
propertyName = nextToken.getValue();
|
|
1511
1825
|
propInfo.name = propertyName.getValue();
|
|
1512
1826
|
break;
|
|
1513
1827
|
case Token.LBRACK:
|
|
1828
|
+
// [Symbol.iterator]
|
|
1514
1829
|
this.consume(Token.LBRACK);
|
|
1515
1830
|
this.setAcceptIN(true);
|
|
1516
1831
|
propertyName = this.parseAssignmentExpression();
|
|
@@ -1556,6 +1871,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1556
1871
|
if (!Token.isMember(this.peek().token)) {
|
|
1557
1872
|
throw new Error(this.errorMessage(`Parsing member expression`));
|
|
1558
1873
|
}
|
|
1874
|
+
// Parses this part of MemberExpression:
|
|
1875
|
+
// ('[' Expression ']' | '.' Identifier | TemplateLiteral)*
|
|
1559
1876
|
do {
|
|
1560
1877
|
switch (this.peek().token) {
|
|
1561
1878
|
case Token.LBRACK: {
|
|
@@ -1589,12 +1906,23 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1589
1906
|
if (next.isType(Token.IDENTIFIER) || next.isType(Token.PRIVATE_NAME)) {
|
|
1590
1907
|
return next.getValue();
|
|
1591
1908
|
}
|
|
1909
|
+
// check keyword as identifier
|
|
1592
1910
|
if (Token.isPropertyName(next.token) && next.isNotType(Token.EOS)) {
|
|
1593
1911
|
return new Identifier(next.token.getName());
|
|
1594
1912
|
}
|
|
1595
1913
|
throw new SyntaxError(this.errorMessage(`Parsing property expression: Unexpected Token`));
|
|
1596
1914
|
}
|
|
1597
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]
|
|
1598
1926
|
let token;
|
|
1599
1927
|
while (Token.isPipelineOperator(token = this.peek().token)) {
|
|
1600
1928
|
this.consume(token);
|
|
@@ -1605,13 +1933,16 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1605
1933
|
parsePipelineBody(lhs) {
|
|
1606
1934
|
let body;
|
|
1607
1935
|
let token = this.peek();
|
|
1936
|
+
// parse function
|
|
1608
1937
|
switch (token.token) {
|
|
1609
1938
|
case Token.FUNCTION:
|
|
1610
1939
|
body = this.parseFunctionExpression();
|
|
1611
1940
|
break;
|
|
1612
1941
|
case Token.ASYNC:
|
|
1613
|
-
this.
|
|
1614
|
-
|
|
1942
|
+
if (this.peekAhead().isType(Token.FUNCTION) && !this.scanner.hasLineTerminatorAfterNext()) {
|
|
1943
|
+
this.consume(Token.ASYNC);
|
|
1944
|
+
body = this.parseAsyncFunctionLiteral();
|
|
1945
|
+
}
|
|
1615
1946
|
break;
|
|
1616
1947
|
default:
|
|
1617
1948
|
break;
|
|
@@ -1620,13 +1951,17 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1620
1951
|
return new PipelineExpression(lhs, body);
|
|
1621
1952
|
}
|
|
1622
1953
|
if (token.isType(Token.LPAREN)) {
|
|
1954
|
+
// parse arrow function
|
|
1955
|
+
// x |> ( y => y+1 )
|
|
1623
1956
|
body = this.parsePrimaryExpression();
|
|
1624
1957
|
return new PipelineExpression(lhs, body);
|
|
1625
1958
|
}
|
|
1626
|
-
|
|
1959
|
+
// parse angular-like and f# and partial operator syntax
|
|
1960
|
+
const func = this.parseMemberExpression(); //this.parseLogicalExpression();
|
|
1627
1961
|
let args = [];
|
|
1628
1962
|
switch (this.peek().token) {
|
|
1629
1963
|
case Token.COLON:
|
|
1964
|
+
// support angular pipeline syntax
|
|
1630
1965
|
do {
|
|
1631
1966
|
this.consume(Token.COLON);
|
|
1632
1967
|
const isSpread = this.check(Token.ELLIPSIS);
|
|
@@ -1651,6 +1986,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1651
1986
|
} while (this.peek().isType(Token.COLON));
|
|
1652
1987
|
break;
|
|
1653
1988
|
case Token.LPAREN:
|
|
1989
|
+
// es2022 syntax, F# & partial operator
|
|
1654
1990
|
this.consume(Token.LPAREN);
|
|
1655
1991
|
let indexed = false;
|
|
1656
1992
|
while (this.peek().isNotType(Token.RPAREN)) {
|
|
@@ -1677,7 +2013,9 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1677
2013
|
this.check(Token.COMMA);
|
|
1678
2014
|
}
|
|
1679
2015
|
this.expect(Token.RPAREN);
|
|
2016
|
+
// should be indexed, has partial operator
|
|
1680
2017
|
if (!indexed) {
|
|
2018
|
+
// z |> method(x, y) === method(x, y)(z)
|
|
1681
2019
|
body = new CallExpression(func, args);
|
|
1682
2020
|
return new PipelineExpression(lhs, body);
|
|
1683
2021
|
}
|
|
@@ -1688,14 +2026,24 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1688
2026
|
return new PipelineExpression(lhs, func, args);
|
|
1689
2027
|
}
|
|
1690
2028
|
parseConditionalExpression() {
|
|
2029
|
+
// ConditionalExpression ::
|
|
2030
|
+
// LogicalExpression
|
|
2031
|
+
// LogicalExpression '?' AssignmentExpression ':' AssignmentExpression
|
|
2032
|
+
//
|
|
1691
2033
|
let expression = this.parseLogicalExpression();
|
|
1692
2034
|
expression = this.parsePipelineExpression(expression);
|
|
1693
2035
|
return this.peek().isType(Token.CONDITIONAL) ? this.parseConditionalContinuation(expression) : expression;
|
|
1694
2036
|
}
|
|
1695
2037
|
parseLogicalExpression() {
|
|
2038
|
+
// LogicalExpression ::
|
|
2039
|
+
// LogicalORExpression
|
|
2040
|
+
// CoalesceExpression
|
|
2041
|
+
// Both LogicalORExpression and CoalesceExpression start with BitwiseOR.
|
|
2042
|
+
// Parse for binary expressions >= 6 (BitwiseOR);
|
|
1696
2043
|
let expression = this.parseBinaryExpression(6);
|
|
1697
2044
|
const peek = this.peek();
|
|
1698
2045
|
if (peek.isType(Token.AND) || peek.isType(Token.OR)) {
|
|
2046
|
+
// LogicalORExpression, pickup parsing where we left off.
|
|
1699
2047
|
const precedence = Token.precedence(peek.token, this.acceptIN);
|
|
1700
2048
|
expression = this.parseBinaryContinuation(expression, 4, precedence);
|
|
1701
2049
|
}
|
|
@@ -1706,13 +2054,18 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1706
2054
|
}
|
|
1707
2055
|
parseBinaryContinuation(x, prec, prec1) {
|
|
1708
2056
|
do {
|
|
2057
|
+
// prec1 >= 4
|
|
1709
2058
|
while (Token.precedence(this.peek().token, this.acceptIN) === prec1) {
|
|
1710
2059
|
let y;
|
|
1711
2060
|
let op = this.next();
|
|
1712
2061
|
const is_right_associative = op.isType(Token.EXP);
|
|
1713
2062
|
const next_prec = is_right_associative ? prec1 : prec1 + 1;
|
|
1714
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.)
|
|
1715
2067
|
if (Token.isCompare(op.token)) {
|
|
2068
|
+
// We have a comparison.
|
|
1716
2069
|
let cmp = op.token;
|
|
1717
2070
|
switch (op.token) {
|
|
1718
2071
|
case Token.NE:
|
|
@@ -1725,6 +2078,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1725
2078
|
}
|
|
1726
2079
|
x = shortcutNumericLiteralBinaryExpression(x, y, cmp);
|
|
1727
2080
|
if (op.isNotType(cmp)) {
|
|
2081
|
+
// The comparison was negated - add a NOT.
|
|
1728
2082
|
x = buildUnaryExpression(x, Token.NOT);
|
|
1729
2083
|
}
|
|
1730
2084
|
}
|
|
@@ -1736,7 +2090,10 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1736
2090
|
} while (prec1 >= prec);
|
|
1737
2091
|
return x;
|
|
1738
2092
|
}
|
|
2093
|
+
// Precedence >= 4
|
|
1739
2094
|
parseBinaryExpression(precedence) {
|
|
2095
|
+
// "#foo in ShiftExpression" needs to be parsed separately, since private
|
|
2096
|
+
// identifiers are not valid PrimaryExpressions.
|
|
1740
2097
|
if (this.peek().isType(Token.PRIVATE_NAME)) {
|
|
1741
2098
|
const x = this.parsePropertyOrPrivatePropertyName();
|
|
1742
2099
|
const precedence1 = Token.precedence(this.peek().token, this.acceptIN);
|
|
@@ -1753,6 +2110,18 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1753
2110
|
return x;
|
|
1754
2111
|
}
|
|
1755
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]
|
|
1756
2125
|
const op = this.peek();
|
|
1757
2126
|
if (Token.isUnaryOrCount(op.token)) {
|
|
1758
2127
|
return this.parseUnaryOrPrefixExpression();
|
|
@@ -1768,6 +2137,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1768
2137
|
if (Token.isUnary(op.token)) {
|
|
1769
2138
|
if (op.isType(Token.DELETE)) {
|
|
1770
2139
|
if (this.isIdentifier(expression) && isStrict(this.languageMode)) {
|
|
2140
|
+
// "delete identifier" is a syntax error in strict mode.
|
|
1771
2141
|
throw new Error(this.errorMessage(`"delete identifier" is a syntax error in strict mode`));
|
|
1772
2142
|
}
|
|
1773
2143
|
if (expression instanceof MemberExpression && expression.getProperty().toString().startsWith('#')) {
|
|
@@ -1779,11 +2149,14 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1779
2149
|
}
|
|
1780
2150
|
}
|
|
1781
2151
|
if (Token.isCount(op.token) || Token.isUnary(op.token)) {
|
|
2152
|
+
// Allow the parser to rewrite the expression.
|
|
1782
2153
|
return buildUnaryExpression(expression, op.token);
|
|
1783
2154
|
}
|
|
1784
2155
|
throw new Error(this.errorMessage(`while rewrite unary operation`));
|
|
1785
2156
|
}
|
|
1786
2157
|
parsePostfixExpression() {
|
|
2158
|
+
// PostfixExpression ::
|
|
2159
|
+
// LeftHandSideExpression ('++' | '--')?
|
|
1787
2160
|
const expression = this.parseLeftHandSideExpression();
|
|
1788
2161
|
if (!Token.isCount(this.peek().token) || this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1789
2162
|
return expression;
|
|
@@ -1798,6 +2171,8 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1798
2171
|
return buildPostfixExpression(expression, op.token);
|
|
1799
2172
|
}
|
|
1800
2173
|
parseLeftHandSideExpression() {
|
|
2174
|
+
// LeftHandSideExpression ::
|
|
2175
|
+
// (NewExpression | MemberExpression) ...
|
|
1801
2176
|
const result = this.parseMemberExpression();
|
|
1802
2177
|
if (!Token.isPropertyOrCall(this.peek().token))
|
|
1803
2178
|
return result;
|
|
@@ -1810,8 +2185,10 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1810
2185
|
&& !this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1811
2186
|
const args = this.parseArguments(ParsingArrowHeadFlag.AsyncArrowFunction);
|
|
1812
2187
|
if (this.peek().isType(Token.ARROW)) {
|
|
2188
|
+
// async () => ...
|
|
1813
2189
|
if (!args.length)
|
|
1814
2190
|
return new EmptyStatement;
|
|
2191
|
+
// async ( Arguments ) => ...
|
|
1815
2192
|
return this.expressionListToExpression(args);
|
|
1816
2193
|
}
|
|
1817
2194
|
result = new CallExpression(result, args);
|
|
@@ -1822,6 +2199,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1822
2199
|
let isOptional = false;
|
|
1823
2200
|
do {
|
|
1824
2201
|
switch (this.peek().token) {
|
|
2202
|
+
// chain
|
|
1825
2203
|
case Token.QUESTION_PERIOD: {
|
|
1826
2204
|
if (isOptional) {
|
|
1827
2205
|
throw new Error(this.errorMessage(`Failure Expression`));
|
|
@@ -1835,6 +2213,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1835
2213
|
result = new MemberExpression(result, key, false, isOptional);
|
|
1836
2214
|
break;
|
|
1837
2215
|
}
|
|
2216
|
+
/* Property */
|
|
1838
2217
|
case Token.LBRACK: {
|
|
1839
2218
|
this.consume(Token.LBRACK);
|
|
1840
2219
|
this.setAcceptIN(true);
|
|
@@ -1844,6 +2223,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1844
2223
|
this.expect(Token.RBRACK);
|
|
1845
2224
|
break;
|
|
1846
2225
|
}
|
|
2226
|
+
/* Property */
|
|
1847
2227
|
case Token.PERIOD: {
|
|
1848
2228
|
if (isOptional) {
|
|
1849
2229
|
throw new Error(this.errorMessage(`Unexpected Token:${this.position()}`));
|
|
@@ -1853,11 +2233,13 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1853
2233
|
result = new MemberExpression(result, key, false, isOptional);
|
|
1854
2234
|
break;
|
|
1855
2235
|
}
|
|
2236
|
+
/* Call */
|
|
1856
2237
|
case Token.LPAREN: {
|
|
1857
2238
|
const args = this.parseArguments();
|
|
1858
2239
|
result = new CallExpression(result, args, isOptional);
|
|
1859
2240
|
break;
|
|
1860
2241
|
}
|
|
2242
|
+
/* bind call */
|
|
1861
2243
|
case Token.BIND: {
|
|
1862
2244
|
if (isOptional) {
|
|
1863
2245
|
throw new Error(this.errorMessage(`Unexpected Token:${this.position()}`));
|
|
@@ -1867,6 +2249,7 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1867
2249
|
result = new BindExpression(result, key, false, isOptional);
|
|
1868
2250
|
break;
|
|
1869
2251
|
}
|
|
2252
|
+
/* chain bind call */
|
|
1870
2253
|
case Token.QUESTION_BIND: {
|
|
1871
2254
|
if (isOptional) {
|
|
1872
2255
|
throw new Error(this.errorMessage(`Failure Expression`));
|
|
@@ -1879,9 +2262,11 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1879
2262
|
break;
|
|
1880
2263
|
}
|
|
1881
2264
|
default:
|
|
2265
|
+
// Template literals in/after an Optional Chain not supported:
|
|
1882
2266
|
if (optionalChaining) {
|
|
1883
2267
|
throw new Error(this.errorMessage(`Optional Chaining No Template support`));
|
|
1884
2268
|
}
|
|
2269
|
+
/* Tagged Template */
|
|
1885
2270
|
result = this.parseTemplateLiteral(result);
|
|
1886
2271
|
break;
|
|
1887
2272
|
}
|
|
@@ -1903,10 +2288,19 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1903
2288
|
return buildUnaryExpression(value, Token.AWAIT);
|
|
1904
2289
|
}
|
|
1905
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.
|
|
1906
2299
|
const list = [];
|
|
1907
2300
|
list.push(expression);
|
|
1908
2301
|
while (this.peek().isType(Token.NULLISH)) {
|
|
1909
2302
|
this.consume(Token.NULLISH);
|
|
2303
|
+
// Parse BitwiseOR or higher.
|
|
1910
2304
|
expression = this.parseBinaryExpression(6);
|
|
1911
2305
|
list.push(expression);
|
|
1912
2306
|
}
|
|
@@ -1925,8 +2319,10 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1925
2319
|
return new ConditionalExpression(expression, left, right);
|
|
1926
2320
|
}
|
|
1927
2321
|
parseYieldExpression() {
|
|
2322
|
+
// YieldExpression ::
|
|
2323
|
+
// 'yield' ([no line terminator] '*'? AssignmentExpression)?
|
|
1928
2324
|
this.consume(Token.YIELD);
|
|
1929
|
-
let delegating = false;
|
|
2325
|
+
let delegating = false; // yield*
|
|
1930
2326
|
let expression;
|
|
1931
2327
|
if (!this.scanner.hasLineTerminatorBeforeNext()) {
|
|
1932
2328
|
if (this.check(Token.MUL)) {
|
|
@@ -1941,8 +2337,14 @@ export class JavaScriptInlineParser extends AbstractParser {
|
|
|
1941
2337
|
case Token.COLON:
|
|
1942
2338
|
case Token.COMMA:
|
|
1943
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.
|
|
1944
2344
|
if (!delegating)
|
|
1945
2345
|
break;
|
|
2346
|
+
// Delegating yields require an RHS; fall through.
|
|
2347
|
+
// V8_FALLTHROUGH;
|
|
1946
2348
|
throw new Error(this.errorMessage(`Delegating yields require an RHS`));
|
|
1947
2349
|
default:
|
|
1948
2350
|
expression = this.parseAssignmentExpressionCoverGrammar();
|