cue: refactor index

Prepare to hoist index type.

Moves Loaded to runtime.Runtime.

Change-Id: Id4fb32a487281e0fed35f88fb911d8db8470ad4a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9363
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/build.go b/cue/build.go
index b694906..2101032 100644
--- a/cue/build.go
+++ b/cue/build.go
@@ -79,7 +79,7 @@
 	if err := p.Complete(); err != nil {
 		return nil, err
 	}
-	inst := idx.loadInstance(p)
+	inst := loadInstance(idx, p)
 	inst.ImportPath = p.ImportPath
 	if inst.Err != nil {
 		return nil, inst.Err
@@ -165,7 +165,7 @@
 		_ = p.Complete()
 		errs = errors.Append(errs, p.Err)
 
-		i := index.loadInstance(p)
+		i := loadInstance(index, p)
 		errs = errors.Append(errs, i.Err)
 		loaded = append(loaded, i)
 	}
@@ -189,7 +189,6 @@
 // All instances belonging to the same package should share this index.
 type index struct {
 	*runtime.Runtime
-	loaded map[*build.Instance]*Instance
 }
 
 // NewRuntime creates a *runtime.Runtime with builtins preloaded.
@@ -204,7 +203,6 @@
 	r := runtime.New()
 	i := &index{
 		Runtime: r,
-		loaded:  map[*build.Instance]*Instance{},
 	}
 	r.Data = i
 	return i
@@ -214,7 +212,7 @@
 	return runtime.SharedRuntime.IsBuiltinPackage(s)
 }
 
-func (idx *index) loadInstance(p *build.Instance) *Instance {
+func loadInstance(idx *index, p *build.Instance) *Instance {
 	v, _ := idx.Runtime.Build(p)
-	return idx.getImportFromBuild(p, v)
+	return getImportFromBuild(idx, p, v)
 }
diff --git a/cue/build_test.go b/cue/build_test.go
index 55e4268..ccaeca8 100644
--- a/cue/build_test.go
+++ b/cue/build_test.go
@@ -200,7 +200,7 @@
 				got = err.Error()
 			} else {
 				cfg := &debug.Config{Compact: true}
-				got = debug.NodeString(insts[0].Runtime, insts[0].Value().v, cfg)
+				got = debug.NodeString(insts[0].index.Runtime, insts[0].Value().v, cfg)
 			}
 			if got != tc.emit {
 				t.Errorf("\n got: %s\nwant: %s", got, tc.emit)
diff --git a/cue/context.go b/cue/context.go
index 33d213d..48a7d09 100644
--- a/cue/context.go
+++ b/cue/context.go
@@ -27,7 +27,7 @@
 }
 
 // newContext returns a new evaluation context.
-func (idx *index) newContext() *context {
+func newContext(idx *index) *context {
 	c := &context{
 		index: idx,
 	}
diff --git a/cue/instance.go b/cue/instance.go
index e391129..63b1d68 100644
--- a/cue/instance.go
+++ b/cue/instance.go
@@ -28,7 +28,7 @@
 // An Instance defines a single configuration based on a collection of
 // underlying CUE files.
 type Instance struct {
-	*index
+	index *index
 
 	root *adt.Vertex
 
@@ -54,13 +54,20 @@
 	}
 	// fmt.Println(p.ImportPath, "XXX")
 	x.AddInst(p.ImportPath, p.root, p.inst)
-	x.loaded[p.inst] = p
+	x.SetBuildData(p.inst, p)
 	p.index = x
 	return p
 }
 
-func (x *index) getImportFromBuild(p *build.Instance, v *adt.Vertex) *Instance {
-	inst := x.loaded[p]
+func lookupInstance(x *index, p *build.Instance) *Instance {
+	if x, ok := x.BuildData(p); ok {
+		return x.(*Instance)
+	}
+	return nil
+}
+
+func getImportFromBuild(x *index, p *build.Instance, v *adt.Vertex) *Instance {
+	inst := lookupInstance(x, p)
 
 	if inst != nil {
 		return inst
@@ -79,27 +86,27 @@
 		inst.setListOrError(p.Err)
 	}
 
-	x.loaded[p] = inst
+	x.SetBuildData(p, inst)
 
 	return inst
 }
 
-func (x *index) getImportFromNode(v *adt.Vertex) *Instance {
+func getImportFromNode(x *index, v *adt.Vertex) *Instance {
 	p := x.GetInstanceFromNode(v)
 	if p == nil {
 		return nil
 	}
 
-	return x.getImportFromBuild(p, v)
+	return getImportFromBuild(x, p, v)
 }
 
-func (x *index) getImportFromPath(id string) *Instance {
+func getImportFromPath(x *index, id string) *Instance {
 	node, _ := x.LoadImport(id)
 	if node == nil {
 		return nil
 	}
 	b := x.GetInstanceFromNode(node)
-	inst := x.loaded[b]
+	inst := lookupInstance(x, b)
 	if inst == nil {
 		inst = &Instance{
 			ImportPath: b.ImportPath,
@@ -145,7 +152,7 @@
 	}
 
 	x.AddInst(p.ImportPath, v, p)
-	x.loaded[p] = inst
+	x.SetBuildData(p, inst)
 	inst.index = x
 	return inst
 }
@@ -170,7 +177,7 @@
 	internal.EvalExpr = func(value, expr interface{}) interface{} {
 		v := value.(Value)
 		e := expr.(ast.Expr)
-		ctx := v.idx.newContext()
+		ctx := newContext(v.idx)
 		return newValueRoot(ctx, evalExpr(ctx, v.vertex(ctx), e))
 	}
 }
@@ -262,7 +269,7 @@
 // defines in emit value, it will be that value. Otherwise it will be all
 // top-level values.
 func (inst *Instance) Value() Value {
-	ctx := inst.newContext()
+	ctx := newContext(inst.index)
 	inst.root.Finalize(ctx.opCtx)
 	return newVertexRoot(ctx, inst.root)
 }
@@ -271,7 +278,7 @@
 //
 // Expressions may refer to builtin packages if they can be uniquely identified.
 func (inst *Instance) Eval(expr ast.Expr) Value {
-	ctx := inst.newContext()
+	ctx := newContext(inst.index)
 	v := inst.root
 	v.Finalize(ctx.opCtx)
 	result := evalExpr(ctx, v, expr)
@@ -285,7 +292,7 @@
 	v := &adt.Vertex{}
 
 	i := inst[0]
-	ctx := i.index.newContext().opCtx
+	ctx := newContext(i.index).opCtx
 
 	// TODO: interesting test: use actual unification and then on K8s corpus.
 
@@ -336,7 +343,7 @@
 }
 
 func (inst *Instance) value() Value {
-	return newVertexRoot(inst.newContext(), inst.root)
+	return newVertexRoot(newContext(inst.index), inst.root)
 }
 
 // Lookup reports the value at a path starting from the top level struct. The
diff --git a/cue/marshal.go b/cue/marshal.go
index 8d86525..00e5720 100644
--- a/cue/marshal.go
+++ b/cue/marshal.go
@@ -129,7 +129,7 @@
 // The stored instances are functionally the same, but preserving of file
 // information is only done on a best-effort basis.
 func (r *Runtime) Marshal(instances ...*Instance) (b []byte, err error) {
-	ctx := r.index().newContext()
+	ctx := newContext(r.index())
 
 	staged := []instanceData{}
 	done := map[string]int{}
@@ -192,7 +192,7 @@
 		p := len(staged) - 1
 
 		for _, imp := range imports {
-			i := ctx.getImportFromPath(imp)
+			i := getImportFromPath(ctx.index, imp)
 			if i == nil || !strings.Contains(imp, ".") {
 				continue // a builtin package.
 			}
diff --git a/cue/types.go b/cue/types.go
index 30efd1e..3df1a5d 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -632,7 +632,7 @@
 	runtime := ctx.Impl().(*runtime.Runtime)
 	index := runtime.Data.(*index)
 
-	return newValueRoot(index.newContext(), v)
+	return newValueRoot(newContext(index), v)
 }
 
 func makeValue(idx *index, v *adt.Vertex) Value {
@@ -663,7 +663,7 @@
 }
 
 func (v Value) ctx() *context {
-	return v.idx.newContext()
+	return newContext(v.idx)
 }
 
 func (v Value) makeChild(ctx *context, i uint32, a *adt.Vertex) Value {
@@ -876,7 +876,7 @@
 	if v.v == nil {
 		return json.Marshal(nil)
 	}
-	ctx := v.idx.newContext()
+	ctx := newContext(v.idx)
 	x := v.eval(ctx)
 
 	if _, ok := x.(adt.Resolver); ok {
@@ -1749,7 +1749,7 @@
 	addConjuncts(n, v.v)
 	addConjuncts(n, w.v)
 
-	ctx := v.idx.newContext().opCtx
+	ctx := newContext(v.idx).opCtx
 	n.Finalize(ctx)
 
 	n.Parent = v.v.Parent
@@ -1786,7 +1786,7 @@
 	n.AddConjunct(adt.MakeRootConjunct(nil, v.v))
 	n.AddConjunct(adt.MakeRootConjunct(nil, w.v))
 
-	ctx := v.idx.newContext().opCtx
+	ctx := newContext(v.idx).opCtx
 	n.Finalize(ctx)
 
 	n.Parent = v.v.Parent
@@ -1834,7 +1834,7 @@
 	if v.v == nil {
 		return nil
 	}
-	return v.idx.getImportFromNode(v.v)
+	return getImportFromNode(v.idx, v.v)
 }
 
 // Reference returns the instance and path referred to by this value such that
@@ -1882,7 +1882,7 @@
 
 	case *adt.ImportReference:
 		imp := x.ImportPath.StringValue(ctx)
-		inst = c.index.getImportFromPath(imp)
+		inst = getImportFromPath(c.index, imp)
 
 	case *adt.SelectorExpr:
 		inst, path = reference(c, env, x.X)
@@ -1902,7 +1902,7 @@
 
 func mkPath(ctx *context, a []string, v *adt.Vertex) (inst *Instance, path []string) {
 	if v.Parent == nil {
-		return ctx.index.getImportFromNode(v), a
+		return getImportFromNode(ctx.index, v), a
 	}
 	inst, path = mkPath(ctx, a, v.Parent)
 	path = append(path, v.Label.SelectorString(ctx.opCtx))
diff --git a/internal/core/runtime/runtime.go b/internal/core/runtime/runtime.go
index 448dc30..cc67bce 100644
--- a/internal/core/runtime/runtime.go
+++ b/internal/core/runtime/runtime.go
@@ -14,18 +14,41 @@
 
 package runtime
 
+import (
+	"cuelang.org/go/cue/build"
+)
+
 // A Runtime maintains data structures for indexing and resuse for evaluation.
 type Runtime struct {
 	index *index
 
 	// Data holds the legacy index strut. It is for transitional purposes only.
 	Data interface{}
+
+	loaded map[*build.Instance]interface{}
+}
+
+func (r *Runtime) SetBuildData(b *build.Instance, x interface{}) {
+	r.loaded[b] = x
+}
+
+func (r *Runtime) BuildData(b *build.Instance) (x interface{}, ok bool) {
+	x, ok = r.loaded[b]
+	return x, ok
 }
 
 // New creates a new Runtime. The builtins registered with RegisterBuiltin
 // are available for
 func New() *Runtime {
-	return &Runtime{
-		index: sharedIndex,
+	r := &Runtime{}
+	r.Init()
+	return r
+}
+
+func (r *Runtime) Init() {
+	if r.index != nil {
+		return
 	}
+	r.index = sharedIndex
+	r.loaded = map[*build.Instance]interface{}{}
 }