cue: fix lookup for cue API
Fixes analogue of commit c937e7a0e47b.
Fixes #157
Issue #202
Change-Id: Ieb3e37206b5cbe1ddddebfb2712f07b9e9efccf6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4220
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/instance.go b/cue/instance.go
index 9b7955e..60ceffb 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -257,7 +257,7 @@
i.setError(val.toErr(err))
return i
}
- i.scope = v.n
+ i.scope = v.obj
if err := resolveFiles(idx, p); err != nil {
i.setError(err)
diff --git a/cue/types.go b/cue/types.go
index e62d628..8f7c30b 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -135,20 +135,21 @@
type structValue struct {
ctx *context
path *valueData
- n *structLit
+ obj *structLit
+ arcs arcs
}
// Len reports the number of fields in this struct.
func (o *structValue) Len() int {
- if o.n == nil {
+ if o.obj == nil {
return 0
}
- return len(o.n.arcs)
+ return len(o.arcs)
}
// At reports the key and value of the ith field, i < o.Len().
func (o *structValue) At(i int) (key string, v Value) {
- a := o.n.arcs[i]
+ a := o.arcs[i]
v = newChildValue(o, i)
return o.ctx.labelStr(a.feature), v
}
@@ -160,19 +161,17 @@
i := 0
len := o.Len()
for ; i < len; i++ {
- if o.n.arcs[i].feature == f {
+ if o.arcs[i].feature == f {
break
}
}
if i == len {
// TODO: better message.
ctx := o.ctx
- x := ctx.mkErr(o.n, codeNotExist, "value %q not found", key)
+ x := ctx.mkErr(o.obj, codeNotExist, "value %q not found", key)
v := x.evalPartial(ctx)
return Value{ctx.index, &valueData{o.path, 0, arc{cache: v, v: x}}}
}
- // v, _ := o.n.lookup(o.ctx, f)
- // v = o.ctx.manifest(v)
return newChildValue(o, i)
}
@@ -606,8 +605,26 @@
}
func newChildValue(obj *structValue, i int) Value {
- a := obj.n.arcs[i]
- a.cache = obj.n.at(obj.ctx, i)
+ a := obj.arcs[i]
+ for j, b := range obj.obj.arcs {
+ if b.feature == a.feature {
+ a = obj.obj.iterAt(obj.ctx, j)
+ // TODO: adding more technical debt here. The evaluator should be
+ // rewritten.
+ x := obj.obj
+ ctx := obj.ctx
+ if x.optionals != nil {
+ name := ctx.labelStr(x.arcs[i].feature)
+ arg := &stringLit{x.baseValue, name, nil}
+
+ val, _ := x.optionals.constraint(ctx, arg)
+ if val != nil {
+ a.v = mkBin(ctx, x.Pos(), opUnify, a.v, val)
+ }
+ }
+ break
+ }
+ }
return Value{obj.ctx.index, &valueData{obj.path, uint32(i), a}}
}
@@ -640,7 +657,8 @@
if v.path == nil {
return v
}
- return remakeValue(v, v.path.v.evalPartial(v.ctx()))
+ fmt.Println(v)
+ return remakeValue(v, v.path.v)
}
// Default reports the default value and whether it existed. It returns the
@@ -1148,17 +1166,9 @@
k++
}
arcs = arcs[:k]
- obj = &structLit{
- obj.baseValue, // baseValue
- obj.emit, // emit
- obj.optionals, // template
- obj.closeStatus, // closeStatus
- nil, // comprehensions
- arcs, // arcs
- nil, // attributes
- }
+ return structValue{ctx, v.path, obj, arcs}, nil
}
- return structValue{ctx, v.path, obj}, nil
+ return structValue{ctx, v.path, obj, obj.arcs}, nil
}
// Struct returns the underlying struct of a value or an error if the value
@@ -1206,6 +1216,19 @@
a := s.s.arcs[i]
a.cache = s.s.at(ctx, i)
+ // TODO: adding more technical debt here. The evaluator should be
+ // rewritten.
+ x := s.s
+ if x.optionals != nil {
+ name := ctx.labelStr(x.arcs[i].feature)
+ arg := &stringLit{x.baseValue, name, nil}
+
+ val, _ := x.optionals.constraint(ctx, arg)
+ if val != nil {
+ a.v = mkBin(ctx, x.Pos(), opUnify, a.v, val)
+ }
+ }
+
v := Value{ctx.index, &valueData{s.v.path, uint32(i), a}}
str := ctx.labelStr(a.feature)
return FieldInfo{str, i, v, a.definition, a.optional, a.feature&hidden != 0}
@@ -1237,7 +1260,16 @@
if err != nil {
return Iterator{ctx: ctx}, v.toErr(err)
}
- return Iterator{ctx: ctx, val: v, iter: obj.n, len: len(obj.n.arcs)}, nil
+ n := &structLit{
+ obj.obj.baseValue, // baseValue
+ obj.obj.emit, // emit
+ obj.obj.optionals, // template
+ obj.obj.closeStatus, // closeStatus
+ nil, // comprehensions
+ obj.arcs, // arcs
+ nil, // attributes
+ }
+ return Iterator{ctx: ctx, val: v, iter: n, len: len(n.arcs)}, nil
}
// Lookup reports the value at a path starting from v.
@@ -1665,7 +1697,7 @@
for i := 0; i < obj.Len(); i++ {
_, v := obj.At(i)
opts := opts
- if obj.n.arcs[i].definition {
+ if obj.arcs[i].definition {
opts.concrete = false
}
x.walk(v, opts)
diff --git a/cue/types_test.go b/cue/types_test.go
index 010808a..bbebffd 100644
--- a/cue/types_test.go
+++ b/cue/types_test.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "go/parser"
"io/ioutil"
"math"
"math/big"
@@ -687,6 +688,69 @@
}
}
+func TestLookup(t *testing.T) {
+ _ = parser.ParseFile
+ var runtime = new(Runtime)
+ inst, err := runtime.Compile("x.cue", `
+V :: {
+ x: int
+}
+X :: {
+ <_>: int64
+} & V
+v: X
+`)
+ if err != nil {
+ t.Fatalf("compile: %v", err)
+ }
+ // expr, err := parser.ParseExpr("lookup.cue", `v`, parser.DeclarationErrors, parser.AllErrors)
+ // if err != nil {
+ // log.Fatalf("parseExpr: %v", err)
+ // }
+ // v := inst.Eval(expr)
+ testCases := []struct {
+ ref []string
+ raw string
+ eval string
+ }{{
+ ref: []string{"v", "x"},
+ raw: "(int & <=9223372036854775807 & int & >=-9223372036854775808)",
+ eval: "int64",
+ }}
+ for _, tc := range testCases {
+ v := inst.Lookup(tc.ref...)
+
+ if got := fmt.Sprint(v); got != tc.raw {
+ t.Errorf("got %v; want %v", got, tc.raw)
+ }
+
+ if got := fmt.Sprint(v.Eval().Syntax()); got != tc.eval {
+ t.Errorf("got %v; want %v", got, tc.eval)
+ }
+
+ v = inst.Lookup()
+ for _, ref := range tc.ref {
+ s, err := v.Struct()
+ if err != nil {
+ t.Fatal(err)
+ }
+ fi, err := s.FieldByName(ref)
+ if err != nil {
+ t.Fatal(err)
+ }
+ v = fi.Value
+ }
+
+ if got := fmt.Sprint(v); got != tc.raw {
+ t.Errorf("got %v; want %v", got, tc.raw)
+ }
+
+ if got := fmt.Sprint(v.Eval().Syntax()); got != tc.eval {
+ t.Errorf("got %v; want %v", got, tc.eval)
+ }
+ }
+}
+
func TestDefaults(t *testing.T) {
testCases := []struct {
value string
@@ -1745,7 +1809,7 @@
return doc
}
-func TestMashalJSON(t *testing.T) {
+func TestMarshalJSON(t *testing.T) {
testCases := []struct {
value string
json string