Skip to content

Commit c715de2

Browse files
committed
JS: parse import assertions without storing in AST
1 parent 5fdc293 commit c715de2

File tree

4 files changed

+1081
-4
lines changed

4 files changed

+1081
-4
lines changed

javascript/extractor/src/com/semmle/jcorn/ESNextParser.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ protected ExportDeclaration parseExportRest(SourceLocation exportStart, Set<Stri
314314
this.parseExportSpecifiersMaybe(specifiers, exports);
315315
}
316316
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
317+
Expression assertion = this.parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST
317318
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
318319
}
319320

@@ -330,6 +331,7 @@ protected ExportDeclaration parseExportAll(
330331
List<ExportSpecifier> specifiers = CollectionUtil.makeList(nsSpec);
331332
this.parseExportSpecifiersMaybe(specifiers, exports);
332333
Literal source = (Literal) this.parseExportFrom(specifiers, null, true);
334+
Expression assertion = this.parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST
333335
return this.finishNode(new ExportNamedDeclaration(exportStart, null, specifiers, source));
334336
}
335337

@@ -435,6 +437,10 @@ private MetaProperty parseImportMeta(Position loc) {
435437
*/
436438
private DynamicImport parseDynamicImport(Position startLoc) {
437439
Expression source = parseMaybeAssign(false, null, null);
440+
Expression assertion = null;
441+
if (this.eat(TokenType.comma)) {
442+
assertion = this.parseMaybeAssign(false, null, null); // TODO: store in AST
443+
}
438444
this.expect(TokenType.parenR);
439445
DynamicImport di = this.finishNode(new DynamicImport(new SourceLocation(startLoc), source));
440446
return di;

javascript/extractor/src/com/semmle/jcorn/Parser.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,7 +2783,7 @@ protected Statement parseBreakContinueStatement(Position startLoc, String keywor
27832783
boolean isBreak = keyword.equals("break");
27842784
this.next();
27852785
Identifier label = null;
2786-
if (this.eat(TokenType.semi) || this.insertSemicolon()) {
2786+
if (this.eagerlyTrySemicolon()) {
27872787
label = null;
27882788
} else if (this.type != TokenType.name) {
27892789
this.unexpected();
@@ -2893,6 +2893,15 @@ protected Statement parseIfStatement(Position startLoc) {
28932893
new IfStatement(new SourceLocation(startLoc), test, consequent, alternate));
28942894
}
28952895

2896+
/**
2897+
* Consumes or inserts a semicolon if possible, and returns true if a semicolon was consumed or inserted.
2898+
*
2899+
* Returns false if there was no semicolon and insertion was not possible.
2900+
*/
2901+
protected boolean eagerlyTrySemicolon() {
2902+
return this.eat(TokenType.semi) || this.insertSemicolon();
2903+
}
2904+
28962905
protected ReturnStatement parseReturnStatement(Position startLoc) {
28972906
if (!this.inFunction && !this.options.allowReturnOutsideFunction())
28982907
this.raise(this.start, "'return' outside of function");
@@ -2902,7 +2911,7 @@ protected ReturnStatement parseReturnStatement(Position startLoc) {
29022911
// optional arguments, we eagerly look for a semicolon or the
29032912
// possibility to insert one.
29042913
Expression argument;
2905-
if (this.eat(TokenType.semi) || this.insertSemicolon()) {
2914+
if (this.eagerlyTrySemicolon()) {
29062915
argument = null;
29072916
} else {
29082917
argument = this.parseExpression(false, null);
@@ -3404,6 +3413,7 @@ protected ExportDeclaration parseExportRest(SourceLocation loc, Set<String> expo
34043413
Statement declaration;
34053414
List<ExportSpecifier> specifiers;
34063415
Expression source = null;
3416+
Expression assertion = null;
34073417
if (this.shouldParseExportStatement()) {
34083418
declaration = this.parseStatement(true, false);
34093419
if (declaration == null) return null;
@@ -3419,11 +3429,13 @@ protected ExportDeclaration parseExportRest(SourceLocation loc, Set<String> expo
34193429
declaration = null;
34203430
specifiers = this.parseExportSpecifiers(exports);
34213431
source = parseExportFrom(specifiers, source, false);
3432+
assertion = parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST
34223433
}
34233434
return this.finishNode(
34243435
new ExportNamedDeclaration(loc, declaration, specifiers, (Literal) source));
34253436
}
34263437

3438+
/** Parses the 'from' clause of an export, not including the assertion or semicolon. */
34273439
protected Expression parseExportFrom(
34283440
List<ExportSpecifier> specifiers, Expression source, boolean expectFrom) {
34293441
if (this.eatContextual("from")) {
@@ -3442,13 +3454,13 @@ protected Expression parseExportFrom(
34423454

34433455
source = null;
34443456
}
3445-
this.semicolon();
34463457
return source;
34473458
}
34483459

34493460
protected ExportDeclaration parseExportAll(
34503461
SourceLocation loc, Position starLoc, Set<String> exports) {
34513462
Expression source = parseExportFrom(null, null, true);
3463+
Expression assertion = parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST
34523464
return this.finishNode(new ExportAllDeclaration(loc, (Literal) source));
34533465
}
34543466

@@ -3514,6 +3526,16 @@ protected Statement parseImport(Position startLoc) {
35143526
return parseImportRest(loc);
35153527
}
35163528

3529+
protected Expression parseImportOrExportAssertionAndSemicolon() {
3530+
Expression result = null;
3531+
if (!this.eagerlyTrySemicolon()) {
3532+
this.expectContextual("assert");
3533+
result = this.parseObj(false, null);
3534+
this.semicolon();
3535+
}
3536+
return result;
3537+
}
3538+
35173539
protected ImportDeclaration parseImportRest(SourceLocation loc) {
35183540
List<ImportSpecifier> specifiers;
35193541
Literal source;
@@ -3527,7 +3549,7 @@ protected ImportDeclaration parseImportRest(SourceLocation loc) {
35273549
if (this.type != TokenType.string) this.unexpected();
35283550
source = (Literal) this.parseExprAtom(null);
35293551
}
3530-
this.semicolon();
3552+
Expression assertion = this.parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST
35313553
if (specifiers == null) return null;
35323554
return this.finishNode(new ImportDeclaration(loc, specifiers, source));
35333555
}

javascript/extractor/src/com/semmle/jcorn/flow/FlowParser.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,10 +943,12 @@ protected ExportDeclaration parseExportRest(SourceLocation loc, Set<String> expo
943943
// `export type { foo, bar };`
944944
List<ExportSpecifier> specifiers = this.parseExportSpecifiers(exports);
945945
this.parseExportFrom(specifiers, null, false);
946+
this.parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST?
946947
return null;
947948
} else if (this.eat(TokenType.star)) {
948949
if (this.eatContextual("as")) this.parseIdent(true);
949950
this.parseExportFrom(null, null, true);
951+
this.parseImportOrExportAssertionAndSemicolon(); // TODO: store in AST?
950952
return null;
951953
} else {
952954
// `export type Foo = Bar;`

0 commit comments

Comments
 (0)