cue: support list addition
Change-Id: Iba4c4c83c6b4c55af8743199d1e9fa01be86182c
Reviewed-on: https://cue-review.googlesource.com/c/1563
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/binop.go b/cue/binop.go
index b3fe6c7..a6976ba 100644
--- a/cue/binop.go
+++ b/cue/binop.go
@@ -956,6 +956,25 @@
}
return &list{baseValue: binSrc(src.Pos(), op, x, other), a: a, typ: typ, len: n}
+ case opAdd:
+ y, ok := other.(*list)
+ if !ok {
+ break
+ }
+ n := &list{baseValue: binSrc(src.Pos(), op, x, other), typ: y.typ}
+ n.a = append(x.a, y.a...)
+ switch v := y.len.(type) {
+ case *numLit:
+ // Closed list
+ ln := &numLit{numBase: v.numBase}
+ ln.v.SetInt64(int64(len(n.a)))
+ n.len = ln
+ default:
+ // Open list
+ n.len = y.len
+ }
+ return n
+
case opMul:
k := other.kind()
if !k.isAnyOf(intKind) {
diff --git a/cue/kind.go b/cue/kind.go
index c5d281f..fdc4aed 100644
--- a/cue/kind.go
+++ b/cue/kind.go
@@ -55,6 +55,7 @@
referenceKind
atomKind = (listKind - 1) &^ unknownKind
+ addableKind = (structKind - 1) &^ unknownKind
concreteKind = (lambdaKind - 1) &^ unknownKind
// doneKind indicates a value can not further develop on its own (i.e. not a
@@ -257,9 +258,8 @@
return boolKind | catBits, false
}
case opAdd:
- if u.isAnyOf(atomKind) {
- return u&(atomKind) | catBits, false
- // u&(durationKind|intKind)
+ if u.isAnyOf(addableKind) {
+ return u&(addableKind) | catBits, false
}
case opSub:
if u.isAnyOf(scalarKinds) {
diff --git a/cue/resolve_test.go b/cue/resolve_test.go
index ba47879..5780db3 100644
--- a/cue/resolve_test.go
+++ b/cue/resolve_test.go
@@ -279,6 +279,10 @@
b0: 'foo' + 'bar'
b1: 3 * 'abc'
b2: 'abc' * 2
+
+ // TODO: consider the semantics of this and perhaps allow this.
+ e0: "a" + ''
+ e1: 'b' + "c"
`,
out: `<0>{` +
`s0: "foobar", ` +
@@ -286,7 +290,10 @@
`s2: "abcabc", ` +
`b0: 'foobar', ` +
`b1: 'abcabcabc', ` +
- `b2: 'abcabc'` +
+ `b2: 'abcabc', ` +
+
+ `e0: _|_(("a" + ''):unsupported op +(string, bytes)), ` +
+ `e1: _|_(('b' + "c"):unsupported op +(bytes, string))` +
`}`,
}, {
desc: "escaping",
@@ -834,6 +841,44 @@
l6: 3*[...int]
l7: 3*[1, ...int]
l8: 3*[1, 2, ...int]
+
+ s0: [] + []
+ s1: [1] + []
+ s2: [] + [2]
+ s3: [1] + [2]
+ s4: [1,2] + []
+ s5: [] + [1,2]
+ s6: [1] + [1,2]
+ s7: [1,2] + [1]
+ s8: [1,2] + [1,2]
+ s9: [] + [...]
+ s10: [1] + [...]
+ s11: [] + [2, ...]
+ s12: [1] + [2, ...]
+ s13: [1,2] + [...]
+ s14: [] + [1,2, ...]
+ s15: [1] + [1,2, ...]
+ s16: [1,2] + [1, ...]
+ s17: [1,2] + [1,2, ...]
+
+ s18: [...] + []
+ s19: [1, ...] + []
+ s20: [...] + [2]
+ s21: [1, ...] + [2]
+ s22: [1,2, ...] + []
+ s23: [...] + [1,2]
+ s24: [1, ...] + [1,2]
+ s25: [1,2, ...] + [1]
+ s26: [1,2, ...] + [1,2]
+ s27: [...] + [...]
+ s28: [1, ...] + [...]
+ s29: [...] + [2, ...]
+ s30: [1, ...] + [2, ...]
+ s31: [1,2, ...] + [...]
+ s32: [...] + [1,2, ...]
+ s33: [1, ...] + [1,2, ...]
+ s34: [1,2, ...] + [1, ...]
+ s35: [1,2, ...] + [1,2, ...]
`,
out: `<0>{l0: [1,2,3,1,2,3,1,2,3], ` +
`l1: [], ` +
@@ -843,7 +888,46 @@
`l5: (<=2 * (int * [int])), ` +
`l6: [, ...int], ` +
`l7: [1,1,1, ...int], ` +
- `l8: [1,2,1,2,1,2, ...int]` +
+ `l8: [1,2,1,2,1,2, ...int], ` +
+
+ `s0: [], ` +
+ `s1: [1], ` +
+ `s2: [2], ` +
+ `s3: [1,2], ` +
+ `s4: [1,2], ` +
+ `s5: [1,2], ` +
+ `s6: [1,1,2], ` +
+ `s7: [1,2,1], ` +
+ `s8: [1,2,1,2], ` +
+ `s9: [, ...], ` +
+ `s10: [1, ...], ` +
+ `s11: [2, ...], ` +
+ `s12: [1,2, ...], ` +
+ `s13: [1,2, ...], ` +
+ `s14: [1,2, ...], ` +
+ `s15: [1,1,2, ...], ` +
+ `s16: [1,2,1, ...], ` +
+ `s17: [1,2,1,2, ...], ` +
+
+ `s18: [], ` +
+ `s19: [1], ` +
+ `s20: [2], ` +
+ `s21: [1,2], ` +
+ `s22: [1,2], ` +
+ `s23: [1,2], ` +
+ `s24: [1,1,2], ` +
+ `s25: [1,2,1], ` +
+ `s26: [1,2,1,2], ` +
+ `s27: [, ...], ` +
+ `s28: [1, ...], ` +
+ `s29: [2, ...], ` +
+ `s30: [1,2, ...], ` +
+ `s31: [1,2, ...], ` +
+ `s32: [1,2, ...], ` +
+ `s33: [1,1,2, ...], ` +
+ `s34: [1,2,1, ...], ` +
+ `s35: [1,2,1,2, ...]` +
+
`}`,
}, {
desc: "correct error messages",
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index 09b4015..94228ec 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -1544,6 +1544,7 @@
[ 1, 2 ] + [ 3, 4 ] // [ 1, 2, 3, 4 ]
[ 1, 2, ... ] + [ 3, 4 ] // [ 1, 2, 3, 4 ]
[ 1, 2 ] + [ 3, 4, ... ] // [ 1, 2, 3, 4, ... ]
+[ 1, 2, ... ] + [ 3, 4, ... ] // [ 1, 2, 3, 4, ... ]
```
Lists can be multiplied with a non-negative`int` using the `*` operator