JS: Add parsing support in JS parser

This commit is contained in:
Asger F
2025-09-05 11:38:16 +02:00
parent 215602c963
commit bab2a79055
4 changed files with 21 additions and 9 deletions

View File

@@ -61,6 +61,7 @@ import com.semmle.js.ast.IfStatement;
import com.semmle.js.ast.ImportDeclaration;
import com.semmle.js.ast.ImportDefaultSpecifier;
import com.semmle.js.ast.ImportNamespaceSpecifier;
import com.semmle.js.ast.ImportPhaseModifier;
import com.semmle.js.ast.ImportSpecifier;
import com.semmle.js.ast.LabeledStatement;
import com.semmle.js.ast.Literal;
@@ -3587,6 +3588,7 @@ public class Parser {
}
protected ImportDeclaration parseImportRest(SourceLocation loc) {
ImportPhaseModifier[] phaseModifier = { ImportPhaseModifier.NONE };
List<ImportSpecifier> specifiers;
Literal source;
// import '...'
@@ -3594,27 +3596,32 @@ public class Parser {
specifiers = new ArrayList<ImportSpecifier>();
source = (Literal) this.parseExprAtom(null);
} else {
specifiers = this.parseImportSpecifiers();
specifiers = this.parseImportSpecifiers(phaseModifier);
this.expectContextual("from");
if (this.type != TokenType.string) this.unexpected();
source = (Literal) this.parseExprAtom(null);
}
Expression attributes = this.parseImportOrExportAttributesAndSemicolon();
if (specifiers == null) return null;
return this.finishNode(new ImportDeclaration(loc, specifiers, source, attributes));
return this.finishNode(new ImportDeclaration(loc, specifiers, source, attributes, phaseModifier[0]));
}
// Parses a comma-separated list of module imports.
protected List<ImportSpecifier> parseImportSpecifiers() {
protected List<ImportSpecifier> parseImportSpecifiers(ImportPhaseModifier[] phaseModifier) {
List<ImportSpecifier> nodes = new ArrayList<ImportSpecifier>();
boolean first = true;
if (this.type == TokenType.name) {
// import defaultObj, { x, y as z } from '...'
SourceLocation loc = new SourceLocation(this.startLoc);
Identifier local = this.parseIdent(false);
this.checkLVal(local, true, null);
nodes.add(this.finishNode(new ImportDefaultSpecifier(loc, local)));
if (!this.eat(TokenType.comma)) return nodes;
// Parse `import defer *` as the beginning of a deferred import, instead of a default import specifier
if (this.type == TokenType.star && local.getName().equals("defer")) {
phaseModifier[0] = ImportPhaseModifier.DEFER;
} else {
this.checkLVal(local, true, null);
nodes.add(this.finishNode(new ImportDefaultSpecifier(loc, local)));
if (!this.eat(TokenType.comma)) return nodes;
}
}
if (this.type == TokenType.star) {
SourceLocation loc = new SourceLocation(this.startLoc);
@@ -3647,7 +3654,7 @@ public class Parser {
if (this.type == TokenType.string) {
// Arbitrary Module Namespace Identifiers
// e.g. `import { "Foo::new" as Foo_new } from "./foo.wasm"`
Expression string = this.parseExprAtom(null);
Expression string = this.parseExprAtom(null);
String str = ((Literal)string).getStringValue();
imported = this.finishNode(new Identifier(loc, str));
// only makes sense if there is a local identifier

View File

@@ -14,6 +14,7 @@ import com.semmle.js.ast.Expression;
import com.semmle.js.ast.ExpressionStatement;
import com.semmle.js.ast.FieldDefinition;
import com.semmle.js.ast.Identifier;
import com.semmle.js.ast.ImportPhaseModifier;
import com.semmle.js.ast.ImportSpecifier;
import com.semmle.js.ast.Literal;
import com.semmle.js.ast.MethodDefinition;
@@ -1064,13 +1065,13 @@ public class FlowParser extends ESNextParser {
}
@Override
protected List<ImportSpecifier> parseImportSpecifiers() {
protected List<ImportSpecifier> parseImportSpecifiers(ImportPhaseModifier[] phaseModifier) {
String kind = null;
if (flow()) {
kind = flowParseImportSpecifiers();
}
List<ImportSpecifier> specs = super.parseImportSpecifiers();
List<ImportSpecifier> specs = super.parseImportSpecifiers(phaseModifier);
if (kind != null || specs.isEmpty()) return null;
return specs;
}

View File

@@ -0,0 +1,3 @@
import defer * as deferred from "somewhere";
import * as normal from "somewhere";
import defer from "somewhere";

View File

@@ -1 +1,2 @@
| test-js.js:1:1:1:44 | import ... where"; |
| tst.ts:1:1:1:44 | import ... where"; |