Skip to content

Commit

Permalink
JS: fix parsing of for/for-of/for-in regarding LHSExpr vs Expr
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Jan 11, 2024
1 parent 202ca96 commit 64705f8
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 11 deletions.
23 changes: 13 additions & 10 deletions js/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,15 @@ func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
}
}
init = varDecl
} else if p.tt != SemicolonToken {
} else if await {
init = p.parseExpression(OpLHS)
} else if p.tt != SemicolonToken {
init = p.parseExpression(OpExpr)
}
p.in = true

if p.tt == InToken {
isLHSExpr := isLHSExpr(init)
if isLHSExpr && p.tt == InToken {
if await {
p.fail("for statement", OfToken)
return
Expand All @@ -385,7 +388,7 @@ func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
varDecl.InForInOf = true
}
stmt = &ForInStmt{init, value, body}
} else if p.tt == OfToken {
} else if isLHSExpr && p.tt == OfToken {
p.next()
value := p.parseExpression(OpAssign)
if !p.consume("for statement", CloseParenToken) {
Expand All @@ -403,13 +406,7 @@ func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
varDecl.InForInOf = true
}
stmt = &ForOfStmt{await, init, value, body}
} else {
init = p.parseExpressionSuffix(init, OpExpr, OpLHS)
if p.tt != SemicolonToken {
p.fail("for statement", InToken, OfToken, SemicolonToken)
return
}

} else if p.tt == SemicolonToken {
var cond, post IExpr
if await {
p.fail("for statement", OfToken)
Expand Down Expand Up @@ -444,6 +441,12 @@ func (p *Parser) parseStmt(allowDeclaration bool) (stmt IStmt) {
varDecl.InFor = true
}
stmt = &ForStmt{init, cond, post, body}
} else if isLHSExpr {
p.fail("for statement", InToken, OfToken, SemicolonToken)
return
} else {
p.fail("for statement", SemicolonToken)
return
}
p.exitScope(parent)
case SwitchToken:
Expand Down
5 changes: 4 additions & 1 deletion js/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ func TestParse(t *testing.T) {
{"for (c && (a in b);;) {}", "Stmt(for (c&&((a in b))) ; ; Stmt({ }))"},
{"for (a in b) {}", "Stmt(for a in b Stmt({ }))"},
{"for (a = b;;) {}", "Stmt(for (a=b) ; ; Stmt({ }))"},
{"for (!a;;) {}", "Stmt(for (!a) ; ; Stmt({ }))"},
{"for (var [a] in b) {}", "Stmt(for Decl(var Binding([ Binding(a) ])) in b Stmt({ }))"},
{"for(async of b);", "Stmt(for async of b Stmt({ }))"},
{"for await (async of b);", "Stmt(for await async of b Stmt({ }))"},
{"for (async of => 5;;);", "Stmt(for (async Params(Binding(of)) => Stmt({ Stmt(return 5) })) ; ; Stmt({ }))"},
{"throw 5", "Stmt(throw 5)"},
{"try {} catch {b}", "Stmt(try Stmt({ }) catch Stmt({ Stmt(b) }))"},
{"try {} finally {c}", "Stmt(try Stmt({ }) finally Stmt({ Stmt(c) }))"},
Expand Down Expand Up @@ -460,6 +462,7 @@ func TestParseError(t *testing.T) {
{"for(var [a],b;", "unexpected ; in for statement"},
{"for(var [a]=5,{b};", "expected = instead of ; in var statement"},
{`for(let{[(`, `unexpected EOF in expression`},
{"for(async of b);", "expected => instead of b in arrow function"},
{"for await", "expected ( instead of EOF in for statement"},
{"function a(){for await", "expected ( instead of await in for statement"},
{"async function a(){ for await(a;", "expected of instead of ; in for statement"},
Expand Down
8 changes: 8 additions & 0 deletions js/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import (
"io"
)

func isLHSExpr(i IExpr) bool {
switch i.(type) {
case *CommaExpr, *CondExpr, *YieldExpr, *ArrowFunc, *BinaryExpr, *UnaryExpr:
return false
}
return true
}

// AsIdentifierName returns true if a valid identifier name is given.
func AsIdentifierName(b []byte) bool {
if len(b) == 0 || !identifierStartTable[b[0]] {
Expand Down

0 comments on commit 64705f8

Please sign in to comment.