Skip to content

Commit 6c49cf0

Browse files
committed
cue: implement embedded scalars
Mostly already implemented in evaluator. Changes - some adjustments in evaluator - FieldSetDefined no longer necessary as result of adjustments. - print definitions alongside scalars if requested in value mode. Change-Id: Ie00dc2ef1dfe5a001c6133f0e7a27546687e2c9b Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7728 Reviewed-by: CUE cueckoo <[email protected]> Reviewed-by: Marcel van Lohuizen <[email protected]>
1 parent 1c904cc commit 6c49cf0

File tree

9 files changed

+326
-50
lines changed

9 files changed

+326
-50
lines changed
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,41 @@
11
-- in.cue --
22
cond: bool
3-
src: {}
3+
src: {}
4+
top: _
45
a: [ if cond {} ]
56
b: [ for x in src.foo {} ]
7+
c: { for x in top {} }
68
-- out/eval --
79
(struct){
810
cond: (bool){ bool }
911
src: (struct){
1012
}
13+
top: (_){ _ }
1114
a: (_|_){
1215
// [incomplete] a: incomplete bool value 'bool'
1316
}
1417
b: (_|_){
1518
// [incomplete] b: undefined field foo:
16-
// ./in.cue:4:19
19+
// ./in.cue:5:19
20+
}
21+
c: (_|_){
22+
// [incomplete] c: incomplete feed source value top (type _):
23+
// ./in.cue:6:15
1724
}
1825
}
1926
-- out/compile --
2027
--- in.cue
2128
{
2229
cond: bool
2330
src: {}
31+
top: _
2432
a: [
2533
if 〈0;cond〉 {},
2634
]
2735
b: [
2836
for _, x in 〈0;src〉.foo {},
2937
]
38+
c: {
39+
for _, x in 〈1;top〉 {}
40+
}
3041
}

cue/testdata/scalars/embed.txtar

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
-- in.cue --
2+
import "strings"
3+
4+
a1: {
5+
2
6+
}
7+
a2: {
8+
v: {
9+
3
10+
#foo: a2.v + 1
11+
}
12+
w: v
13+
x: v.#foo
14+
}
15+
a3: a1 + a2.v
16+
17+
b3: {
18+
[1, 2]
19+
#foo: 1
20+
}
21+
b4: b3 + b3
22+
b5: b3[1]
23+
b6: b3[5]
24+
b7: b4[a1] // 1
25+
26+
s1: {
27+
"foo"
28+
#bar: "bar"
29+
}
30+
s2: [ s1, { s1.#bar, #baz: 4 } ]
31+
s3: strings.Join(s2, "--")
32+
33+
-- out/eval --
34+
Errors:
35+
b6: invalid list index 5 (out of bounds):
36+
./in.cue:22:8
37+
38+
Result:
39+
(_|_){
40+
// [eval]
41+
a1: (int){ 2 }
42+
a2: (struct){
43+
v: (int){
44+
3
45+
#foo: (int){ 4 }
46+
}
47+
w: (int){
48+
3
49+
#foo: (int){ 4 }
50+
}
51+
x: (int){ 4 }
52+
}
53+
a3: (int){ 5 }
54+
b3: (#list){
55+
#foo: (int){ 1 }
56+
0: (int){ 1 }
57+
1: (int){ 2 }
58+
}
59+
b4: (#list){
60+
0: (int){ 1 }
61+
1: (int){ 2 }
62+
2: (int){ 1 }
63+
3: (int){ 2 }
64+
}
65+
b5: (int){ 2 }
66+
b6: (_|_){
67+
// [eval] b6: invalid list index 5 (out of bounds):
68+
// ./in.cue:22:8
69+
}
70+
b7: (int){ 1 }
71+
s1: (string){
72+
"foo"
73+
#bar: (string){ "bar" }
74+
}
75+
s2: (#list){
76+
0: (string){
77+
"foo"
78+
#bar: (string){ "bar" }
79+
}
80+
1: (string){
81+
"bar"
82+
#baz: (int){ 4 }
83+
}
84+
}
85+
s3: (string){ "foo--bar" }
86+
}
87+
-- out/compile --
88+
--- in.cue
89+
{
90+
a1: {
91+
2
92+
}
93+
a2: {
94+
v: {
95+
3
96+
#foo: (〈2;a2〉.v + 1)
97+
}
98+
w: 〈0;v〉
99+
x: 〈0;v〉.#foo
100+
}
101+
a3: (〈0;a1〉 + 〈0;a2〉.v)
102+
b3: {
103+
[
104+
1,
105+
2,
106+
]
107+
#foo: 1
108+
}
109+
b4: (〈0;b3〉 + 〈0;b3〉)
110+
b5: 〈0;b3〉[1]
111+
b6: 〈0;b3〉[5]
112+
b7: 〈0;b4〉[〈0;a1〉]
113+
s1: {
114+
"foo"
115+
#bar: "bar"
116+
}
117+
s2: [
118+
〈0;s1〉,
119+
{
120+
〈1;s1〉.#bar
121+
#baz: 4
122+
},
123+
]
124+
s3: 〈import;strings〉.Join(〈0;s2〉, "--")
125+
}

internal/core/adt/composite.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,6 @@ const (
228228
// nodeContext to allow reusing the computations done so far.
229229
Partial
230230

231-
// FieldSetDefined indicates that the value and conjuncts of all fields have
232-
// been completed, but that the individual arcs are not yet evaluated.
233-
FieldSetDefined
234-
235231
// EvaluatingArcs indicates that the arcs of the Vertex are currently being
236232
// evaluated. If this is encountered it indicates a structural cycle.
237233
// Value does not have to be nil

internal/core/adt/context.go

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func (c *OpContext) Concrete(env *Environment, x Expr, msg interface{}) (result
387387

388388
v, complete := c.Evaluate(env, x)
389389

390-
v, ok := c.getDefault(v)
390+
v, ok := c.getDefault(v, true)
391391
if !ok {
392392
return v, false
393393
}
@@ -406,21 +406,28 @@ func (c *OpContext) Concrete(env *Environment, x Expr, msg interface{}) (result
406406
return v, true
407407
}
408408

409-
func (c *OpContext) getDefault(v Value) (result Value, ok bool) {
409+
func (c *OpContext) getDefault(v Value, scalar bool) (result Value, ok bool) {
410410
var d *Disjunction
411411
switch x := v.(type) {
412412
default:
413413
return v, true
414414

415415
case *Vertex:
416+
// TODO: return vertex if not disjunction.
416417
switch t := x.Value.(type) {
417418
case *Disjunction:
418419
d = t
419420

420421
case *StructMarker, *ListMarker:
421422
return v, true
422423

424+
case *Vertex:
425+
return c.getDefault(t, scalar)
426+
423427
default:
428+
if !scalar {
429+
return v, true
430+
}
424431
return t, true
425432
}
426433

@@ -433,7 +440,7 @@ func (c *OpContext) getDefault(v Value) (result Value, ok bool) {
433440
"unresolved disjunction %s (type %s)", c.Str(d), d.Kind())
434441
return nil, false
435442
}
436-
return c.getDefault(d.Values[0])
443+
return c.getDefault(d.Values[0], scalar)
437444
}
438445

439446
// Evaluate evaluates an expression within the given environment and indicates
@@ -473,12 +480,14 @@ func (c *OpContext) Evaluate(env *Environment, x Expr) (result Value, complete b
473480
func (c *OpContext) value(x Expr) (result Value) {
474481
v := c.evalState(x, Partial)
475482

476-
v, _ = c.getDefault(v)
483+
v, _ = c.getDefault(v, true)
477484
return v
478485
}
479486

480-
func (c *OpContext) eval(v Expr) (result Value) {
481-
return c.evalState(v, Partial)
487+
func (c *OpContext) eval(x Expr) (result Value) {
488+
v := c.evalState(x, Partial)
489+
return v
490+
482491
}
483492

484493
func (c *OpContext) evalState(v Expr, state VertexStatus) (result Value) {
@@ -626,36 +635,43 @@ func pos(x Node) token.Pos {
626635
return x.Source().Pos()
627636
}
628637

629-
func (c *OpContext) node(x Expr, state VertexStatus) *Vertex {
630-
v := c.evalState(x, state)
638+
func (c *OpContext) node(x Expr, scalar bool) *Vertex {
639+
v := c.evalState(x, EvaluatingArcs)
631640

632-
v, ok := c.getDefault(v)
641+
v, ok := c.getDefault(v, scalar)
633642
if !ok {
634643
// Error already generated by getDefault.
635644
return emptyNode
636645
}
637646

638647
node, ok := v.(*Vertex)
639-
if !ok {
640-
if isError(v) {
641-
if v == nil {
642-
c.addErrf(IncompleteError, pos(x), "incomplete value %s", c.Str(x))
643-
return emptyNode
644-
}
645-
}
648+
if ok {
649+
v = node.Value
650+
}
651+
switch nv := v.(type) {
652+
case nil:
653+
c.addErrf(IncompleteError, pos(x), "incomplete value %s", c.Str(x))
654+
return emptyNode
655+
656+
case *Bottom:
657+
c.AddBottom(nv)
658+
return emptyNode
659+
660+
case *StructMarker, *ListMarker:
661+
662+
default:
646663
if v.Kind()&StructKind != 0 {
647664
c.addErrf(IncompleteError, pos(x),
648665
"incomplete feed source value %s (type %s)",
649666
x.Source(), v.Kind())
650-
} else if b, ok := v.(*Bottom); ok {
651-
c.AddBottom(b)
652-
} else {
667+
return emptyNode
668+
669+
} else if !ok {
653670
c.addErrf(0, pos(x), // TODO(error): better message.
654671
"invalid operand %s (found %s, want list or struct)",
655672
x.Source(), v.Kind())
656-
673+
return emptyNode
657674
}
658-
return emptyNode
659675
}
660676
return node.Default()
661677
}

internal/core/adt/expr.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ func (x *SelectorExpr) Source() ast.Node {
585585
}
586586

587587
func (x *SelectorExpr) resolve(c *OpContext) *Vertex {
588-
n := c.node(x.X, FieldSetDefined)
588+
n := c.node(x.X, x.Sel.IsRegular())
589589
return c.lookup(n, x.Src.Sel.Pos(), x.Sel)
590590
}
591591

@@ -608,7 +608,7 @@ func (x *IndexExpr) Source() ast.Node {
608608

609609
func (x *IndexExpr) resolve(ctx *OpContext) *Vertex {
610610
// TODO: support byte index.
611-
n := ctx.node(x.X, EvaluatingArcs)
611+
n := ctx.node(x.X, true)
612612
i := ctx.value(x.Index)
613613
f := ctx.Label(i)
614614
return ctx.lookup(n, x.Src.Index.Pos(), f)
@@ -1174,7 +1174,7 @@ func (x *ForClause) Source() ast.Node {
11741174
}
11751175

11761176
func (x *ForClause) yield(c *OpContext, f YieldFunc) {
1177-
n := c.node(x.Src, EvaluatingArcs)
1177+
n := c.node(x.Src, true)
11781178
for _, a := range n.Arcs {
11791179
c.Unify(c, a, Partial)
11801180

internal/core/eval/eval.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ func (e *Evaluator) Eval(v *adt.Vertex) errors.Error {
145145
// can be the only value in a valid configuration. This means that an error
146146
// may go undetected at this point, as long as it is caught later.
147147
//
148+
// TODO: return *adt.Vertex
148149
func (e *Evaluator) Evaluate(c *adt.OpContext, v *adt.Vertex) adt.Value {
149150
var resultValue adt.Value
150151

@@ -235,17 +236,14 @@ func (e *Evaluator) Evaluate(c *adt.OpContext, v *adt.Vertex) adt.Value {
235236
// TODO: Store if concrete and fully resolved.
236237
}
237238

238-
switch v.Value.(type) {
239-
case nil:
240-
// Error saved in result.
241-
return resultValue // incomplete
242-
243-
case *adt.ListMarker, *adt.StructMarker:
244-
return v
245-
246-
default:
247-
return v.Value
239+
// TODO: Use this and ensure that each use of Evaluate handles
240+
// struct numbers correctly. E.g. by using a function that
241+
// gets the concrete value.
242+
//
243+
if v.Value == nil {
244+
return resultValue
248245
}
246+
return v
249247
}
250248

251249
// Unify implements adt.Unifier.

internal/core/export/export.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,11 @@ func (e *exporter) addField(label adt.Feature, f *ast.Field, n ast.Node) {
385385
frame.fields[label] = entry
386386
}
387387

388+
func (e *exporter) addEmbed(x ast.Expr) {
389+
frame := e.top()
390+
frame.scope.Elts = append(frame.scope.Elts, x)
391+
}
392+
388393
func (e *exporter) pushFrame(conjuncts []adt.Conjunct) (s *ast.StructLit, saved []frame) {
389394
saved = e.stack
390395
s = &ast.StructLit{}

0 commit comments

Comments
 (0)