internal/core/adt: do list artihmetic with comprehensions
Change-Id: I60cf6a2ced7def18a1e0196d7a70a8e52ace9b12
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7761
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
diff --git a/internal/core/adt/binop.go b/internal/core/adt/binop.go
index b43bea6..73670c2 100644
--- a/internal/core/adt/binop.go
+++ b/internal/core/adt/binop.go
@@ -183,20 +183,36 @@
return c.newBytes(b)
case leftKind == ListKind && rightKind == ListKind:
- a := c.Elems(left)
- b := c.Elems(right)
+ // TODO: get rid of list addition. Semantically it is somewhat
+ // unclear and, as it turns out, it is also hard to get right.
+ // Simulate addition with comprehensions now.
if err := c.Err(); err != nil {
return err
}
- n := c.newList(c.src, nil)
- if err := n.appendListArcs(a); err != nil {
- return err
+
+ x := MakeIdentLabel(c, "x", "")
+
+ forClause := func(src Expr) *ForClause {
+ return &ForClause{
+ Value: x,
+ Src: src,
+ Dst: &ValueClause{&StructLit{Decls: []Decl{
+ &FieldReference{UpCount: 1, Label: x},
+ }}},
+ }
}
- if err := n.appendListArcs(b); err != nil {
- return err
+
+ list := &ListLit{
+ Elems: []Elem{
+ forClause(left),
+ forClause(right),
+ },
}
- // n.isList = true
- // n.IsClosed = true
+
+ n := &Vertex{}
+ n.AddConjunct(MakeRootConjunct(c.Env(0), list))
+ n.Finalize(c)
+
return n
}
@@ -230,21 +246,30 @@
fallthrough
case leftKind == IntKind && rightKind == ListKind:
- a := c.Elems(right)
- n := c.newList(c.src, nil)
- // n.IsClosed = true
- index := int64(0)
+ // TODO: get rid of list multiplication.
+
+ list := &ListLit{}
+ x := MakeIdentLabel(c, "x", "")
+
for i := c.uint64(left, "list multiplier"); i > 0; i-- {
- for _, a := range a {
- f, _ := MakeLabel(a.Source(), index, IntLabel)
- n.Arcs = append(n.Arcs, &Vertex{
- Parent: n,
- Label: f,
- Conjuncts: a.Conjuncts,
- })
- index++
- }
+ list.Elems = append(list.Elems,
+ &ForClause{
+ Value: x,
+ Src: right,
+ Dst: &ValueClause{&StructLit{Decls: []Decl{
+ &FieldReference{UpCount: 1, Label: x},
+ }}},
+ },
+ )
}
+ if err := c.Err(); err != nil {
+ return err
+ }
+
+ n := &Vertex{}
+ n.AddConjunct(MakeRootConjunct(c.Env(0), list))
+ n.Finalize(c)
+
return n
}
diff --git a/internal/core/adt/composite.go b/internal/core/adt/composite.go
index 6d160d9..00f0737 100644
--- a/internal/core/adt/composite.go
+++ b/internal/core/adt/composite.go
@@ -572,23 +572,6 @@
return a
}
-func (v *Vertex) appendListArcs(arcs []*Vertex) (err *Bottom) {
- for _, a := range arcs {
- // TODO(list): BUG this only works if lists do not have definitions
- // fields.
- label, err := MakeLabel(a.Source(), int64(len(v.Arcs)), IntLabel)
- if err != nil {
- return &Bottom{Src: a.Source(), Err: err}
- }
- v.Arcs = append(v.Arcs, &Vertex{
- Parent: v,
- Label: label,
- Conjuncts: a.Conjuncts,
- })
- }
- return nil
-}
-
// An Conjunct is an Environment-Expr pair. The Environment is the starting
// point for reference lookup for any reference contained in X.
type Conjunct struct {
diff --git a/internal/core/adt/expr.go b/internal/core/adt/expr.go
index a2dd75f..bd4a02c 100644
--- a/internal/core/adt/expr.go
+++ b/internal/core/adt/expr.go
@@ -875,11 +875,7 @@
return err
}
- value := BinOp(c, x.Op, left, right)
- if n, ok := value.(*Vertex); ok && n.IsList() {
- n.UpdateStatus(Partial)
- }
- return value
+ return BinOp(c, x.Op, left, right)
}
// A CallExpr represents a call to a builtin.
diff --git a/internal/core/eval/eval.go b/internal/core/eval/eval.go
index 8ab1974..30499e1 100644
--- a/internal/core/eval/eval.go
+++ b/internal/core/eval/eval.go
@@ -1731,6 +1731,9 @@
// TODO: disallow adding conjuncts when cache set?
arc.AddConjunct(x)
+ adt.Assert("invalid adt.ID",
+ x.CloseID == 0 || int(x.CloseID) < len(closedInfo(n.node).Canopy))
+
if isNew {
closedInfo(n.node).visitAllFieldSets(func(o *fieldSet) {
o.MatchAndInsert(ctx, arc)