cue/ast: add NewBinExpr helper
Change-Id: I2f067d5a1b087d43a0c2f95f6054fcfed977fb7b
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4603
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/get_go.go b/cmd/cue/cmd/get_go.go
index 877a2ab..be8ea78 100644
--- a/cmd/cue/cmd/get_go.go
+++ b/cmd/cue/cmd/get_go.go
@@ -627,7 +627,7 @@
for _, v := range enums[1:] {
y := e.ident(v)
cueast.SetRelPos(y, cuetoken.Newline)
- x = &cueast.BinaryExpr{X: x, Op: cuetoken.OR, Y: y}
+ x = cueast.NewBinExpr(cuetoken.OR, x, y)
}
a = append(a, e.def(nil, enumName, x, true))
}
@@ -678,11 +678,7 @@
switch s {
case "byte", "string", "error":
default:
- cv = &cueast.BinaryExpr{
- X: e.makeType(typ),
- Op: cuetoken.AND,
- Y: cv,
- }
+ cv = cueast.NewBinExpr(cuetoken.AND, e.makeType(typ), cv)
}
}
diff --git a/cue/ast/ast.go b/cue/ast/ast.go
index 9a4441e..b95714c 100644
--- a/cue/ast/ast.go
+++ b/cue/ast/ast.go
@@ -609,6 +609,21 @@
expr
}
+// NewBinExpr creates for list of expressions of length 2 or greater a chained
+// binary expression of the form (((x1 op x2) op x3) ...). For lists of lenght
+// 1 it returns the expression itself. It panics for empty lists.
+// Useful for ASTs generated by code other than the CUE parser.
+func NewBinExpr(op token.Token, operands ...Expr) Expr {
+ if len(operands) == 0 {
+ panic("must specify at least one expression")
+ }
+ expr := operands[0]
+ for _, e := range operands[1:] {
+ expr = &BinaryExpr{X: expr, Op: op, Y: e}
+ }
+ return expr
+}
+
// token.Pos and End implementations for expression/type nodes.
func (x *BadExpr) Pos() token.Pos { return x.From }
diff --git a/cue/export.go b/cue/export.go
index 2f43291..4677550 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -456,10 +456,7 @@
s := &ast.StructLit{}
return p.closeOrOpen(s, p.embedding(s, x))
}
- return &ast.BinaryExpr{
- X: p.expr(x.left),
- Op: opMap[x.op], Y: p.expr(x.right),
- }
+ return ast.NewBinExpr(opMap[x.op], p.expr(x.left), p.expr(x.right))
case *bound:
return &ast.UnaryExpr{Op: opMap[x.op], X: p.expr(x.value)}
@@ -491,7 +488,7 @@
}
bin := expr(x.values[0])
for _, v := range x.values[1:] {
- bin = &ast.BinaryExpr{X: bin, Op: token.OR, Y: expr(v)}
+ bin = ast.NewBinExpr(token.OR, bin, expr(v))
}
return bin
@@ -631,15 +628,14 @@
if !ok || ln > len(x.elem.arcs) {
list.Elts = append(list.Elts, &ast.Ellipsis{Type: p.expr(x.typ)})
if !open && !isTop(x.typ) {
- expr = &ast.BinaryExpr{
- X: &ast.BinaryExpr{
- X: p.expr(x.len),
- Op: token.MUL,
- Y: ast.NewList(p.expr(x.typ)),
- },
- Op: token.AND,
- Y: list,
- }
+ expr = ast.NewBinExpr(
+ token.AND,
+ ast.NewBinExpr(
+ token.MUL,
+ p.expr(x.len),
+ ast.NewList(p.expr(x.typ))),
+ list,
+ )
}
}
@@ -1159,9 +1155,5 @@
if b == nil {
return a
}
- return &ast.BinaryExpr{
- X: a,
- Op: opMap[op],
- Y: b,
- }
+ return ast.NewBinExpr(opMap[op], a, b)
}