cue: delay default picking
Allows values to be examined before manifestation.
Defaults will still be selected for all the methods that
request concrete values.
Change-Id: I80220b639fc0b2e34fc8e33aa4c847c2b31095fd
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/1966
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/instance.go b/cue/instance.go
index e3b0fbf..452d5ff 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -71,6 +71,7 @@
}
func (inst *Instance) eval(ctx *context) evaluated {
+ // TODO: remove manifest here? It may be good here, though not consistent.
v := ctx.manifest(inst.rootValue)
if s, ok := v.(*structLit); ok && s.emit != nil {
v = ctx.manifest(s.emit)
diff --git a/cue/types.go b/cue/types.go
index f9aa791..b3d0bcc 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -210,6 +210,7 @@
}
func (v Value) getNum(k kind) (*numLit, error) {
+ v, _ = v.Default()
if err := v.checkKind(v.ctx(), k); err != nil {
return nil, err
}
@@ -455,7 +456,7 @@
func newChildValue(obj *structValue, i int) Value {
a := obj.n.arcs[i]
- a.cache = obj.ctx.manifest(obj.n.at(obj.ctx, i))
+ a.cache = obj.n.at(obj.ctx, i)
return Value{obj.ctx.index, &valueData{obj.path, uint32(i), a}}
}
@@ -472,7 +473,6 @@
}
func (v Value) makeChild(ctx *context, i uint32, a arc) Value {
- a.cache = ctx.manifest(a.cache)
return Value{v.idx, &valueData{v.path, i, a}}
}
@@ -523,7 +523,7 @@
if v.path == nil {
return BottomKind
}
- k := v.eval(v.ctx()).kind()
+ k := v.path.v.evalPartial(v.ctx()).kind()
if k.isGround() {
switch {
case k.isAnyOf(nullKind):
@@ -551,7 +551,10 @@
// IncompleteKind returns a mask of all kinds that this value may be.
func (v Value) IncompleteKind() Kind {
- k := v.eval(v.ctx()).kind()
+ if v.path == nil {
+ return BottomKind
+ }
+ k := v.path.v.evalPartial(v.ctx()).kind()
vk := BottomKind // Everything is a bottom kind.
for i := kind(1); i < nonGround; i <<= 1 {
if k&i != 0 {
@@ -580,6 +583,7 @@
// MarshalJSON marshalls this value into valid JSON.
func (v Value) MarshalJSON() (b []byte, err error) {
+ v, _ = v.Default()
if v.path == nil {
return json.Marshal(nil)
}
@@ -692,6 +696,7 @@
// Err returns the error represented by v or nil v is not an error.
func (v Value) Err() error {
+ // TODO(incomplete): change to not return an error for incomplete.
if err := v.checkKind(v.ctx(), bottomKind); err != nil {
return err
}
@@ -828,6 +833,7 @@
// List creates an iterator over the values of a list or reports an error if
// v is not a list.
func (v Value) List() (Iterator, error) {
+ v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, listKind); err != nil {
return Iterator{ctx: ctx}, err
@@ -838,19 +844,21 @@
// Null reports an error if v is not null.
func (v Value) Null() error {
+ v, _ = v.Default()
if err := v.checkKind(v.ctx(), nullKind); err != nil {
return err
}
return nil
}
-// IsNull reports whether v is null.
-func (v Value) IsNull() bool {
- return v.Null() == nil
-}
+// // IsNull reports whether v is null.
+// func (v Value) IsNull() bool {
+// return v.Null() == nil
+// }
// Bool returns the bool value of v or false and an error if v is not a boolean.
func (v Value) Bool() (bool, error) {
+ v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, boolKind); err != nil {
return false, err
@@ -860,6 +868,7 @@
// String returns the string value if v is a string or an error otherwise.
func (v Value) String() (string, error) {
+ v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, stringKind); err != nil {
return "", err
@@ -870,6 +879,7 @@
// Bytes returns a byte slice if v represents a list of bytes or an error
// otherwise.
func (v Value) Bytes() ([]byte, error) {
+ v, _ = v.Default()
ctx := v.ctx()
switch x := v.eval(ctx).(type) {
case *bytesLit:
@@ -883,6 +893,7 @@
// Reader returns a new Reader if v is a string or bytes type and an error
// otherwise.
func (v Value) Reader() (io.Reader, error) {
+ v, _ = v.Default()
ctx := v.ctx()
switch x := v.eval(ctx).(type) {
case *bytesLit:
@@ -907,6 +918,7 @@
// structVal returns an structVal or an error if v is not a struct.
func (v Value) structValOpts(ctx *context, o options) (structValue, error) {
+ v, _ = v.Default()
if err := v.checkKind(ctx, structKind); err != nil {
return structValue{}, err
}
@@ -1023,11 +1035,11 @@
if w.path == nil {
return v
}
- a := v.path.cache.evalPartial(ctx)
- b := w.path.cache.evalPartial(ctx)
+ a := v.path.v
+ b := w.path.v
src := binSrc(token.NoPos, opUnify, a, b)
- val := binOp(ctx, src, opUnify, a, b)
- if err := validate(ctx, val); err != nil {
+ val := mkBin(ctx, src.Pos(), opUnify, a, b)
+ if err := validate(ctx, val.evalPartial(ctx)); err != nil {
val = err
}
return newValueRoot(ctx, val)