internal/core/dep: support dynamic dependencies
This mix of evaluation interleaved with conjunction
tracking seems most desirable for workflow
dependencies.
Change-Id: I61c8fbbc71139550613b0bf5c65e4351053eaebc
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7641
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/internal/core/dep/dep.go b/internal/core/dep/dep.go
index 71ab3e4..ae9cda7 100644
--- a/internal/core/dep/dep.go
+++ b/internal/core/dep/dep.go
@@ -79,6 +79,19 @@
return visit(c, n, f, true, true)
}
+// VisitFields calls f for n and all its descendent arcs that have a conjunct
+// that originates from a conjunct in n. Only the conjuncts of n that ended up
+// as a conjunct in an actual field are visited and they are visited for each
+// field in which the occurs.
+func VisitFields(c *adt.OpContext, n *adt.Vertex, f VisitFunc) error {
+ m := marked{}
+
+ m.markExpr(n)
+
+ dynamic(c, n, f, m, true)
+ return nil
+}
+
var empty *adt.Vertex
func init() {
diff --git a/internal/core/dep/dep_test.go b/internal/core/dep/dep_test.go
index 3ec0c00..d4d6313 100644
--- a/internal/core/dep/dep_test.go
+++ b/internal/core/dep/dep_test.go
@@ -62,6 +62,10 @@
name: "all",
root: "a",
fn: dep.VisitAll,
+ }, {
+ name: "dynamic",
+ root: "a",
+ fn: dep.VisitFields,
}}
for _, tc := range testCases {
@@ -88,7 +92,6 @@
// DO NOT REMOVE: for Testing purposes.
func TestX(t *testing.T) {
- // a and a.b are the fields for which to determine the references.
in := `
`
@@ -117,7 +120,7 @@
deps := []string{}
- _ = dep.VisitAll(ctxt, n, func(d dep.Dependency) error {
+ _ = dep.VisitFields(ctxt, n, func(d dep.Dependency) error {
str := cue.MakeValue(ctxt, d.Node).Path().String()
if i := d.Import(); i != nil {
path := i.ImportPath.StringValue(ctxt)
diff --git a/internal/core/dep/mixed.go b/internal/core/dep/mixed.go
new file mode 100644
index 0000000..601bbfd
--- /dev/null
+++ b/internal/core/dep/mixed.go
@@ -0,0 +1,146 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package dep
+
+import (
+ "fmt"
+
+ "cuelang.org/go/internal/core/adt"
+)
+
+// dynamic visits conjuncts of structs that are defined by the root for all
+// of its fields, recursively.
+//
+// The current algorithm visits all known conjuncts and descends into the
+// evaluated Vertex. A more correct and more performant algorithm would be to
+// descend into the conjuncts and evaluate the necessary values, like fields
+// and comprehension sources.
+func dynamic(c *adt.OpContext, n *adt.Vertex, f VisitFunc, m marked, top bool) {
+ found := false
+ for _, c := range n.Conjuncts {
+ if m[c.Expr()] {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ return
+ }
+
+ if visit(c, n, f, false, top) != nil {
+ return
+ }
+
+ for _, a := range n.Arcs {
+ dynamic(c, a, f, m, false)
+ }
+}
+
+type marked map[adt.Expr]bool
+
+// TODO: factor out the below logic as either a low-level dependency analyzer or
+// some walk functionality.
+
+// markExpr visits all nodes in an expression to mark dependencies.
+func (m marked) markExpr(x adt.Expr) {
+ m[x] = true
+
+ switch x := x.(type) {
+ default:
+
+ case nil:
+ case *adt.Vertex:
+ for _, c := range x.Conjuncts {
+ m.markExpr(c.Expr())
+ }
+
+ case *adt.BinaryExpr:
+ if x.Op == adt.AndOp {
+ m.markExpr(x.X)
+ m.markExpr(x.Y)
+ }
+
+ case *adt.StructLit:
+ for _, e := range x.Decls {
+ switch x := e.(type) {
+ case *adt.Field:
+ m.markExpr(x.Value)
+
+ case *adt.OptionalField:
+ m.markExpr(x.Value)
+
+ case *adt.BulkOptionalField:
+ m.markExpr(x.Value)
+
+ case *adt.DynamicField:
+ m.markExpr(x.Value)
+
+ case *adt.Ellipsis:
+ m.markExpr(x.Value)
+
+ case adt.Expr:
+ m.markExpr(x)
+
+ case adt.Yielder:
+ m.markYielder(x)
+
+ default:
+ panic(fmt.Sprintf("unreachable %T", x))
+ }
+ }
+
+ case *adt.ListLit:
+ for _, e := range x.Elems {
+ switch x := e.(type) {
+ case adt.Expr:
+ m.markExpr(x)
+
+ case adt.Yielder:
+ m.markYielder(x)
+
+ case *adt.Ellipsis:
+ m.markExpr(x.Value)
+
+ default:
+ panic(fmt.Sprintf("unreachable %T", x))
+ }
+ }
+
+ case *adt.DisjunctionExpr:
+ for _, d := range x.Values {
+ m.markExpr(d.Val)
+ }
+
+ case adt.Yielder:
+ m.markYielder(x)
+ }
+}
+
+func (m marked) markYielder(y adt.Yielder) {
+ switch x := y.(type) {
+ case *adt.ForClause:
+ m.markYielder(x.Dst)
+
+ case *adt.IfClause:
+ m.markYielder(x.Dst)
+
+ case *adt.LetClause:
+ m.markYielder(x.Dst)
+
+ case *adt.ValueClause:
+ m.markExpr(x.StructLit)
+ }
+}
diff --git a/internal/core/dep/testdata/alias.txtar b/internal/core/dep/testdata/alias.txtar
index 51f3efa..be5f21d 100644
--- a/internal/core/dep/testdata/alias.txtar
+++ b/internal/core/dep/testdata/alias.txtar
@@ -12,3 +12,6 @@
-- out/dependencies/all --
c
d
+-- out/dependencies/dynamic --
+c
+d
diff --git a/internal/core/dep/testdata/call.txtar b/internal/core/dep/testdata/call.txtar
index 5336504..4082fbe 100644
--- a/internal/core/dep/testdata/call.txtar
+++ b/internal/core/dep/testdata/call.txtar
@@ -11,3 +11,6 @@
-- out/dependencies/all --
"encoding/json".Marshal
str
+-- out/dependencies/dynamic --
+"encoding/json".Marshal
+str
diff --git a/internal/core/dep/testdata/composed.txtar b/internal/core/dep/testdata/composed.txtar
new file mode 100644
index 0000000..78cfeaf
--- /dev/null
+++ b/internal/core/dep/testdata/composed.txtar
@@ -0,0 +1,14 @@
+-- in.cue --
+t1: {$id: "foo"} & {
+ ref: t1.stdout
+ cmd: ["sh", "-c", "echo hello"]
+ stdout: string
+}
+a: b: {$id: "foo"} & {
+ text: t1.stdout
+}
+-- out/dependencies/field --
+-- out/dependencies/all --
+t1.stdout
+-- out/dependencies/dynamic --
+t1.stdout
diff --git a/internal/core/dep/testdata/expr.txtar b/internal/core/dep/testdata/expr.txtar
index 88c48ea..1816962 100644
--- a/internal/core/dep/testdata/expr.txtar
+++ b/internal/core/dep/testdata/expr.txtar
@@ -20,3 +20,9 @@
e
d
e
+-- out/dependencies/dynamic --
+d
+d
+c
+c[0]
+e
diff --git a/internal/core/dep/testdata/field.txtar b/internal/core/dep/testdata/field.txtar
index e993bc3..42af863 100644
--- a/internal/core/dep/testdata/field.txtar
+++ b/internal/core/dep/testdata/field.txtar
@@ -21,3 +21,8 @@
c
c
c
+-- out/dependencies/dynamic --
+pattern
+name
+c
+c
diff --git a/internal/core/dep/testdata/incomplete.txtar b/internal/core/dep/testdata/incomplete.txtar
index fdf83ad..f22b60b 100644
--- a/internal/core/dep/testdata/incomplete.txtar
+++ b/internal/core/dep/testdata/incomplete.txtar
@@ -18,3 +18,10 @@
e
c.d
c.d
+-- out/dependencies/dynamic --
+c.d
+c
+c
+e
+c.d
+c.d
diff --git a/internal/core/dep/testdata/list.txtar b/internal/core/dep/testdata/list.txtar
index 217194a..3ae09ce 100644
--- a/internal/core/dep/testdata/list.txtar
+++ b/internal/core/dep/testdata/list.txtar
@@ -9,3 +9,6 @@
-- out/dependencies/all --
d
e
+-- out/dependencies/dynamic --
+d
+e
diff --git a/internal/core/dep/testdata/listcomprehension.txtar b/internal/core/dep/testdata/listcomprehension.txtar
index d2a458f..b4908a4 100644
--- a/internal/core/dep/testdata/listcomprehension.txtar
+++ b/internal/core/dep/testdata/listcomprehension.txtar
@@ -9,3 +9,10 @@
-- out/dependencies/all --
c
d
+-- out/dependencies/dynamic --
+c
+d
+c[0].a
+d
+c[1].a
+d
diff --git a/internal/core/dep/testdata/self.txtar b/internal/core/dep/testdata/self.txtar
index 70bf1f5..c8c8214 100644
--- a/internal/core/dep/testdata/self.txtar
+++ b/internal/core/dep/testdata/self.txtar
@@ -16,3 +16,8 @@
-- out/dependencies/field --
-- out/dependencies/all --
m
+-- out/dependencies/dynamic --
+m
+a.b.y
+a.b.x.f
+a.b
diff --git a/internal/core/dep/testdata/structcomprehension.txtar b/internal/core/dep/testdata/structcomprehension.txtar
index 62ffd8f..594866c 100644
--- a/internal/core/dep/testdata/structcomprehension.txtar
+++ b/internal/core/dep/testdata/structcomprehension.txtar
@@ -17,3 +17,10 @@
c
e
d
+-- out/dependencies/dynamic --
+c
+e
+c[0]
+d
+c[1]
+d