Skip to content

Commit b4830ba

Browse files
committed
Switch statement expression should be parsed outside the switch block scope.
1 parent 6a7a408 commit b4830ba

File tree

1 file changed

+28
-23
lines changed
  • graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser

1 file changed

+28
-23
lines changed

graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -3612,12 +3612,36 @@ private void switchStatement(boolean yield, boolean await) {
36123612
ParserContextBlockNode switchBlock;
36133613
SwitchNode switchStatement;
36143614
try {
3615+
assert type == TokenType.SWITCH; // tested in caller.
3616+
next();
3617+
3618+
/*
3619+
* Note: Identifier references in the switch expression need to be resolved in the scope
3620+
* of the outer block, so we must parse the expression before pushing the switch scope.
3621+
*/
3622+
expect(LPAREN);
3623+
int expressionLine = line;
3624+
Expression expression = expression(yield, await);
3625+
expect(RPAREN);
3626+
3627+
// Desugar expression to a synthetic let variable assignment in the outer block.
3628+
// This simplifies lexical scope analysis (the expression is outside the switch
3629+
// block).
3630+
// e.g.: let x = 1; switch (x) { case 0: let x = 2; } =>
3631+
// let x = 1; { let :switch = x; { let x; switch (:switch) { case 0: x = 2; } } }
3632+
if (useBlockScope()) {
3633+
IdentNode switchExprName = new IdentNode(Token.recast(expression.getToken(), IDENT), expression.getFinish(), lexer.stringIntern(SWITCH_BINDING_NAME));
3634+
VarNode varNode = new VarNode(expressionLine, Token.recast(expression.getToken(), LET), expression.getFinish(), switchExprName, expression, VarNode.IS_LET);
3635+
outerBlock.appendStatement(varNode);
3636+
declareVar(outerBlock.getScope(), varNode);
3637+
expression = switchExprName;
3638+
}
3639+
36153640
// Block to capture variables declared inside the switch statement.
36163641
switchBlock = newBlock(Scope.createSwitchBlock(lc.getCurrentScope()));
36173642
switchBlock.setFlag(Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK);
36183643

3619-
// SWITCH tested in caller.
3620-
next();
3644+
expect(LBRACE);
36213645

36223646
// Create and add switch statement.
36233647
final ParserContextSwitchNode switchNode = new ParserContextSwitchNode();
@@ -3628,26 +3652,6 @@ private void switchStatement(boolean yield, boolean await) {
36283652
final ArrayList<CaseNode> cases = new ArrayList<>();
36293653

36303654
try {
3631-
expect(LPAREN);
3632-
int expressionLine = line;
3633-
Expression expression = expression(yield, await);
3634-
expect(RPAREN);
3635-
3636-
expect(LBRACE);
3637-
3638-
// Desugar expression to a synthetic let variable assignment in the outer block.
3639-
// This simplifies lexical scope analysis (the expression is outside the switch
3640-
// block).
3641-
// e.g.: let x = 1; switch (x) { case 0: let x = 2; } =>
3642-
// let x = 1; { let :switch = x; { let x; switch (:switch) { case 0: x = 2; } } }
3643-
if (useBlockScope()) {
3644-
IdentNode switchExprName = new IdentNode(Token.recast(expression.getToken(), IDENT), expression.getFinish(), lexer.stringIntern(SWITCH_BINDING_NAME));
3645-
VarNode varNode = new VarNode(expressionLine, Token.recast(expression.getToken(), LET), expression.getFinish(), switchExprName, expression, VarNode.IS_LET);
3646-
outerBlock.appendStatement(varNode);
3647-
declareVar(outerBlock.getScope(), varNode);
3648-
expression = switchExprName;
3649-
}
3650-
36513655
while (type != RBRACE) {
36523656
// Prepare for next case.
36533657
Expression caseExpression = null;
@@ -3686,6 +3690,7 @@ private void switchStatement(boolean yield, boolean await) {
36863690
cases.add(caseNode);
36873691
}
36883692

3693+
assert type == RBRACE;
36893694
next();
36903695

36913696
switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCaseIndex);

0 commit comments

Comments
 (0)