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)",