cue: simplify numLit
- more convenient helper functions
- only one composite literal of numLit (simplifies checking)
Change-Id: I1fb224f1bf7770710428b5e3e923489400d00658
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4421
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/binop.go b/cue/binop.go
index 38dcdb1..a0e9d4f 100644
--- a/cue/binop.go
+++ b/cue/binop.go
@@ -268,9 +268,7 @@
if k == y.k {
return y
}
- i := *y
- i.k = k
- return &i
+ return y.specialize(k)
}
src = mkBin(ctx, src.Pos(), op, x, other)
return ctx.mkErr(src, codeIncomplete, "%s with incomplete values", op)
@@ -446,40 +444,30 @@
// a+1 if b-a == 2
// _|_ if b <= a
+ n := newNum(src, k&numKind, a.rep|b.rep)
switch diff, err := d.Int64(); {
case err != nil:
case diff == 1:
if k&floatKind == 0 {
if x.op == opGeq && y.op == opLss {
- n := *a
- n.k = k & numKind
- n.v.Set(&lo)
- return &n
+ return n.set(&lo)
}
if x.op == opGtr && y.op == opLeq {
- n := *b
- n.k = k & numKind
- n.v.Set(&hi)
- return &n
+ return n.set(&hi)
}
}
case diff == 2:
if k&floatKind == 0 && x.op == opGtr && y.op == opLss {
_, _ = apd.BaseContext.Add(&d, d.SetInt64(1), &lo)
- n := *a
- n.k = k & numKind
- n.v.Set(&d)
- return &n
+ return n.set(&d)
+
}
case diff == 0:
if x.op == opGeq && y.op == opLeq {
- n := *a
- n.k = k & numKind
- n.v.Set(&lo)
- return &n
+ return n.set(&lo)
}
fallthrough
@@ -506,9 +494,7 @@
}
// Narrow down number type.
if y.k != k {
- n := *y
- n.k = k
- return &n
+ return y.specialize(k)
}
return other
@@ -552,9 +538,7 @@
}
// Narrow down number type.
if y.k != k {
- n := *y
- n.k = k
- return &n
+ return y.specialize(k)
}
return other
@@ -1024,7 +1008,14 @@
}
case *numLit:
k, _, _ := matchBinOpKind(op, x.kind(), y.kind())
- n := newNumBin(k, x, y)
+ if k == bottomKind {
+ break
+ }
+ switch op {
+ case opLss, opLeq, opEql, opNeq, opGeq, opGtr:
+ return cmpTonode(src, op, x.v.Cmp(&y.v))
+ }
+ n := newNum(src.base(), k, x.rep|y.rep)
switch op {
case opUnify, opUnifyUnchecked:
if x.v.Cmp(&y.v) != 0 {
@@ -1037,8 +1028,6 @@
return n
}
return x
- case opLss, opLeq, opEql, opNeq, opGeq, opGtr:
- return cmpTonode(src, op, x.v.Cmp(&y.v))
case opAdd:
_, _ = ctx.Add(&n.v, &x.v, &y.v)
case opSub:
@@ -1140,19 +1129,13 @@
case opSub:
return &durationLit{binSrc(src.Pos(), op, x, other), x.d - y.d}
case opQuo:
- n := &numLit{
- numBase: newNumBase(nil, newNumInfo(floatKind, 0, 10, false)),
- }
- n.v.SetInt64(int64(x.d))
+ n := newFloat(src.base(), base10).setInt64(int64(x.d))
d := apd.New(int64(y.d), 0)
// TODO: check result if this code becomes undead.
_, _ = ctx.Quo(&n.v, &n.v, d)
return n
case opIRem:
- n := &numLit{
- numBase: newNumBase(nil, newNumInfo(intKind, 0, 10, false)),
- }
- n.v.SetInt64(int64(x.d % y.d))
+ n := newInt(src.base(), base10).setInt64(int64(x.d % y.d))
n.v.Exponent = -9
return n
}
@@ -1254,9 +1237,7 @@
switch v := y.len.(type) {
case *numLit:
// Closed list
- ln := &numLit{numBase: v.numBase}
- ln.v.SetInt64(int64(len(arcs)))
- n.len = ln
+ n.len = newInt(v.base(), v.rep).setInt(len(arcs))
default:
// Open list
n.len = y.len // TODO: add length of x?
@@ -1290,9 +1271,7 @@
switch v := x.len.(type) {
case *numLit:
// Closed list
- ln := &numLit{numBase: v.numBase}
- ln.v.SetInt64(int64(len(arcs)))
- n.len = ln
+ n.len = newInt(v.base(), v.rep).setInt(len(arcs))
default:
// Open list
n.len = x.len // TODO: multiply length?
diff --git a/cue/go.go b/cue/go.go
index 09c1ae6..468369b 100644
--- a/cue/go.go
+++ b/cue/go.go
@@ -210,7 +210,7 @@
return ctx.manifest(x.walk(v))
case *big.Int:
- n := newNum(src, intKind)
+ n := newInt(src.base(), 0)
n.v.Coeff.Set(v)
if v.Sign() < 0 {
n.v.Coeff.Neg(&n.v.Coeff)
@@ -220,7 +220,7 @@
case *big.Rat:
// should we represent this as a binary operation?
- n := newNum(src, numKind)
+ n := newNum(src, numKind, 0)
_, err := ctx.Quo(&n.v, apd.NewWithBigInt(v.Num(), 0), apd.NewWithBigInt(v.Denom(), 0))
if err != nil {
return ctx.mkErr(src, err)
@@ -231,13 +231,10 @@
return n
case *big.Float:
- n := newNum(src, floatKind)
- _, _, _ = n.v.SetString(v.String())
- return n
+ return newFloat(src, 0).setString(v.String())
case *apd.Decimal:
- n := newNum(src, floatKind|intKind)
- n.v.Set(v)
+ n := newNum(src, numKind, 0).set(v)
if !n.isInt(ctx) {
n.k = floatKind
}
@@ -293,13 +290,9 @@
case uintptr:
return toUint(ctx, src, uint64(v))
case float64:
- r := newNum(src, floatKind)
- _, _, _ = r.v.SetString(fmt.Sprintf("%g", v))
- return r
+ return newFloat(src, 0).setString(fmt.Sprintf("%g", v))
case float32:
- r := newNum(src, floatKind)
- _, _, _ = r.v.SetString(fmt.Sprintf("%g", v))
- return r
+ return newFloat(src, 0).setString(fmt.Sprintf("%g", v))
case reflect.Value:
if v.CanInterface() {
@@ -446,15 +439,11 @@
}
func toInt(ctx *context, src source, x int64) evaluated {
- n := newNum(src, intKind)
- n.v.SetInt64(x)
- return n
+ return newInt(src, 0).setInt64(x)
}
func toUint(ctx *context, src source, x uint64) evaluated {
- n := newNum(src, intKind)
- n.v.Coeff.SetUint64(x)
- return n
+ return newInt(src, 0).setUInt64(x)
}
func convertGoType(r *Runtime, t reflect.Type) value {
diff --git a/cue/go_test.go b/cue/go_test.go
index b9d749e..b311a97 100644
--- a/cue/go_test.go
+++ b/cue/go_test.go
@@ -25,6 +25,8 @@
"github.com/cockroachdb/apd/v2"
)
+func mkBigInt(a int64) (v apd.Decimal) { v.SetInt64(a); return }
+
func TestConvert(t *testing.T) {
i34 := big.NewInt(34)
d34 := mkBigInt(34)
diff --git a/cue/kind.go b/cue/kind.go
index a2a7235..1f95d00 100644
--- a/cue/kind.go
+++ b/cue/kind.go
@@ -264,7 +264,11 @@
if u.isAnyOf(boolKind) {
return boolKind | catBits, swap, ""
}
- case opEql, opNeq, opMat, opNMat:
+ case opMat, opNMat:
+ if u.isAnyOf(stringKind | bytesKind) {
+ return boolKind | catBits, false, ""
+ }
+ case opEql, opNeq:
if u.isAnyOf(fixedKinds) {
return boolKind | catBits, false, ""
}
diff --git a/cue/lit.go b/cue/lit.go
index 325f9e5..6f88baf 100644
--- a/cue/lit.go
+++ b/cue/lit.go
@@ -22,33 +22,24 @@
"github.com/cockroachdb/apd/v2"
)
-type numInfo struct {
- rep multiplier
- k kind
-}
-
-func newNumInfo(k kind, m multiplier, base int, sep bool) numInfo {
+func newRepresentation(m multiplier, base int, sep bool) multiplier {
switch base {
case 10:
m |= base10
case 2:
m |= base2
- k = intKind
case 8:
m |= base8
- k = intKind
case 16:
m |= base16
- k = intKind
}
if sep {
m |= hasSeparators
}
- return numInfo{m, k}
+ return m
}
-func (n numInfo) isValid() bool { return n.k != bottomKind }
-func (n numInfo) multiplier() multiplier { return n.rep & (hasSeparators - 1) }
+func (m multiplier) multiplier() multiplier { return m & (hasSeparators - 1) }
type multiplier uint16
@@ -307,9 +298,7 @@
} else {
mul |= mulDec
}
- n := &numLit{
- numBase: newNumBase(p.node, newNumInfo(intKind, mul, 10, p.useSep)),
- }
+ n := newInt(newExpr(p.node), newRepresentation(mul, 10, p.useSep))
n.v.UnmarshalText(p.buf)
p.ctx.Mul(&n.v, &n.v, mulToRat[mul])
cond, _ := p.ctx.RoundToIntegralExact(&n.v, &n.v)
@@ -331,13 +320,11 @@
exit:
if isFloat {
- f := &numLit{
- numBase: newNumBase(p.node, newNumInfo(floatKind, 0, 10, p.useSep)),
- }
+ f := newFloat(newExpr(p.node), newRepresentation(0, 10, p.useSep))
f.v.UnmarshalText(p.buf)
return f
}
- i := &numLit{numBase: newNumBase(p.node, newNumInfo(intKind, 0, base, p.useSep))}
+ i := newInt(newExpr(p.node), newRepresentation(0, base, p.useSep))
i.v.Coeff.SetString(string(p.buf), base)
return i
}
diff --git a/cue/lit_test.go b/cue/lit_test.go
index 41c1238..ff0d357 100644
--- a/cue/lit_test.go
+++ b/cue/lit_test.go
@@ -25,27 +25,17 @@
"github.com/google/go-cmp/cmp/cmpopts"
)
-var defIntBase = newNumBase(&ast.BasicLit{}, newNumInfo(intKind, 0, 10, false))
-var defRatBase = newNumBase(&ast.BasicLit{}, newNumInfo(floatKind, 0, 10, false))
+var testBase = newExpr(&ast.BasicLit{})
func mkInt(a int64) *numLit {
- x := &numLit{numBase: defIntBase}
- x.v.SetInt64(a)
- return x
+ return newInt(testBase, base10).setInt64(a)
}
func mkIntString(a string) *numLit {
- x := &numLit{numBase: defIntBase}
- x.v.SetString(a)
- return x
+ return newInt(testBase, base10).setString(a)
}
func mkFloat(a string) *numLit {
- x := &numLit{numBase: defRatBase}
- x.v.SetString(a)
- return x
+ return newFloat(testBase, base10).setString(a)
}
-func mkBigInt(a int64) (v apd.Decimal) { v.SetInt64(a); return }
-
-func mkBigFloat(a string) (v apd.Decimal) { v.SetString(a); return }
var diffOpts = []cmp.Option{
cmp.Comparer(func(x, y big.Rat) bool {
@@ -60,8 +50,6 @@
stringLit{},
bytesLit{},
numLit{},
- numBase{},
- numInfo{},
),
cmpopts.IgnoreUnexported(
bottom{},
@@ -78,15 +66,9 @@
func TestLiterals(t *testing.T) {
mkMul := func(x int64, m multiplier, base int) *numLit {
- return &numLit{
- newNumBase(&ast.BasicLit{}, newNumInfo(intKind, m, base, false)),
- mkBigInt(x),
- }
+ return newInt(testBase, newRepresentation(m, base, false)).setInt64(x)
}
- hk := &numLit{
- newNumBase(&ast.BasicLit{}, newNumInfo(intKind, 0, 10, true)),
- mkBigInt(100000),
- }
+ hk := newInt(testBase, newRepresentation(0, 10, true)).setInt64(100000)
testCases := []struct {
lit string
node value
diff --git a/cue/types.go b/cue/types.go
index c019e11..9976180 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -985,10 +985,7 @@
}
func makeInt(v Value, x int64) Value {
- n := &numLit{numBase: numBase{baseValue: v.path.v.base()}}
- n.v.SetInt64(x)
- n.k = intKind
- return remakeValue(v, n)
+ return remakeValue(v, newInt(v.path.v.base(), base10).setInt64(x))
}
// Len returns the number of items of the underlying value.
diff --git a/cue/value.go b/cue/value.go
index 59c0ef1..f6e612e 100644
--- a/cue/value.go
+++ b/cue/value.go
@@ -216,9 +216,7 @@
return ctx.mkErr(x, "index %d out of bounds", i)
}
// TODO: this is incorrect.
- n := newNum(x, intKind)
- n.v.SetInt64(int64(x.b[i]))
- return n
+ return newInt(x, 0).setUInt64(uint64(x.b[i]))
}
func (x *bytesLit) len() int { return len(x.b) }
@@ -302,28 +300,59 @@
return &stringLit{x.baseValue, string(runes[lox:hix]), nil}
}
-type numBase struct {
+type numLit struct {
baseValue
- numInfo
+ rep multiplier
+ k kind
+ v apd.Decimal
}
-func newNumBase(n ast.Expr, info numInfo) numBase {
- return numBase{newExpr(n), info}
-}
-
-func newNumBin(k kind, a, b *numLit) *numLit {
- n := &numLit{
- numBase: numBase{
- baseValue: a.baseValue,
- numInfo: numInfo{a.rep | b.rep, k},
- },
+func newNum(src source, k kind, rep multiplier) *numLit {
+ if rep&base2|base8|base10|base16 == 0 {
+ rep |= base10
}
+ if k&numKind == 0 {
+ panic("not a number")
+ }
+ return &numLit{baseValue: src.base(), rep: rep, k: k}
+}
+
+func newInt(src source, rep multiplier) *numLit {
+ return newNum(src, intKind, rep)
+}
+
+func newFloat(src source, rep multiplier) *numLit {
+ return newNum(src, floatKind, rep)
+}
+
+func (n numLit) specialize(k kind) *numLit {
+ n.k = k
+ return &n
+}
+
+func (n *numLit) set(d *apd.Decimal) *numLit {
+ n.v.Set(d)
return n
}
-type numLit struct {
- numBase
- v apd.Decimal
+func (n *numLit) setInt(x int) *numLit {
+ n.v.SetInt64(int64(x))
+ return n
+}
+
+func (n *numLit) setInt64(x int64) *numLit {
+ n.v.SetInt64(x)
+ return n
+}
+
+func (n *numLit) setUInt64(x uint64) *numLit {
+ n.v.Coeff.SetUint64(x)
+ return n
+}
+
+func (n *numLit) setString(s string) *numLit {
+ _, _, _ = n.v.SetString(s)
+ return n
}
func (n *numLit) String() string {
@@ -342,7 +371,7 @@
Kind: token.INT,
Value: s,
}
- num := newNum(newExpr(n), k)
+ num := newInt(newExpr(n), 0)
_, _, err := num.v.SetString(s)
if err != nil {
panic(err)
@@ -355,7 +384,7 @@
Kind: token.FLOAT,
Value: s,
}
- num := newNum(newExpr(n), floatKind)
+ num := newFloat(newExpr(n), 0)
_, _, err := num.v.SetString(s)
if err != nil {
panic(err)
@@ -363,12 +392,6 @@
return num
}
-func newNum(src source, k kind) *numLit {
- n := &numLit{numBase: numBase{baseValue: src.base()}}
- n.k = k
- return n
-}
-
var ten = big.NewInt(10)
var one = parseInt(intKind, "1")
@@ -508,9 +531,7 @@
// initLit initializes a literal list.
func (x *list) initLit() {
- n := newNum(x, intKind)
- n.v.SetInt64(int64(len(x.elem.arcs)))
- x.len = n
+ x.len = newInt(x, 0).setInt(len(x.elem.arcs))
x.typ = &top{x.baseValue}
}
@@ -520,8 +541,7 @@
}
// A list is ground if its length is ground, or if the current length
// meets matches the cap.
- n := newNum(x, intKind)
- n.v.SetInt64(int64(len(x.elem.arcs)))
+ n := newInt(x, 0).setInt(len(x.elem.arcs))
if n := binOp(ctx, x, opUnify, n, x.len.evalPartial(ctx)); !isBottom(n) {
return &list{
baseValue: x.baseValue,
@@ -1908,8 +1928,7 @@
case *list:
for i := range src.elem.arcs {
- idx := newNum(x, intKind)
- idx.v.SetInt64(int64(i))
+ idx := newInt(x, 0).setInt(i)
v := fn.call(ctx, x, idx, src.at(ctx, i))
if err, ok := v.(*bottom); ok {
return err
diff --git a/cuego/examples_test.go b/cuego/examples_test.go
index 9e160a9..b56a323 100644
--- a/cuego/examples_test.go
+++ b/cuego/examples_test.go
@@ -42,7 +42,7 @@
//Output:
// completed: cuego_test.Sum{A:1, B:5, C:6} (err: <nil>)
// completed: cuego_test.Sum{A:2, B:6, C:8} (err: <nil>)
- // empty disjunction: invalid operation null & {A: 2, B: 3, C: 8} (mismatched types null and struct)
+ // empty disjunction: conflicting values 5 and 2
}
func ExampleConstrain() {