cue: add Runtime type
Used for easier programmatic creation of Instances.
Change-Id: Ic1e6ea43529399f2e3a1c2bdb637362d0b953229
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2124
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index e852780..9cd6b4b 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -36,6 +36,8 @@
}
}
+var runtime = &cue.Runtime{}
+
var cwd = "////"
// printHeader is a hacky and unprincipled way to sanatize the package path.
diff --git a/cmd/cue/cmd/import.go b/cmd/cue/cmd/import.go
index 4023d1e..72235ae 100644
--- a/cmd/cue/cmd/import.go
+++ b/cmd/cue/cmd/import.go
@@ -428,7 +428,7 @@
switch {
case *node != "":
- inst, err := cue.FromExpr(expr)
+ inst, err := runtime.FromExpr(expr)
if err != nil {
return err
}
diff --git a/cue/build.go b/cue/build.go
index 2e7402b..59845be 100644
--- a/cue/build.go
+++ b/cue/build.go
@@ -19,10 +19,63 @@
"strconv"
"cuelang.org/go/cue/ast"
- build "cuelang.org/go/cue/build"
+ "cuelang.org/go/cue/build"
"cuelang.org/go/cue/token"
)
+// A Runtime is used for creating CUE interpretations.
+//
+// Any operation that involves two Values or Instances should originate from
+// the same Runtime.
+type Runtime struct {
+ Context *build.Context
+ idx *index
+ ctxt *build.Context
+}
+
+func dummyLoad(string) *build.Instance { return nil }
+
+func (r *Runtime) index() *index {
+ if r.idx == nil {
+ r.idx = newIndex()
+ }
+ return r.idx
+}
+
+func (r *Runtime) complete(p *build.Instance) (*Instance, error) {
+ idx := r.index()
+ if err := p.Complete(); err != nil {
+ return nil, err
+ }
+ inst := idx.loadInstance(p)
+ if inst.Err != nil {
+ return nil, inst.Err
+ }
+ return inst, nil
+}
+
+// Parse parses a CUE source value into a CUE Instance. The source code may
+// be provided as a string, byte slice, or io.Reader. The name is used as the
+// file name in position information. The source may import builtin packages.
+//
+func (r *Runtime) Parse(name string, source interface{}) (*Instance, error) {
+ ctx := r.Context
+ if ctx == nil {
+ ctx = build.NewContext()
+ }
+ p := ctx.NewInstance(name, dummyLoad)
+ if err := p.AddFile(name, source); err != nil {
+ return nil, err
+ }
+ return r.complete(p)
+}
+
+// Build creates an Instance from the given build.Instance. A returned Instance
+// may be incomplete, in which case its Err field is set.
+func (r *Runtime) Build(instance *build.Instance) (*Instance, error) {
+ return r.complete(instance)
+}
+
// Build creates one Instance for each build.Instance. A returned Instance
// may be incomplete, in which case its Err field is set.
//
@@ -33,7 +86,8 @@
if len(instances) == 0 {
panic("cue: list of instances must not be empty")
}
- index := newIndex()
+ var r Runtime
+ index := r.index()
loaded := []*Instance{}
@@ -48,8 +102,8 @@
// FromExpr creates an instance from an expression.
// Any references must be resolved beforehand.
-func FromExpr(expr ast.Expr) (*Instance, error) {
- i := newIndex().NewInstance(nil)
+func (r *Runtime) FromExpr(expr ast.Expr) (*Instance, error) {
+ i := r.index().NewInstance(nil)
err := i.insertFile(&ast.File{
Decls: []ast.Decl{&ast.EmitDecl{Expr: expr}},
})
diff --git a/cue/build_test.go b/cue/build_test.go
index f06adad..e02f80d 100644
--- a/cue/build_test.go
+++ b/cue/build_test.go
@@ -41,7 +41,8 @@
}}
for _, tc := range testCases {
t.Run("", func(t *testing.T) {
- inst, err := FromExpr(tc.expr)
+ r := &Runtime{}
+ inst, err := r.FromExpr(tc.expr)
if err != nil {
t.Fatal(err)
}
diff --git a/cue/examples_test.go b/cue/examples_test.go
new file mode 100644
index 0000000..f9922e9
--- /dev/null
+++ b/cue/examples_test.go
@@ -0,0 +1,45 @@
+// Copyright 2019 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 cue_test
+
+import (
+ "fmt"
+
+ "cuelang.org/go/cue"
+)
+
+func ExampleRuntime_Parse() {
+ const config = `
+ msg: "Hello \(place)!"
+ place: "world"
+ `
+
+ var r cue.Runtime
+
+ instance, err := r.Parse("test", config)
+ if err != nil {
+ // handle error
+ }
+
+ str, err := instance.Lookup("msg").String()
+ if err != nil {
+ // handle error
+ }
+
+ fmt.Println(str)
+
+ // Output:
+ // Hello world!
+}
diff --git a/pkg/tool/file/file_test.go b/pkg/tool/file/file_test.go
index 097a5cb..474432f 100644
--- a/pkg/tool/file/file_test.go
+++ b/pkg/tool/file/file_test.go
@@ -33,7 +33,8 @@
if err != nil {
t.Fatal(err)
}
- i, err := cue.FromExpr(x)
+ var r cue.Runtime
+ i, err := r.FromExpr(x)
if err != nil {
t.Fatal(err)
}