internal/core/compile: allow resolution in custom scope
Change-Id: Idec88d30f6770c090097ba0319aa12a8370ddd8f
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6623
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/internal/core/compile/compile.go b/internal/core/compile/compile.go
index ad1ff56..0b85136 100644
--- a/internal/core/compile/compile.go
+++ b/internal/core/compile/compile.go
@@ -35,6 +35,13 @@
//
// TODO
Scope *adt.Vertex
+
+ // Imports allows unresolved identifiers to resolve to imports.
+ //
+ // Under normal circumstances, identifiers bind to import specifications,
+ // which get resolved to an ImportReference. Use this option to automaically
+ // resolve identifiers to imports.
+ Imports func(x *ast.Ident) (pkgPath string)
}
// Files compiles the given files as a single instance. It disregards
@@ -195,7 +202,6 @@
c.stack = c.stack[:k]
}
-// entry points // USE CONFIG
func (c *compiler) compileFiles(a []*ast.File) *adt.Vertex { // Or value?
c.fileScope = map[adt.Feature]bool{}
@@ -211,6 +217,21 @@
}
}
+ // TODO: Assume that the other context is unified with the newly compiled
+ // files. This is not the same behavior as the old functionality, but we
+ // wanted to nix this anyway. For instance by allowing pkg_tool to be
+ // treated differently.
+ if v := c.Config.Scope; v != nil {
+ for _, arc := range v.Arcs {
+ if _, ok := c.fileScope[arc.Label]; !ok {
+ c.fileScope[arc.Label] = true
+ }
+ }
+
+ c.pushScope(nil, 0, v.Source()) // File scope
+ defer c.popScope()
+ }
+
// TODO: set doc.
res := &adt.Vertex{}
@@ -228,9 +249,35 @@
}
func (c *compiler) compileExpr(x ast.Expr) adt.Conjunct {
+ c.fileScope = map[adt.Feature]bool{}
+
+ if v := c.Config.Scope; v != nil {
+ for _, arc := range v.Arcs {
+ c.fileScope[arc.Label] = true
+ }
+
+ c.pushScope(nil, 0, v.Source()) // File scope
+ defer c.popScope()
+ }
+
expr := c.expr(x)
env := &adt.Environment{}
+ top := env
+
+ for p := c.Config.Scope; p != nil; p = p.Parent {
+ top.Vertex = p
+ top.Up = &adt.Environment{}
+ top = top.Up
+
+ // TODO: do something like this to allow multi-layered scopes.
+ // e := &adt.Environment{Vertex: p}
+ // if env != nil {
+ // env.Up = e
+ // }
+ // env = e
+ }
+
return adt.MakeConjunct(env, expr)
}
@@ -266,6 +313,16 @@
}
}
+ if c.Config.Imports != nil {
+ if pkgPath := c.Config.Imports(n); pkgPath != "" {
+ return &adt.ImportReference{
+ Src: n,
+ ImportPath: adt.MakeStringLabel(c.index, pkgPath),
+ Label: c.label(n),
+ }
+ }
+ }
+
if p := predeclared(n); p != nil {
return p
}