|
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