|
61 | 61 | import com.semmle.js.ast.ImportDeclaration;
|
62 | 62 | import com.semmle.js.ast.ImportDefaultSpecifier;
|
63 | 63 | import com.semmle.js.ast.ImportNamespaceSpecifier;
|
| 64 | +import com.semmle.js.ast.ImportPhaseModifier; |
64 | 65 | import com.semmle.js.ast.ImportSpecifier;
|
65 | 66 | import com.semmle.js.ast.LabeledStatement;
|
66 | 67 | import com.semmle.js.ast.Literal;
|
@@ -3587,34 +3588,40 @@ protected Expression parseImportOrExportAttributesAndSemicolon() {
|
3587 | 3588 | }
|
3588 | 3589 |
|
3589 | 3590 | protected ImportDeclaration parseImportRest(SourceLocation loc) {
|
| 3591 | + ImportPhaseModifier[] phaseModifier = { ImportPhaseModifier.NONE }; |
3590 | 3592 | List<ImportSpecifier> specifiers;
|
3591 | 3593 | Literal source;
|
3592 | 3594 | // import '...'
|
3593 | 3595 | if (this.type == TokenType.string) {
|
3594 | 3596 | specifiers = new ArrayList<ImportSpecifier>();
|
3595 | 3597 | source = (Literal) this.parseExprAtom(null);
|
3596 | 3598 | } else {
|
3597 |
| - specifiers = this.parseImportSpecifiers(); |
| 3599 | + specifiers = this.parseImportSpecifiers(phaseModifier); |
3598 | 3600 | this.expectContextual("from");
|
3599 | 3601 | if (this.type != TokenType.string) this.unexpected();
|
3600 | 3602 | source = (Literal) this.parseExprAtom(null);
|
3601 | 3603 | }
|
3602 | 3604 | Expression attributes = this.parseImportOrExportAttributesAndSemicolon();
|
3603 | 3605 | if (specifiers == null) return null;
|
3604 |
| - return this.finishNode(new ImportDeclaration(loc, specifiers, source, attributes)); |
| 3606 | + return this.finishNode(new ImportDeclaration(loc, specifiers, source, attributes, phaseModifier[0])); |
3605 | 3607 | }
|
3606 | 3608 |
|
3607 | 3609 | // Parses a comma-separated list of module imports.
|
3608 |
| - protected List<ImportSpecifier> parseImportSpecifiers() { |
| 3610 | + protected List<ImportSpecifier> parseImportSpecifiers(ImportPhaseModifier[] phaseModifier) { |
3609 | 3611 | List<ImportSpecifier> nodes = new ArrayList<ImportSpecifier>();
|
3610 | 3612 | boolean first = true;
|
3611 | 3613 | if (this.type == TokenType.name) {
|
3612 | 3614 | // import defaultObj, { x, y as z } from '...'
|
3613 | 3615 | SourceLocation loc = new SourceLocation(this.startLoc);
|
3614 | 3616 | Identifier local = this.parseIdent(false);
|
3615 |
| - this.checkLVal(local, true, null); |
3616 |
| - nodes.add(this.finishNode(new ImportDefaultSpecifier(loc, local))); |
3617 |
| - if (!this.eat(TokenType.comma)) return nodes; |
| 3617 | + // Parse `import defer *` as the beginning of a deferred import, instead of a default import specifier |
| 3618 | + if (this.type == TokenType.star && local.getName().equals("defer")) { |
| 3619 | + phaseModifier[0] = ImportPhaseModifier.DEFER; |
| 3620 | + } else { |
| 3621 | + this.checkLVal(local, true, null); |
| 3622 | + nodes.add(this.finishNode(new ImportDefaultSpecifier(loc, local))); |
| 3623 | + if (!this.eat(TokenType.comma)) return nodes; |
| 3624 | + } |
3618 | 3625 | }
|
3619 | 3626 | if (this.type == TokenType.star) {
|
3620 | 3627 | SourceLocation loc = new SourceLocation(this.startLoc);
|
@@ -3647,7 +3654,7 @@ protected ImportSpecifier parseImportSpecifier() {
|
3647 | 3654 | if (this.type == TokenType.string) {
|
3648 | 3655 | // Arbitrary Module Namespace Identifiers
|
3649 | 3656 | // e.g. `import { "Foo::new" as Foo_new } from "./foo.wasm"`
|
3650 |
| - Expression string = this.parseExprAtom(null); |
| 3657 | + Expression string = this.parseExprAtom(null); |
3651 | 3658 | String str = ((Literal)string).getStringValue();
|
3652 | 3659 | imported = this.finishNode(new Identifier(loc, str));
|
3653 | 3660 | // only makes sense if there is a local identifier
|
|
0 commit comments