cue: prepare to hoist builtins, step 2

Changed code to allow it to be extracted from the
cue package.

Add the following functionality (for internal usage only):
- Value.Decimal
- bottomer: allow access to Bottom method of custom error types
- MakeValue create Value from internal types

Change-Id: I26076ef2f75b5f39f8f65ecf8814557457db8daf
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6882
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/builtin.go b/cue/builtin.go
index e149554..2eb37d9 100644
--- a/cue/builtin.go
+++ b/cue/builtin.go
@@ -35,7 +35,6 @@
 	"cuelang.org/go/internal/core/adt"
 	"cuelang.org/go/internal/core/compile"
 	"cuelang.org/go/internal/core/convert"
-	"cuelang.org/go/internal/core/runtime"
 )
 
 // A Builtin is a builtin function or constant.
@@ -122,13 +121,10 @@
 		Name:    b.Name,
 	}
 	x.Func = func(ctx *adt.OpContext, args []adt.Value) (ret adt.Expr) {
-		runtime := ctx.Impl().(*runtime.Runtime)
-		index := runtime.Data.(*index)
-
 		// call, _ := ctx.Source().(*ast.CallExpr)
 		c := &CallCtxt{
 			// src:  call,
-			ctx:     index.newContext(),
+			ctx:     ctx,
 			args:    args,
 			builtin: b,
 		}
@@ -143,8 +139,8 @@
 		switch v := c.Ret.(type) {
 		case adt.Value:
 			return v
-		case *valueError:
-			return v.err
+		case bottomer:
+			return v.Bottom()
 		}
 		if c.Err != nil {
 			return nil
@@ -180,11 +176,11 @@
 	return src.Pos()
 }
 
-func (x *Builtin) name(ctx *context) string {
+func (x *Builtin) name(ctx *adt.OpContext) string {
 	if x.Pkg == 0 {
 		return x.Name
 	}
-	return fmt.Sprintf("%s.%s", ctx.LabelStr(x.Pkg), x.Name)
+	return fmt.Sprintf("%s.%s", x.Pkg.StringValue(ctx), x.Name)
 }
 
 func (x *Builtin) isValidator() bool {
@@ -193,24 +189,25 @@
 
 func processErr(call *CallCtxt, errVal interface{}, ret adt.Expr) adt.Expr {
 	ctx := call.ctx
-	src := call.src
 	switch err := errVal.(type) {
 	case nil:
 	case *callError:
 		ret = err.b
 	case *json.MarshalerError:
-		if err, ok := err.Err.(*marshalError); ok && err.b != nil {
-			ret = err.b
+		if err, ok := err.Err.(bottomer); ok {
+			if b := err.Bottom(); b != nil {
+				ret = b
+			}
 		}
-	case *marshalError:
-		ret = wrapCallErr(call, err.b)
-	case *valueError:
-		ret = wrapCallErr(call, err.err)
+	case bottomer:
+		ret = wrapCallErr(call, err.Bottom())
 	case errors.Error:
 		ret = wrapCallErr(call, &adt.Bottom{Err: err})
 	case error:
 		if call.Err == internal.ErrIncomplete {
-			ret = ctx.mkErr(src, codeIncomplete, "incomplete value")
+			err := ctx.NewErrf("incomplete value")
+			err.Code = adt.IncompleteError
+			ret = err
 		} else {
 			// TODO: store the underlying error explicitly
 			ret = wrapCallErr(call, &adt.Bottom{Err: errors.Promote(err, "")})
@@ -278,7 +275,7 @@
 // CallCtxt is passed to builtin implementations that need to use a cue.Value. This is an internal type. It's interface may change.
 type CallCtxt struct {
 	src     adt.Expr // *adt.CallExpr
-	ctx     *context
+	ctx     *adt.OpContext
 	builtin *Builtin
 	Err     interface{}
 	Ret     interface{}
@@ -287,7 +284,7 @@
 }
 
 func (c *CallCtxt) Pos() token.Pos {
-	return c.ctx.opCtx.Pos()
+	return c.ctx.Pos()
 }
 
 func (c *CallCtxt) Name() string {
@@ -351,6 +348,11 @@
 	return c.Err == nil
 }
 
+type bottomer interface {
+	error
+	Bottom() *adt.Bottom
+}
+
 type callError struct {
 	b *adt.Bottom
 }
@@ -360,27 +362,22 @@
 }
 
 func (c *CallCtxt) errf(src adt.Node, underlying error, format string, args ...interface{}) {
-	a := make([]interface{}, 0, 2+len(args))
-	if err, ok := underlying.(*valueError); ok {
-		a = append(a, err.err)
+	var errs errors.Error
+	if err, ok := underlying.(bottomer); ok {
+		errs = err.Bottom().Err
 	}
-	a = append(a, format)
-	a = append(a, args...)
-	err := c.ctx.mkErr(src, a...)
-	c.Err = &callError{err}
+	errs = errors.Wrapf(errs, c.ctx.Pos(), format, args...)
+	c.Err = &callError{&adt.Bottom{Err: errs}}
 }
 
 func (c *CallCtxt) errcf(src adt.Node, code adt.ErrorCode, format string, args ...interface{}) {
-	a := make([]interface{}, 0, 2+len(args))
-	a = append(a, code)
-	a = append(a, format)
-	a = append(a, args...)
-	err := c.ctx.mkErr(src, a...)
+	err := c.ctx.NewErrf(format, args...)
+	err.Code = code
 	c.Err = &callError{err}
 }
 
 func (c *CallCtxt) Value(i int) Value {
-	v := newValueRoot(c.ctx, c.args[i])
+	v := MakeValue(c.ctx, c.args[i])
 	// TODO: remove default
 	// v, _ = v.Default()
 	if !v.IsConcrete() {
@@ -390,7 +387,7 @@
 }
 
 func (c *CallCtxt) Struct(i int) *Struct {
-	v := newValueRoot(c.ctx, c.args[i])
+	v := MakeValue(c.ctx, c.args[i])
 	s, err := v.Struct()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "struct", err)
@@ -400,7 +397,7 @@
 }
 
 func (c *CallCtxt) invalidArgType(arg adt.Expr, i int, typ string, err error) {
-	if ve, ok := err.(*valueError); ok && ve.err.IsIncomplete() {
+	if ve, ok := err.(bottomer); ok && ve.Bottom().IsIncomplete() {
 		c.Err = ve
 		return
 	}
@@ -410,16 +407,16 @@
 	if !ok {
 		c.errf(c.src, nil,
 			"cannot use incomplete value %s as %s in argument %d to %s: %v",
-			c.ctx.str(arg), typ, i, c.Name(), err)
+			c.ctx.Str(arg), typ, i, c.Name(), err)
 	}
 	if err != nil {
 		c.errf(c.src, err,
 			"cannot use %s (type %s) as %s in argument %d to %s: %v",
-			c.ctx.str(arg), v.Kind(), typ, i, c.Name(), err)
+			c.ctx.Str(arg), v.Kind(), typ, i, c.Name(), err)
 	} else {
 		c.errf(c.src, err,
 			"cannot use %s (type %s) as %s in argument %d to %s",
-			c.ctx.str(arg), v.Kind(), typ, i, c.Name())
+			c.ctx.Str(arg), v.Kind(), typ, i, c.Name())
 	}
 }
 
@@ -432,7 +429,7 @@
 
 func (c *CallCtxt) intValue(i, bits int, typ string) int64 {
 	arg := c.args[i]
-	x := newValueRoot(c.ctx, arg)
+	x := MakeValue(c.ctx, arg)
 	n, err := x.Int(nil)
 	if err != nil {
 		c.invalidArgType(arg, i, typ, err)
@@ -454,7 +451,7 @@
 func (c *CallCtxt) Uint64(i int) uint64 { return uint64(c.uintValue(i, 64, "uint64")) }
 
 func (c *CallCtxt) uintValue(i, bits int, typ string) uint64 {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	n, err := x.Int(nil)
 	if err != nil || n.Sign() < 0 {
 		c.invalidArgType(c.args[i], i, typ, err)
@@ -469,16 +466,16 @@
 }
 
 func (c *CallCtxt) Decimal(i int) *apd.Decimal {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	if _, err := x.MantExp(nil); err != nil {
 		c.invalidArgType(c.args[i], i, "Decimal", err)
 		return nil
 	}
-	return &c.args[i].(*numLit).X
+	return &c.args[i].(*adt.Num).X
 }
 
 func (c *CallCtxt) Float64(i int) float64 {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	res, err := x.Float64()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "float64", err)
@@ -488,7 +485,7 @@
 }
 
 func (c *CallCtxt) BigInt(i int) *big.Int {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	n, err := x.Int(nil)
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "int", err)
@@ -500,7 +497,7 @@
 var ten = big.NewInt(10)
 
 func (c *CallCtxt) BigFloat(i int) *big.Float {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	var mant big.Int
 	exp, err := x.MantExp(&mant)
 	if err != nil {
@@ -518,7 +515,7 @@
 }
 
 func (c *CallCtxt) String(i int) string {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	v, err := x.String()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "string", err)
@@ -528,7 +525,7 @@
 }
 
 func (c *CallCtxt) Bytes(i int) []byte {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	v, err := x.Bytes()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "bytes", err)
@@ -538,7 +535,7 @@
 }
 
 func (c *CallCtxt) Reader(i int) io.Reader {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	// TODO: optimize for string and bytes cases
 	r, err := x.Reader()
 	if err != nil {
@@ -549,7 +546,7 @@
 }
 
 func (c *CallCtxt) Bool(i int) bool {
-	x := newValueRoot(c.ctx, c.args[i])
+	x := MakeValue(c.ctx, c.args[i])
 	b, err := x.Bool()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "bool", err)
@@ -560,7 +557,7 @@
 
 func (c *CallCtxt) List(i int) (a []Value) {
 	arg := c.args[i]
-	x := newValueRoot(c.ctx, arg)
+	x := MakeValue(c.ctx, arg)
 	v, err := x.List()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "list", err)
@@ -574,38 +571,37 @@
 
 func (c *CallCtxt) Iter(i int) (a Iterator) {
 	arg := c.args[i]
-	x := newValueRoot(c.ctx, arg)
+	x := MakeValue(c.ctx, arg)
 	v, err := x.List()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "list", err)
-		return Iterator{ctx: c.ctx}
 	}
 	return v
 }
 
 func (c *CallCtxt) DecimalList(i int) (a []*apd.Decimal) {
 	arg := c.args[i]
-	x := newValueRoot(c.ctx, arg)
+	x := MakeValue(c.ctx, arg)
 	v, err := x.List()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "list", err)
 		return nil
 	}
 	for j := 0; v.Next(); j++ {
-		num, err := v.Value().getNum(numKind)
+		num, err := v.Value().Decimal()
 		if err != nil {
 			c.errf(c.src, err, "invalid list element %d in argument %d to %s: %v",
 				j, i, c.Name(), err)
 			break
 		}
-		a = append(a, &num.X)
+		a = append(a, num)
 	}
 	return a
 }
 
 func (c *CallCtxt) StringList(i int) (a []string) {
 	arg := c.args[i]
-	x := newValueRoot(c.ctx, arg)
+	x := MakeValue(c.ctx, arg)
 	v, err := x.List()
 	if err != nil {
 		c.invalidArgType(c.args[i], i, "list", err)
diff --git a/cue/errors.go b/cue/errors.go
index a4beeda..1785167 100644
--- a/cue/errors.go
+++ b/cue/errors.go
@@ -41,6 +41,8 @@
 	err *bottom
 }
 
+func (e *valueError) Bottom() *adt.Bottom { return e.err }
+
 func (e *valueError) Error() string {
 	return errors.String(e)
 }
diff --git a/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar b/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar
index 4b58c30..2dbf144 100644
--- a/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar
+++ b/cue/testdata/fulleval/048_dont_pass_incomplete_values_to_builtins.txtar
@@ -18,6 +18,7 @@
 (struct){
   input: (string){ string }
   foo: (_|_){
-    // [incomplete] non-concrete argument 0
+    // [incomplete] foo: non-concrete argument 0:
+    //     ./in.cue:4:8
   }
 }
diff --git a/cue/testdata/fulleval/051_detectIncompleteYAML.txtar b/cue/testdata/fulleval/051_detectIncompleteYAML.txtar
index 2cc08c1..67de9b0 100644
--- a/cue/testdata/fulleval/051_detectIncompleteYAML.txtar
+++ b/cue/testdata/fulleval/051_detectIncompleteYAML.txtar
@@ -77,10 +77,12 @@
         use: (string){ string }
       }
       baz: (_|_){
-        // [incomplete] non-concrete argument 0
+        // [incomplete] #Spec.data.baz: non-concrete argument 0:
+        //     ./in.cue:11:11
       }
       foobar: (_|_){
-        // [incomplete] incomplete value
+        // [incomplete] #Spec.data.foobar: incomplete value:
+        //     ./in.cue:12:11
       }
     }
   }
diff --git a/cue/testdata/fulleval/052_detectIncompleteJSON.txtar b/cue/testdata/fulleval/052_detectIncompleteJSON.txtar
index 84537c4..8718c37 100644
--- a/cue/testdata/fulleval/052_detectIncompleteJSON.txtar
+++ b/cue/testdata/fulleval/052_detectIncompleteJSON.txtar
@@ -69,7 +69,8 @@
         use: (string){ string }
       }
       baz: (_|_){
-        // [incomplete] non-concrete argument 0
+        // [incomplete] #Spec.data.baz: non-concrete argument 0:
+        //     ./in.cue:11:11
       }
       foobar: (_|_){
         // [incomplete] cannot convert incomplete value "string" to JSON
diff --git a/cue/testdata/fulleval/056_issue314.txtar b/cue/testdata/fulleval/056_issue314.txtar
index b480c77..227a0dd 100644
--- a/cue/testdata/fulleval/056_issue314.txtar
+++ b/cue/testdata/fulleval/056_issue314.txtar
@@ -96,7 +96,8 @@
   #U: (#struct){
     s: (string){ string }
     out: (_|_){
-      // [incomplete] incomplete value
+      // [incomplete] #U.out: incomplete value:
+      //     ./in.cue:26:7
     }
   }
 }
diff --git a/cue/types.go b/cue/types.go
index ce9b720..a8eea40 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -36,6 +36,7 @@
 	"cuelang.org/go/internal/core/convert"
 	"cuelang.org/go/internal/core/eval"
 	"cuelang.org/go/internal/core/export"
+	"cuelang.org/go/internal/core/runtime"
 	"cuelang.org/go/internal/core/subsume"
 	"cuelang.org/go/internal/core/validate"
 )
@@ -187,6 +188,7 @@
 	return fmt.Sprintf("cue: marshal error: %v", e.err)
 }
 
+func (e *marshalError) Bottom() *adt.Bottom          { return e.b }
 func (e *marshalError) Path() []string               { return e.err.Path() }
 func (e *marshalError) Msg() (string, []interface{}) { return e.err.Msg() }
 func (e *marshalError) Position() token.Pos          { return e.err.Position() }
@@ -330,6 +332,16 @@
 	return int(n.X.Exponent), nil
 }
 
+// Decimal is for internal use only. The Decimal type that is returned is
+// subject to change.
+func (v Value) Decimal() (d *internal.Decimal, err error) {
+	n, err := v.getNum(numKind)
+	if err != nil {
+		return nil, err
+	}
+	return &n.X, nil
+}
+
 // AppendInt appends the string representation of x in the given base to buf and
 // returns the extended buffer, or an error if the underlying number was not
 // an integer.
@@ -609,6 +621,17 @@
 	return makeValue(v.idx, n)
 }
 
+// MakeValue converts an adt.Value and given OpContext to a Value. The context
+// must be directly or indirectly obtained from the NewRuntime defined in this
+// package and it will panic if this is not the case. This is for internal use
+// only.
+func MakeValue(ctx *adt.OpContext, v adt.Value) Value {
+	runtime := ctx.Impl().(*runtime.Runtime)
+	index := runtime.Data.(*index)
+
+	return newValueRoot(index.newContext(), v)
+}
+
 func makeValue(idx *index, v *adt.Vertex) Value {
 	if v.Status() == 0 || v.Value == nil {
 		panic(fmt.Sprintf("not properly initialized (state: %v, value: %T)",