Skip to content

Commit 282d924

Browse files
authored
fix: Check ASI upon unusual trailing expressions (#2252)
1 parent 82812de commit 282d924

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

Diff for: src/parser.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ export class Parser extends DiagnosticEmitter {
939939
} while (tn.skip(Token.Comma));
940940

941941
let ret = Node.createVariableStatement(decorators, declarations, tn.range(startPos, tn.pos));
942-
tn.skip(Token.Semicolon);
942+
if (!tn.skip(Token.Semicolon) && !isFor) this.checkASI(tn);
943943
return ret;
944944
}
945945

@@ -1122,7 +1122,7 @@ export class Parser extends DiagnosticEmitter {
11221122
}
11231123

11241124
let ret = Node.createReturnStatement(expr, tn.range(startPos, tn.pos));
1125-
tn.skip(Token.Semicolon);
1125+
if (!tn.skip(Token.Semicolon)) this.checkASI(tn);
11261126
return ret;
11271127
}
11281128

@@ -3009,7 +3009,7 @@ export class Parser extends DiagnosticEmitter {
30093009
}
30103010
}
30113011
let ret = Node.createBlockStatement(statements, tn.range(startPos, tn.pos));
3012-
tn.skip(Token.Semicolon);
3012+
if (topLevel) tn.skip(Token.Semicolon);
30133013
return ret;
30143014
}
30153015

@@ -3417,7 +3417,7 @@ export class Parser extends DiagnosticEmitter {
34173417
let expression = this.parseExpression(tn);
34183418
if (!expression) return null;
34193419
let ret = Node.createThrowStatement(expression, tn.range(startPos, tn.pos));
3420-
tn.skip(Token.Semicolon);
3420+
if (!tn.skip(Token.Semicolon)) this.checkASI(tn);
34213421
return ret;
34223422
}
34233423

@@ -4401,6 +4401,18 @@ export class Parser extends DiagnosticEmitter {
44014401
return expr;
44024402
}
44034403

4404+
private checkASI(
4405+
tn: Tokenizer
4406+
): void {
4407+
// see: https://tc39.es/ecma262/#sec-automatic-semicolon-insertion
4408+
let token = tn.peek(true);
4409+
if (tn.nextTokenOnNewLine || token == Token.EndOfFile || token == Token.CloseBrace) return;
4410+
this.error(
4411+
DiagnosticCode.Unexpected_token,
4412+
tn.range(tn.nextTokenPos)
4413+
);
4414+
}
4415+
44044416
/** Skips over a statement on errors in an attempt to reduce unnecessary diagnostic noise. */
44054417
skipStatement(tn: Tokenizer): void {
44064418
tn.peek(true);

Diff for: tests/parser/asi.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function failLet(y: i32): i32 {
2+
let x = y 234;
3+
return x + y;
4+
}
5+
6+
function failReturn(): i32 {
7+
return 123 456;
8+
}
9+
10+
function failThrow(): i32 {
11+
throw 123 456;
12+
}
13+
14+
function successCloseBrace(): i32 {
15+
return 123 }
16+
17+
function successCloseParen(): i32 {
18+
return ( 123 )
19+
}

Diff for: tests/parser/asi.ts.fixture.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
function failLet(y: i32): i32 {
2+
let x = y;
3+
234;
4+
return x + y;
5+
}
6+
function failReturn(): i32 {
7+
return 123;
8+
456;
9+
}
10+
function failThrow(): i32 {
11+
throw 123;
12+
456;
13+
}
14+
function successCloseBrace(): i32 {
15+
return 123;
16+
}
17+
function successCloseParen(): i32 {
18+
return (123);
19+
}
20+
// ERROR 1012: "Unexpected token." in asi.ts(2,13+0)
21+
// ERROR 1012: "Unexpected token." in asi.ts(7,14+0)
22+
// ERROR 1012: "Unexpected token." in asi.ts(11,13+0)

0 commit comments

Comments
 (0)