Skip to content

Commit

Permalink
JS: parse comma-operator expressions as a list, not a tree
Browse files Browse the repository at this point in the history
  • Loading branch information
tdewolff committed Jan 13, 2022
1 parent c27ce52 commit 1e0dbbe
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 6 deletions.
30 changes: 30 additions & 0 deletions js/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (v Var) JS() string {
}

// VarsByUses is sortable by uses in descending order.
// TODO: write custom sorter for varsbyuses
type VarsByUses VarArray

func (vs VarsByUses) Len() int {
Expand Down Expand Up @@ -1989,6 +1990,34 @@ func (n ArrowFunc) JS() string {
return s + n.Params.JS() + " => " + n.Body.JS()
}

// CommaExpr is a series of comma expressions.
type CommaExpr struct {
List []IExpr
}

func (n CommaExpr) String() string {
s := "("
for i, item := range n.List {
if i != 0 {
s += ","
}
s += item.String()
}
return s + ")"
}

// JS converts the node back to valid JavaScript
func (n CommaExpr) JS() string {
s := ""
for i, item := range n.List {
if i != 0 {
s += ","
}
s += item.JS()
}
return s
}

func (v *Var) exprNode() {}
func (n LiteralExpr) exprNode() {}
func (n ArrayExpr) exprNode() {}
Expand All @@ -2007,3 +2036,4 @@ func (n BinaryExpr) exprNode() {}
func (n CondExpr) exprNode() {}
func (n YieldExpr) exprNode() {}
func (n ArrowFunc) exprNode() {}
func (n CommaExpr) exprNode() {}
15 changes: 10 additions & 5 deletions js/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2050,7 +2050,12 @@ func (p *Parser) parseExpressionSuffix(left IExpr, prec, precLeft OpPrec) IExpr
return left
}
p.next()
left = &BinaryExpr{tt, left, p.parseExpression(OpAssign)}
if commaExpr, ok := left.(*CommaExpr); ok {
commaExpr.List = append(commaExpr.List, p.parseExpression(OpAssign))
i-- // adjust expression nesting limit
} else {
left = &CommaExpr{[]IExpr{left, p.parseExpression(OpAssign)}}
}
precLeft = OpExpr
case ArrowToken:
// handle identifier => ..., where identifier could also be yield or await
Expand Down Expand Up @@ -2197,11 +2202,11 @@ func (p *Parser) parseParenthesizedExpressionOrArrowFunc(prec OpPrec, async []by
precLeft = OpCall
} else {
// parenthesized expression
left = list[0]
for _, item := range list[1:] {
left = &BinaryExpr{CommaToken, left, item}
if 1 < len(list) {
left = &GroupExpr{&CommaExpr{list}}
} else {
left = &GroupExpr{list[0]}
}
left = &GroupExpr{left}
}
}
return p.parseExpressionSuffix(left, prec, precLeft)
Expand Down
6 changes: 5 additions & 1 deletion js/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func TestParse(t *testing.T) {
{"a&b&c", "Stmt((a&b)&c)"},
{"a|b|c", "Stmt((a|b)|c)"},
{"a^b^c", "Stmt((a^b)^c)"},
{"a,b,c", "Stmt((a,b),c)"},
{"a,b,c", "Stmt(a,b,c)"},

// regular expressions
{"/abc/", "Stmt(/abc/)"},
Expand Down Expand Up @@ -796,6 +796,10 @@ func (sv *ScopeVars) AddExpr(iexpr IExpr) {
sv.AddExpr(expr.Y)
case *GroupExpr:
sv.AddExpr(expr.X)
case *CommaExpr:
for _, item := range expr.List {
sv.AddExpr(item)
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions js/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ func Walk(v IVisitor, n INode) {
case *ArrowFunc:
Walk(v, &n.Body)
Walk(v, &n.Params)
case *CommaExpr:
for _, item := range n.List {
Walk(v, item)
}
default:
return
}
Expand Down

0 comments on commit 1e0dbbe

Please sign in to comment.