blob: 636fe522246951183323398b2f6deadc7cfa3a54 [file] [log] [blame]
// Copyright 2018 The 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
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"math/big"
"strings"
"github.com/cockroachdb/apd/v2"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal"
"cuelang.org/go/internal/core/adt"
"cuelang.org/go/internal/core/compile"
"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"
"cuelang.org/go/internal/types"
)
// Kind determines the underlying type of a Value.
type Kind = adt.Kind
const BottomKind Kind = 0
const (
// NullKind indicates a null value.
NullKind Kind = adt.NullKind
// BoolKind indicates a boolean value.
BoolKind = adt.BoolKind
// IntKind represents an integral number.
IntKind = adt.IntKind
// FloatKind represents a decimal float point number that cannot be
// converted to an integer. The underlying number may still be integral,
// but resulting from an operation that enforces the float type.
FloatKind = adt.FloatKind
// StringKind indicates any kind of string.
StringKind = adt.StringKind
// BytesKind is a blob of data.
BytesKind = adt.BytesKind
// StructKind is a kev-value map.
StructKind = adt.StructKind
// ListKind indicates a list of values.
ListKind = adt.ListKind
// _numberKind is used as a implementation detail inside
// Kind.String to indicate NumberKind.
// NumberKind represents any kind of number.
NumberKind = IntKind | FloatKind
TopKind = adt.TopKind
)
// An structValue represents a JSON object.
//
// TODO: remove
type structValue struct {
ctx *adt.OpContext
v Value
obj *adt.Vertex
features []adt.Feature
}
type hiddenStructValue = structValue
// Len reports the number of fields in this struct.
func (o *hiddenStructValue) Len() int {
if o.obj == nil {
return 0
}
return len(o.features)
}
// At reports the key and value of the ith field, i < o.Len().
func (o *hiddenStructValue) At(i int) (key string, v Value) {
f := o.features[i]
return o.v.idx.LabelStr(f), newChildValue(o, i)
}
func (o *hiddenStructValue) at(i int) (v *adt.Vertex, isOpt bool) {
f := o.features[i]
arc := o.obj.Lookup(f)
if arc == nil {
arc = &adt.Vertex{
Parent: o.v.v,
Label: f,
}
o.obj.MatchAndInsert(o.ctx, arc)
arc.Finalize(o.ctx)
isOpt = true
}
return arc, isOpt
}
// Lookup reports the field for the given key. The returned Value is invalid
// if it does not exist.
func (o *hiddenStructValue) Lookup(key string) Value {
f := o.v.idx.StrLabel(key)
i := 0
len := o.Len()
for ; i < len; i++ {
if o.features[i] == f {
break
}
}
if i == len {
// TODO: better message.
x := mkErr(o.v.idx, o.obj, adt.NotExistError, "value %q not found", key)
return newErrValue(o.v, x)
}
return newChildValue(o, i)
}
// MarshalJSON returns a valid JSON encoding or reports an error if any of the
// fields is invalid.
func (o *structValue) marshalJSON() (b []byte, err errors.Error) {
b = append(b, '{')
n := o.Len()
for i := 0; i < n; i++ {
k, v := o.At(i)
s, err := json.Marshal(k)
if err != nil {
return nil, unwrapJSONError(err)
}
b = append(b, s...)
b = append(b, ':')
bb, err := json.Marshal(v)
if err != nil {
return nil, unwrapJSONError(err)
}
b = append(b, bb...)
if i < n-1 {
b = append(b, ',')
}
}
b = append(b, '}')
return b, nil
}
var _ errors.Error = &marshalError{}
type marshalError struct {
err errors.Error
b *adt.Bottom
}
func toMarshalErr(v Value, b *adt.Bottom) error {
return &marshalError{v.toErr(b), b}
}
func marshalErrf(v Value, src adt.Node, code adt.ErrorCode, msg string, args ...interface{}) error {
arguments := append([]interface{}{code, msg}, args...)
b := mkErr(v.idx, src, arguments...)
return toMarshalErr(v, b)
}
func (e *marshalError) Error() string {
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() }
func (e *marshalError) InputPositions() []token.Pos {
return e.err.InputPositions()
}
func unwrapJSONError(err error) errors.Error {
switch x := err.(type) {
case *json.MarshalerError:
return unwrapJSONError(x.Err)
case *marshalError:
return x
case errors.Error:
return &marshalError{x, nil}
default:
return &marshalError{errors.Wrapf(err, token.NoPos, "json error"), nil}
}
}
// An Iterator iterates over values.
//
type Iterator struct {
val Value
idx *runtime.Runtime
ctx *adt.OpContext
arcs []field
p int
cur Value
f adt.Feature
isOpt bool
}
type hiddenIterator = Iterator
type field struct {
arc *adt.Vertex
isOptional bool
}
// Next advances the iterator to the next value and reports whether there was
// any. It must be called before the first call to Value or Key.
func (i *Iterator) Next() bool {
if i.p >= len(i.arcs) {
i.cur = Value{}
return false
}
f := i.arcs[i.p]
f.arc.Finalize(i.ctx)
p := linkParent(i.val.parent_, i.val.v, f.arc)
i.cur = makeValue(i.val.idx, f.arc, p)
i.f = f.arc.Label
i.isOpt = f.isOptional
i.p++
return true
}
// Value returns the current value in the list. It will panic if Next advanced
// past the last entry.
func (i *Iterator) Value() Value {
return i.cur
}
// Selector reports the field label of this iteration.
func (i *Iterator) Selector() Selector {
return featureToSel(i.f, i.idx)
}
// Label reports the label of the value if i iterates over struct fields and ""
// otherwise.
//
//
// Slated to be deprecated: use i.Selector().String(). Note that this will give
// more accurate string representations.
func (i *hiddenIterator) Label() string {
if i.f == 0 {
return ""
}
return i.idx.LabelStr(i.f)
}
// IsHidden reports if a field is hidden from the data model.
//
// Deprecated: use i.Selector().PkgPath() != ""
func (i *hiddenIterator) IsHidden() bool {
return i.f.IsHidden()
}
// IsOptional reports if a field is optional.
func (i *Iterator) IsOptional() bool {
return i.isOpt
}
// IsDefinition reports if a field is a definition.
//
// Deprecated: use i.Selector().IsDefinition()
func (i *hiddenIterator) IsDefinition() bool {
return i.f.IsDef()
}
// marshalJSON iterates over the list and generates JSON output. HasNext
// will return false after this operation.
func marshalList(l *Iterator) (b []byte, err errors.Error) {
b = append(b, '[')
if l.Next() {
for i := 0; ; i++ {
x, err := json.Marshal(l.Value())
if err != nil {
return nil, unwrapJSONError(err)
}
b = append(b, x...)
if !l.Next() {
break
}
b = append(b, ',')
}
}
b = append(b, ']')
return b, nil
}
func (v Value) getNum(k adt.Kind) (*adt.Num, errors.Error) {
v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, k); err != nil {
return nil, v.toErr(err)
}
n, _ := v.eval(ctx).(*adt.Num)
return n, nil
}
// MantExp breaks x into its mantissa and exponent components and returns the
// exponent. If a non-nil mant argument is provided its value is set to the
// mantissa of x. The components satisfy x == mant × 10**exp. It returns an
// error if v is not a number.
//
// The components are not normalized. For instance, 2.00 is represented mant ==
// 200 and exp == -2. Calling MantExp with a nil argument is an efficient way to
// get the exponent of the receiver.
func (v Value) MantExp(mant *big.Int) (exp int, err error) {
n, err := v.getNum(adt.NumKind)
if err != nil {
return 0, err
}
if n.X.Form != 0 {
return 0, ErrInfinite
}
if mant != nil {
mant.Set(&n.X.Coeff)
if n.X.Negative {
mant.Neg(mant)
}
}
return int(n.X.Exponent), nil
}
// Decimal is for internal use only. The Decimal type that is returned is
// subject to change.
func (v hiddenValue) Decimal() (d *internal.Decimal, err error) {
n, err := v.getNum(adt.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.
func (v Value) AppendInt(buf []byte, base int) ([]byte, error) {
i, err := v.Int(nil)
if err != nil {
return nil, err
}
return i.Append(buf, base), nil
}
// AppendFloat appends to buf the string form of the floating-point number x.
// It returns an error if v is not a number.
func (v Value) AppendFloat(buf []byte, fmt byte, prec int) ([]byte, error) {
n, err := v.getNum(adt.NumKind)
if err != nil {
return nil, err
}
ctx := apd.BaseContext
nd := int(apd.NumDigits(&n.X.Coeff)) + int(n.X.Exponent)
if n.X.Form == apd.Infinite {
if n.X.Negative {
buf = append(buf, '-')
}
return append(buf, string('∞')...), nil
}
if fmt == 'f' && nd > 0 {
ctx.Precision = uint32(nd + prec)
} else {
ctx.Precision = uint32(prec)
}
var d apd.Decimal
ctx.Round(&d, &n.X)
return d.Append(buf, fmt), nil
}
var (
// ErrBelow indicates that a value was rounded down in a conversion.
ErrBelow = errors.New("value was rounded down")
// ErrAbove indicates that a value was rounded up in a conversion.
ErrAbove = errors.New("value was rounded up")
// ErrInfinite indicates that a value is infinite.
ErrInfinite = errors.New("infinite")
)
// Int converts the underlying integral number to an big.Int. It reports an
// error if the underlying value is not an integer type. If a non-nil *Int
// argument z is provided, Int stores the result in z instead of allocating a
// new Int.
func (v Value) Int(z *big.Int) (*big.Int, error) {
n, err := v.getNum(adt.IntKind)
if err != nil {
return nil, err
}
if z == nil {
z = &big.Int{}
}
if n.X.Exponent != 0 {
panic("cue: exponent should always be nil for integer types")
}
z.Set(&n.X.Coeff)
if n.X.Negative {
z.Neg(z)
}
return z, nil
}
// Int64 converts the underlying integral number to int64. It reports an
// error if the underlying value is not an integer type or cannot be represented
// as an int64. The result is (math.MinInt64, ErrAbove) for x < math.MinInt64,
// and (math.MaxInt64, ErrBelow) for x > math.MaxInt64.
func (v Value) Int64() (int64, error) {
n, err := v.getNum(adt.IntKind)
if err != nil {
return 0, err
}
if !n.X.Coeff.IsInt64() {
if n.X.Negative {
return math.MinInt64, ErrAbove
}
return math.MaxInt64, ErrBelow
}
i := n.X.Coeff.Int64()
if n.X.Negative {
i = -i
}
return i, nil
}
// Uint64 converts the underlying integral number to uint64. It reports an
// error if the underlying value is not an integer type or cannot be represented
// as a uint64. The result is (0, ErrAbove) for x < 0, and
// (math.MaxUint64, ErrBelow) for x > math.MaxUint64.
func (v Value) Uint64() (uint64, error) {
n, err := v.getNum(adt.IntKind)
if err != nil {
return 0, err
}
if n.X.Negative {
return 0, ErrAbove
}
if !n.X.Coeff.IsUint64() {
return math.MaxUint64, ErrBelow
}
i := n.X.Coeff.Uint64()
return i, nil
}
// trimZeros trims 0's for better JSON respresentations.
func trimZeros(s string) string {
n1 := len(s)
s2 := strings.TrimRight(s, "0")
n2 := len(s2)
if p := strings.IndexByte(s2, '.'); p != -1 {
if p == n2-1 {
return s[:len(s2)+1]
}
return s2
}
if n1-n2 <= 4 {
return s
}
return fmt.Sprint(s2, "e+", n1-n2)
}
var (
smallestPosFloat64 *apd.Decimal
smallestNegFloat64 *apd.Decimal
maxPosFloat64 *apd.Decimal
maxNegFloat64 *apd.Decimal
)
func init() {
const (
// math.SmallestNonzeroFloat64: 1 / 2**(1023 - 1 + 52)
smallest = "4.940656458412465441765687928682213723651e-324"
// math.MaxFloat64: 2**1023 * (2**53 - 1) / 2**52
max = "1.797693134862315708145274237317043567981e+308"
)
ctx := apd.BaseContext
ctx.Precision = 40
var err error
smallestPosFloat64, _, err = ctx.NewFromString(smallest)
if err != nil {
panic(err)
}
smallestNegFloat64, _, err = ctx.NewFromString("-" + smallest)
if err != nil {
panic(err)
}
maxPosFloat64, _, err = ctx.NewFromString(max)
if err != nil {
panic(err)
}
maxNegFloat64, _, err = ctx.NewFromString("-" + max)
if err != nil {
panic(err)
}
}
// Float64 returns the float64 value nearest to x. It reports an error if v is
// not a number. If x is too small to be represented by a float64 (|x| <
// math.SmallestNonzeroFloat64), the result is (0, ErrBelow) or (-0, ErrAbove),
// respectively, depending on the sign of x. If x is too large to be represented
// by a float64 (|x| > math.MaxFloat64), the result is (+Inf, ErrAbove) or
// (-Inf, ErrBelow), depending on the sign of x.
func (v Value) Float64() (float64, error) {
n, err := v.getNum(adt.NumKind)
if err != nil {
return 0, err
}
if n.X.Negative {
if n.X.Cmp(smallestNegFloat64) == 1 {
return -0, ErrAbove
}
if n.X.Cmp(maxNegFloat64) == -1 {
return math.Inf(-1), ErrBelow
}
} else {
if n.X.Cmp(smallestPosFloat64) == -1 {
return 0, ErrBelow
}
if n.X.Cmp(maxPosFloat64) == 1 {
return math.Inf(1), ErrAbove
}
}
f, _ := n.X.Float64()
return f, nil
}
// Value holds any value, which may be a Boolean, Error, List, Null, Number,
// Struct, or String.
type Value struct {
idx *runtime.Runtime
v *adt.Vertex
// Parent keeps track of the parent if the value corresponding to v.Parent
// differs, recursively.
parent_ *parent
}
// parent is a distinct type from Value to ensure more type safety: Value
// is typically used by value, so taking a pointer to it has a high risk
// or globbering the contents.
type parent struct {
v *adt.Vertex
p *parent
}
func (v Value) parent() Value {
switch {
case v.v == nil:
return Value{}
case v.parent_ != nil:
return Value{v.idx, v.parent_.v, v.parent_.p}
default:
return Value{v.idx, v.v.Parent, nil}
}
}
type valueScope Value
func (v valueScope) Vertex() *adt.Vertex { return v.v }
func (v valueScope) Parent() compile.Scope {
p := Value(v).parent()
if p.v == nil {
return nil
}
return valueScope(p)
}
type hiddenValue = Value
// Core is for internal use only.
func (v hiddenValue) Core(x *types.Value) {
x.V = v.v
x.R = v.idx
}
func newErrValue(v Value, b *adt.Bottom) Value {
node := &adt.Vertex{BaseValue: b}
if v.v != nil {
node.Label = v.v.Label
node.Parent = v.v.Parent
}
node.UpdateStatus(adt.Finalized)
node.AddConjunct(adt.MakeRootConjunct(nil, b))
return makeChildValue(v.parent(), node)
}
func newVertexRoot(idx *runtime.Runtime, ctx *adt.OpContext, x *adt.Vertex) Value {
if ctx != nil {
// This is indicative of an zero Value. In some cases this is called
// with an error value.
x.Finalize(ctx)
} else {
x.UpdateStatus(adt.Finalized)
}
return makeValue(idx, x, nil)
}
func newValueRoot(idx *runtime.Runtime, ctx *adt.OpContext, x adt.Expr) Value {
if n, ok := x.(*adt.Vertex); ok {
return newVertexRoot(idx, ctx, n)
}
node := &adt.Vertex{}
node.AddConjunct(adt.MakeRootConjunct(nil, x))
return newVertexRoot(idx, ctx, node)
}
func newChildValue(o *structValue, i int) Value {
arc, _ := o.at(i)
return makeValue(o.v.idx, arc, linkParent(o.v.parent_, o.v.v, arc))
}
// Dereference reports the value v refers to if v is a reference or v itself
// otherwise.
func Dereference(v Value) Value {
n := v.v
if n == nil || len(n.Conjuncts) != 1 {
return v
}
c := n.Conjuncts[0]
r, _ := c.Expr().(adt.Resolver)
if r == nil {
return v
}
ctx := v.ctx()
n, b := ctx.Resolve(c.Env, r)
if b != nil {
return newErrValue(v, b)
}
n.Finalize(ctx)
// NOTE: due to structure sharing, the path of the referred node may end
// up different from the one explicitly pointed to. The value will be the
// same, but the scope may differ.
// TODO(structureshare): see if we can construct the original path. This
// only has to be done if structures are being shared.
return makeValue(v.idx, n, nil)
}
func makeValue(idx *runtime.Runtime, v *adt.Vertex, p *parent) Value {
if v.Status() == 0 || v.BaseValue == nil {
panic(fmt.Sprintf("not properly initialized (state: %v, value: %T)",
v.Status(), v.BaseValue))
}
return Value{idx, v, p}
}
// makeChildValue makes a new value, of which p is the parent, and links the
// parent pointer to p if necessary.
func makeChildValue(p Value, arc *adt.Vertex) Value {
return makeValue(p.idx, arc, linkParent(p.parent_, p.v, arc))
}
// linkParent creates the parent struct for an arc, if necessary.
//
// The parent struct is necessary if the parent struct also has a parent struct,
// or if arc is (structurally) shared and does not have node as a parent.
func linkParent(p *parent, node, arc *adt.Vertex) *parent {
if p == nil && node == arc.Parent {
return nil
}
return &parent{node, p}
}
func remakeValue(base Value, env *adt.Environment, v adt.Expr) Value {
// TODO: right now this is necessary because disjunctions do not have
// populated conjuncts.
if v, ok := v.(*adt.Vertex); ok && v.Status() >= adt.Partial {
return Value{base.idx, v, nil}
}
n := &adt.Vertex{Label: base.v.Label}
n.AddConjunct(adt.MakeRootConjunct(env, v))
n = manifest(base.ctx(), n)
n.Parent = base.v.Parent
return makeChildValue(base.parent(), n)
}
func remakeFinal(base Value, env *adt.Environment, v adt.Value) Value {
n := &adt.Vertex{Parent: base.v.Parent, Label: base.v.Label, BaseValue: v}
n.UpdateStatus(adt.Finalized)
return makeChildValue(base.parent(), n)
}
func (v Value) ctx() *adt.OpContext {
return newContext(v.idx)
}
// Eval resolves the references of a value and returns the result.
// This method is not necessary to obtain concrete values.
func (v Value) Eval() Value {
if v.v == nil {
return v
}
x := v.v
// x = eval.FinalizeValue(v.idx.Runtime, v.v)
// x.Finalize(v.ctx())
x = x.ToDataSingle()
return makeValue(v.idx, x, v.parent_)
// return remakeValue(v, nil, ctx.value(x))
}
// Default reports the default value and whether it existed. It returns the
// normal value if there is no default.
func (v Value) Default() (Value, bool) {
if v.v == nil {
return v, false
}
d := v.v.Default()
if d == v.v {
return v, false
}
return makeValue(v.idx, d, v.parent_), true
// d, ok := v.v.Value.(*adt.Disjunction)
// if !ok {
// return v, false
// }
// var w *adt.Vertex
// switch d.NumDefaults {
// case 0:
// return v, false
// case 1:
// w = d.Values[0]
// default:
// x := *v.v
// x.Value = &adt.Disjunction{
// Src: d.Src,
// Values: d.Values[:d.NumDefaults],
// NumDefaults: 0,
// }
// w = &x
// }
// w.Conjuncts = nil
// for _, c := range v.v.Conjuncts {
// // TODO: preserve field information.
// expr, _ := stripNonDefaults(c.Expr())
// w.AddConjunct(adt.MakeConjunct(c.Env, expr))
// }
// return makeValue(v.idx, w), true
// if !stripped {
// return v, false
// }
// n := *v.v
// n.Conjuncts = conjuncts
// return Value{v.idx, &n}, true
// isDefault := false
// for _, c := range v.v.Conjuncts {
// if hasDisjunction(c.Expr()) {
// isDefault = true
// break
// }
// }
// if !isDefault {
// return v, false
// }
// TODO: record expanded disjunctions in output.
// - Rename Disjunction to DisjunctionExpr
// - Introduce Disjuncts with Values.
// - In Expr introduce Star
// - Don't pick default by default?
// Evaluate the value.
// x := eval.FinalizeValue(v.idx.Runtime, v.v)
// if b, _ := x.Value.(*adt.Bottom); b != nil { // && b.IsIncomplete() {
// return v, false
// }
// // Finalize and return here.
// return Value{v.idx, x}, isDefault
}
// TODO: this should go: record preexpanded disjunctions in Vertex.
func hasDisjunction(expr adt.Expr) bool {
switch x := expr.(type) {
case *adt.DisjunctionExpr:
return true
case *adt.Conjunction:
for _, v := range x.Values {
if hasDisjunction(v) {
return true
}
}
case *adt.BinaryExpr:
switch x.Op {
case adt.OrOp:
return true
case adt.AndOp:
return hasDisjunction(x.X) || hasDisjunction(x.Y)
}
}
return false
}
// TODO: this should go: record preexpanded disjunctions in Vertex.
func stripNonDefaults(expr adt.Expr) (r adt.Expr, stripped bool) {
switch x := expr.(type) {
case *adt.DisjunctionExpr:
if !x.HasDefaults {
return x, false
}
d := *x
d.Values = []adt.Disjunct{}
for _, v := range x.Values {
if v.Default {
d.Values = append(d.Values, v)
}
}
if len(d.Values) == 1 {
return d.Values[0].Val, true
}
return &d, true
case *adt.BinaryExpr:
if x.Op != adt.AndOp {
return x, false
}
a, sa := stripNonDefaults(x.X)
b, sb := stripNonDefaults(x.Y)
if sa || sb {
bin := *x
bin.X = a
bin.Y = b
return &bin, true
}
return x, false
default:
return x, false
}
}
// Label reports he label used to obtain this value from the enclosing struct.
//
// TODO: get rid of this somehow. Probably by including a FieldInfo struct
// or the like.
func (v hiddenValue) Label() (string, bool) {
if v.v == nil || v.v.Label == 0 {
return "", false
}
return v.idx.LabelStr(v.v.Label), true
}
// Kind returns the kind of value. It returns BottomKind for atomic values that
// are not concrete. For instance, it will return BottomKind for the bounds
// >=0.
func (v Value) Kind() Kind {
if v.v == nil {
return BottomKind
}
c := v.v.BaseValue
if !v.v.IsConcrete() {
return BottomKind
}
if v.IncompleteKind() == adt.ListKind && !v.v.IsClosedList() {
return BottomKind
}
return c.Kind()
}
// IncompleteKind returns a mask of all kinds that this value may be.
func (v Value) IncompleteKind() Kind {
if v.v == nil {
return BottomKind
}
return v.v.Kind()
}
// MarshalJSON marshalls this value into valid JSON.
func (v Value) MarshalJSON() (b []byte, err error) {
b, err = v.marshalJSON()
if err != nil {
return nil, unwrapJSONError(err)
}
return b, nil
}
func (v Value) marshalJSON() (b []byte, err error) {
v, _ = v.Default()
if v.v == nil {
return json.Marshal(nil)
}
ctx := newContext(v.idx)
x := v.eval(ctx)
if _, ok := x.(adt.Resolver); ok {
return nil, marshalErrf(v, x, adt.IncompleteError, "value %q contains unresolved references", str(ctx, x))
}
if !adt.IsConcrete(x) {
return nil, marshalErrf(v, x, adt.IncompleteError, "cannot convert incomplete value %q to JSON", str(ctx, x))
}
// TODO: implement marshalles in value.
switch k := x.Kind(); k {
case adt.NullKind:
return json.Marshal(nil)
case adt.BoolKind:
return json.Marshal(x.(*adt.Bool).B)
case adt.IntKind, adt.FloatKind, adt.NumKind:
b, err := x.(*adt.Num).X.MarshalText()
b = bytes.TrimLeft(b, "+")
return b, err
case adt.StringKind:
return json.Marshal(x.(*adt.String).Str)
case adt.BytesKind:
return json.Marshal(x.(*adt.Bytes).B)
case adt.ListKind:
i, _ := v.List()
return marshalList(&i)
case adt.StructKind:
obj, err := v.structValData(ctx)
if err != nil {
return nil, toMarshalErr(v, err)
}
return obj.marshalJSON()
case adt.BottomKind:
return nil, toMarshalErr(v, x.(*adt.Bottom))
default:
return nil, marshalErrf(v, x, 0, "cannot convert value %q of type %T to JSON", str(ctx, x), x)
}
}
// Syntax converts the possibly partially evaluated value into syntax. This
// can use used to print the value with package format.
func (v Value) Syntax(opts ...Option) ast.Node {
// TODO: the default should ideally be simplified representation that
// exactly represents the value. The latter can currently only be
// ensured with Raw().
if v.v == nil {
return nil
}
var o options = getOptions(opts)
// var inst *Instance
p := export.Profile{
Simplify: !o.raw,
TakeDefaults: o.final,
ShowOptional: !o.omitOptional && !o.concrete,
ShowDefinitions: !o.omitDefinitions && !o.concrete,
ShowHidden: !o.omitHidden && !o.concrete,
ShowAttributes: !o.omitAttrs,
ShowDocs: o.docs,
}
pkgID := v.instance().ID()
bad := func(name string, err error) ast.Node {
const format = `"%s: internal error
Error: %s
Profile:
%#v
Value:
%v
You could file a bug with the above information at:
https://github.com/cuelang/cue/issues/new?assignees=&labels=NeedsInvestigation&template=bug_report.md&title=.
`
cg := &ast.CommentGroup{Doc: true}
msg := fmt.Sprintf(format, name, err, p, v)
for _, line := range strings.Split(msg, "\n") {
cg.List = append(cg.List, &ast.Comment{Text: "// " + line})
}
x := &ast.BadExpr{}
ast.AddComment(x, cg)
return x
}
// var expr ast.Expr
var err error
var f *ast.File
if o.concrete || o.final {
// inst = v.instance()
var expr ast.Expr
expr, err = p.Value(v.idx, pkgID, v.v)
if err != nil {
return bad(`"cuelang.org/go/internal/core/export".Value`, err)
}
// This introduces gratuitous unshadowing!
f, err = astutil.ToFile(expr)
if err != nil {
return bad(`"cuelang.org/go/ast/astutil".ToFile`, err)
}
// return expr
} else {
f, err = p.Def(v.idx, pkgID, v.v)
if err != nil {
return bad(`"cuelang.org/go/internal/core/export".Def`, err)
}
}
outer:
for _, d := range f.Decls {
switch d.(type) {
case *ast.Package, *ast.ImportDecl:
return f
case *ast.CommentGroup, *ast.Attribute:
default:
break outer
}
}
if len(f.Decls) == 1 {
if e, ok := f.Decls[0].(*ast.EmbedDecl); ok {
return e.Expr
}
}
return &ast.StructLit{
Elts: f.Decls,
}
}
// Doc returns all documentation comments associated with the field from which
// the current value originates.
func (v Value) Doc() []*ast.CommentGroup {
if v.v == nil {
return nil
}
return export.ExtractDoc(v.v)
}
// Split returns a list of values from which v originated such that
// the unification of all these values equals v and for all returned values.
// It will also split unchecked unifications (embeddings), so unifying the
// split values may fail if actually unified.
// Source returns a non-nil value.
//
// Deprecated: use Expr.
func (v hiddenValue) Split() []Value {
if v.v == nil {
return nil
}
a := []Value{}
for _, x := range v.v.Conjuncts {
a = append(a, remakeValue(v, x.Env, x.Expr()))
}
return a
}
// Source returns the original node for this value. The return value may not
// be a syntax.Expr. For instance, a struct kind may be represented by a
// struct literal, a field comprehension, or a file. It returns nil for
// computed nodes. Use Split to get all source values that apply to a field.
func (v Value) Source() ast.Node {
if v.v == nil {
return nil
}
if len(v.v.Conjuncts) == 1 {
return v.v.Conjuncts[0].Source()
}
return v.v.Value().Source()
}
// Err returns the error represented by v or nil v is not an error.
func (v Value) Err() error {
if err := v.checkKind(v.ctx(), adt.BottomKind); err != nil {
return v.toErr(err)
}
return nil
}
// Pos returns position information.
func (v Value) Pos() token.Pos {
if v.v == nil || v.Source() == nil {
return token.NoPos
}
pos := v.Source().Pos()
return pos
}
// TODO: IsFinal: this value can never be changed.
// IsClosed reports whether a list of struct is closed. It reports false when
// when the value is not a list or struct.
//
// Deprecated: use Allows and Kind/IncompleteKind.
func (v hiddenValue) IsClosed() bool {
if v.v == nil {
return false
}
return v.v.IsClosedList() || v.v.IsClosedStruct()
}
// Allows reports whether a field with the given selector could be added to v.
//
// Allows does not take into account validators like list.MaxItems(4). This may
// change in the future.
func (v Value) Allows(sel Selector) bool {
c := v.ctx()
f := sel.sel.feature(c)
return v.v.Accept(c, f)
}
// IsConcrete reports whether the current value is a concrete scalar value
// (not relying on default values), a terminal error, a list, or a struct.
// It does not verify that values of lists or structs are concrete themselves.
// To check whether there is a concrete default, use v.Default().IsConcrete().
func (v Value) IsConcrete() bool {
if v.v == nil {
return false // any is neither concrete, not a list or struct.
}
if b, ok := v.v.BaseValue.(*adt.Bottom); ok {
return !b.IsIncomplete()
}
if !adt.IsConcrete(v.v) {
return false
}
if v.IncompleteKind() == adt.ListKind && !v.v.IsClosedList() {
return false
}
return true
}
// // Deprecated: IsIncomplete
// //
// // It indicates that the value cannot be fully evaluated due to
// // insufficient information.
// func (v Value) IsIncomplete() bool {
// panic("deprecated")
// }
// Exists reports whether this value existed in the configuration.
func (v Value) Exists() bool {
if v.v == nil {
return false
}
if err, ok := v.v.BaseValue.(*adt.Bottom); ok {
return err.Code != adt.NotExistError
}
return true
}
func (v Value) checkKind(ctx *adt.OpContext, want adt.Kind) *adt.Bottom {
if v.v == nil {
return errNotExists
}
// TODO: use checkKind
x := v.eval(ctx)
if b, ok := x.(*adt.Bottom); ok {
return b
}
k := x.Kind()
if want != adt.BottomKind {
if k&want == adt.BottomKind {
return mkErr(v.idx, x, "cannot use value %v (type %s) as %s",
ctx.Str(x), k, want)
}
if !adt.IsConcrete(x) {
return mkErr(v.idx, x, adt.IncompleteError, "non-concrete value %v", k)
}
}
return nil
}
func makeInt(v Value, x int64) Value {
n := &adt.Num{K: adt.IntKind}
n.X.SetInt64(int64(x))
return remakeFinal(v, nil, n)
}
// Len returns the number of items of the underlying value.
// For lists it reports the capacity of the list. For structs it indicates the
// number of fields, for bytes the number of bytes.
func (v Value) Len() Value {
if v.v != nil {
switch x := v.eval(v.ctx()).(type) {
case *adt.Vertex:
if x.IsList() {
n := &adt.Num{K: adt.IntKind}
n.X.SetInt64(int64(len(x.Elems())))
if x.IsClosedList() {
return remakeFinal(v, nil, n)
}
// Note: this HAS to be a Conjunction value and cannot be
// an adt.BinaryExpr, as the expressions would be considered
// to be self-contained and unresolvable when evaluated
// (can never become concrete).
c := &adt.Conjunction{Values: []adt.Value{
&adt.BasicType{K: adt.IntKind},
&adt.BoundValue{Op: adt.GreaterEqualOp, Value: n},
}}
return remakeFinal(v, nil, c)
}
case *adt.Bytes:
return makeInt(v, int64(len(x.B)))
case *adt.String:
return makeInt(v, int64(len([]rune(x.Str))))
}
}
const msg = "len not supported for type %v"
return remakeValue(v, nil, mkErr(v.idx, v.v, msg, v.Kind()))
}
// Elem returns the value of undefined element types of lists and structs.
//
// Deprecated: use LookupPath in combination with "AnyString" or "AnyIndex".
func (v hiddenValue) Elem() (Value, bool) {
sel := AnyString
if v.v.IsList() {
sel = AnyIndex
}
x := v.LookupPath(MakePath(sel))
return x, x.Exists()
}
// List creates an iterator over the values of a list or reports an error if
// v is not a list.
func (v Value) List() (Iterator, error) {
v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, adt.ListKind); err != nil {
return Iterator{idx: v.idx, ctx: ctx}, v.toErr(err)
}
arcs := []field{}
for _, a := range v.v.Elems() {
if a.Label.IsInt() {
arcs = append(arcs, field{arc: a})
}
}
return Iterator{idx: v.idx, ctx: ctx, val: v, arcs: arcs}, nil
}
// Null reports an error if v is not null.
func (v Value) Null() error {
v, _ = v.Default()
if err := v.checkKind(v.ctx(), adt.NullKind); err != nil {
return v.toErr(err)
}
return nil
}
// // IsNull reports whether v is null.
// func (v Value) IsNull() bool {
// return v.Null() == nil
// }
// Bool returns the bool value of v or false and an error if v is not a boolean.
func (v Value) Bool() (bool, error) {
v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, adt.BoolKind); err != nil {
return false, v.toErr(err)
}
return v.eval(ctx).(*adt.Bool).B, nil
}
// String returns the string value if v is a string or an error otherwise.
func (v Value) String() (string, error) {
v, _ = v.Default()
ctx := v.ctx()
if err := v.checkKind(ctx, adt.StringKind); err != nil {
return "", v.toErr(err)
}
return v.eval(ctx).(*adt.String).Str, nil
}
// Bytes returns a byte slice if v represents a list of bytes or an error
// otherwise.
func (v Value) Bytes() ([]byte, error) {
v, _ = v.Default()
ctx := v.ctx()
switch x := v.eval(ctx).(type) {
case *adt.Bytes:
return append([]byte(nil), x.B...), nil
case *adt.String:
return []byte(x.Str), nil
}
return nil, v.toErr(v.checkKind(ctx, adt.BytesKind|adt.StringKind))
}
// Reader returns a new Reader if v is a string or bytes type and an error
// otherwise.
func (v hiddenValue) Reader() (io.Reader, error) {
v, _ = v.Default()
ctx := v.ctx()
switch x := v.eval(ctx).(type) {
case *adt.Bytes:
return bytes.NewReader(x.B), nil
case *adt.String:
return strings.NewReader(x.Str), nil
}
return nil, v.toErr(v.checkKind(ctx, adt.StringKind|adt.BytesKind))
}
// TODO: distinguish between optional, hidden, etc. Probably the best approach
// is to mark options in context and have a single function for creating
// a structVal.
// structVal returns an structVal or an error if v is not a struct.
func (v Value) structValData(ctx *adt.OpContext) (structValue, *adt.Bottom) {
return v.structValOpts(ctx, options{
omitHidden: true,
omitDefinitions: true,
omitOptional: true,
})
}
func (v Value) structValFull(ctx *adt.OpContext) (structValue, *adt.Bottom) {
return v.structValOpts(ctx, options{allowScalar: true})
}
// structVal returns an structVal or an error if v is not a struct.
func (v Value) structValOpts(ctx *adt.OpContext, o options) (s structValue, err *adt.Bottom) {
v, _ = v.Default()
obj := v.v
if !o.allowScalar {
obj, err = v.getStruct()
if err != nil {
return structValue{}, err
}
}
features := export.VertexFeatures(obj)
k := 0
for _, f := range features {
if f.IsDef() && (o.omitDefinitions || o.concrete) {
continue
}
if f.IsHidden() && o.omitHidden {
continue
}
if arc := obj.Lookup(f); arc == nil {
if o.omitOptional {
continue
}
// ensure it really exists.
v := adt.Vertex{
Parent: obj,
Label: f,
}
obj.MatchAndInsert(ctx, &v)
if len(v.Conjuncts) == 0 {
continue
}
}
features[k] = f
k++
}
features = features[:k]
return structValue{ctx, v, obj, features}, nil
}
// Struct returns the underlying struct of a value or an error if the value
// is not a struct.
func (v hiddenValue) Struct() (*Struct, error) {
// TODO: deprecate
ctx := v.ctx()
obj, err := v.structValOpts(ctx, options{})
if err != nil {
return nil, v.toErr(err)
}
return &Struct{obj}, nil
}
func (v Value) getStruct() (*adt.Vertex, *adt.Bottom) {
ctx := v.ctx()
if err := v.checkKind(ctx, adt.StructKind); err != nil {
if !err.ChildError {
return nil, err
}
}
return v.v, nil
}
// Struct represents a CUE struct value.
type Struct struct {
structValue
}
type hiddenStruct = Struct
// FieldInfo contains information about a struct field.
type FieldInfo struct {
Selector string
Name string // Deprecated: use Selector
Pos int
Value Value
IsDefinition bool
IsOptional bool
IsHidden bool
}
func (s *hiddenStruct) Len() int {
return s.structValue.Len()
}
// field reports information about the ith field, i < o.Len().
func (s *hiddenStruct) Field(i int) FieldInfo {
a, opt := s.at(i)
ctx := s.v.ctx()
v := makeChildValue(s.v, a)
name := s.v.idx.LabelStr(a.Label)
str := a.Label.SelectorString(ctx)
return FieldInfo{str, name, i, v, a.Label.IsDef(), opt, a.Label.IsHidden()}
}
// FieldByName looks up a field for the given name. If isIdent is true, it will
// look up a definition or hidden field (starting with `_` or `_#`). Otherwise
// it interprets name as an arbitrary string for a regular field.
func (s *hiddenStruct) FieldByName(name string, isIdent bool) (FieldInfo, error) {
f := s.v.idx.Label(name, isIdent)
for i, a := range s.features {
if a == f {
return s.Field(i), nil
}
}
return FieldInfo{}, errNotFound
}
// Fields creates an iterator over the Struct's fields.
func (s *hiddenStruct) Fields(opts ...Option) *Iterator {
iter, _ := s.v.Fields(opts...)
return iter
}
// Fields creates an iterator over v's fields if v is a struct or an error
// otherwise.
func (v Value) Fields(opts ...Option) (*Iterator, error) {
o := options{omitDefinitions: true, omitHidden: true, omitOptional: true}
o.updateOptions(opts)
ctx := v.ctx()
obj, err := v.structValOpts(ctx, o)
if err != nil {
return &Iterator{idx: v.idx, ctx: ctx}, v.toErr(err)
}
arcs := []field{}
for i := range obj.features {
arc, isOpt := obj.at(i)
arcs = append(arcs, field{arc: arc, isOptional: isOpt})
}
return &Iterator{idx: v.idx, ctx: ctx, val: v, arcs: arcs}, nil
}
// Lookup reports the value at a path starting from v. The empty path returns v
// itself.
//
// The Exists() method can be used to verify if the returned value existed.
// Lookup cannot be used to look up hidden or optional fields or definitions.
//
// Deprecated: use LookupPath. At some point before v1.0.0, this method will
// be removed to be reused eventually for looking up a selector.
func (v hiddenValue) Lookup(path ...string) Value {
ctx := v.ctx()
for _, k := range path {
// TODO(eval) TODO(error): always search in full data and change error
// message if a field is found but is of the incorrect type.
obj, err := v.structValData(ctx)
if err != nil {
// TODO: return a Value at the same location and a new error?
return newErrValue(v, err)
}
v = obj.Lookup(k)
}
return v
}
// Path returns the path to this value from the root of an Instance.
//
// This is currently only defined for values that have a fixed path within
// a configuration, and thus not those that are derived from Elem, Template,
// or programmatically generated values such as those returned by Unify.
func (v Value) Path() Path {
if v.v == nil {
return Path{}
}
return Path{path: appendPath(nil, v)}
}
// Path computes the sequence of Features leading from the root to of the
// instance to this Vertex.
func appendPath(a []Selector, v Value) []Selector {
if p := v.parent(); p.v != nil {
a = appendPath(a, p)
}
if v.v.Label == 0 {
// A Label may be 0 for programmatically inserted nodes.
return a
}
f := v.v.Label
if index := f.Index(); index == adt.MaxIndex {
return append(a, Selector{anySelector(f)})
}
var sel selector
switch f.Typ() {
case adt.IntLabel:
sel = indexSelector(f)
case adt.DefinitionLabel:
sel = definitionSelector(f.SelectorString(v.idx))
case adt.HiddenDefinitionLabel, adt.HiddenLabel:
sel = scopedSelector{
name: f.IdentString(v.idx),
pkg: f.PkgID(v.idx),
}
case adt.StringLabel:
sel = stringSelector(f.StringValue(v.idx))
}
return append(a, Selector{sel})
}
// LookupDef is equal to LookupPath(MakePath(Def(name))).
//
// Deprecated: use LookupPath.
func (v hiddenValue) LookupDef(name string) Value {
return v.LookupPath(MakePath(Def(name)))
}
var errNotFound = errors.Newf(token.NoPos, "field not found")
// FieldByName looks up a field for the given name. If isIdent is true, it will
// look up a definition or hidden field (starting with `_` or `_#`). Otherwise
// it interprets name as an arbitrary string for a regular field.
//
// Deprecated: use LookupPath.
func (v hiddenValue) FieldByName(name string, isIdent bool) (f FieldInfo, err error) {
s, err := v.Struct()
if err != nil {
return f, err
}
return s.FieldByName(name, isIdent)
}
// LookupField reports information about a field of v.
//
// Deprecated: use LookupPath
func (v hiddenValue) LookupField(name string) (FieldInfo, error) {
s, err := v.Struct()
if err != nil {
// TODO: return a Value at the same location and a new error?
return FieldInfo{}, err
}
f, err := s.FieldByName(name, true)
if err != nil {
return f, err
}
if f.IsHidden {
return f, errNotFound
}
return f, err
}
// TODO: expose this API?
//
// // EvalExpr evaluates an expression within the scope of v, which must be
// // a struct.
// //
// // Expressions may refer to builtin packages if they can be uniquely identified.
// func (v Value) EvalExpr(expr ast.Expr) Value {
// ctx := v.ctx()
// result := evalExpr(ctx, v.eval(ctx), expr)
// return newValueRoot(ctx, result)
// }
// Fill creates a new value by unifying v with the value of x at the given path.
//
// Values may be any Go value that can be converted to CUE, an ast.Expr or
// a Value. In the latter case, it will panic if the Value is not from the same
// Runtime.
//
// Any reference in v referring to the value at the given path will resolve
// to x in the newly created value. The resulting value is not validated.
//
// Deprecated: use FillPath.
func (v hiddenValue) Fill(x interface{}, path ...string) Value {
if v.v == nil {
return v
}
selectors := make([]Selector, len(path))
for i, p := range path {
selectors[i] = Str(p)
}
return v.FillPath(MakePath(selectors...), x)
}
// FillPath creates a new value by unifying v with the value of x at the given
// path.
//
// If x is an cue/ast.Expr, it will be evaluated within the context of the
// given path: identifiers that are not resolved within the expression are
// resolved as if they were defined at the path position.
//
// If x is a Value, it will be used as is. It panics if x is not created
// from the same Runtime as v.
//
// Otherwise, the given Go value will be converted to CUE using the same rules
// as Context.Encode.
//
// Any reference in v referring to the value at the given path will resolve to x
// in the newly created value. The resulting value is not validated.
//
func (v Value) FillPath(p Path, x interface{}) Value {
if v.v == nil {
// TODO: panic here?
return v
}
ctx := v.ctx()
if err := p.Err(); err != nil {
return newErrValue(v, mkErr(v.idx, nil, 0, "invalid path: %v", err))
}
var expr adt.Expr
switch x := x.(type) {
case Value:
if v.idx != x.idx {
panic("values are not from the same runtime")
}
expr = x.v
case ast.Expr:
n := getScopePrefix(v, p)
// TODO: inject import path of current package?
expr = resolveExpr(ctx, n, x)
default:
expr = convert.GoValueToValue(ctx, x, true)
}
for i := len(p.path) - 1; i >= 0; i-- {
switch sel := p.path[i].sel; {
case sel == AnyString.sel:
expr = &adt.StructLit{Decls: []adt.Decl{
&adt.BulkOptionalField{
Filter: &adt.BasicType{K: adt.StringKind},
Value: expr,
},
}}
case sel == anyIndex.sel:
expr = &adt.ListLit{Elems: []adt.Elem{
&adt.Ellipsis{Value: expr},
}}
case sel == anyDefinition.sel:
expr = &adt.Bottom{Err: errors.Newf(token.NoPos,
"AnyDefinition not supported")}
case sel.kind() == adt.IntLabel:
i := sel.feature(ctx.Runtime).Index()
list := &adt.ListLit{}
any := &adt.Top{}
// TODO(perf): make this a constant thing. This will be possible with the query extension.
for k := 0; k < i; k++ {
list.Elems = append(list.Elems, any)
}
list.Elems = append(list.Elems, expr, &adt.Ellipsis{})
expr = list
default:
var d adt.Decl
if sel.optional() {
d = &adt.OptionalField{
Label: sel.feature(v.idx),
Value: expr,
}
} else {
d = &adt.Field{
Label: sel.feature(v.idx),
Value: expr,
}
}
expr = &adt.StructLit{Decls: []adt.Decl{d}}
}
}
n := &adt.Vertex{}
n.AddConjunct(adt.MakeRootConjunct(nil, expr))
n.Finalize(ctx)
w := makeValue(v.idx, n, v.parent_)
return v.Unify(w)
}
// Template returns a function that represents the template definition for a
// struct in a configuration file. It returns nil if v is not a struct kind or
// if there is no template associated with the struct.
//
// The returned function returns the value that would be unified with field
// given its name.
//
// Deprecated: use LookupPath in combination with using optional selectors.
func (v hiddenValue) Template() func(label string) Value {
if v.v == nil {
return nil
}
types := v.v.OptionalTypes()
if types&(adt.HasAdditional|adt.HasPattern) == 0 {
return nil
}
return func(label string) Value {
return v.LookupPath(MakePath(Str(label).Optional()))
}
}
// Subsume reports nil when w is an instance of v or an error otherwise.
//
// Without options, the entire value is considered for assumption, which means
// Subsume tests whether v is a backwards compatible (newer) API version of w.
//
// Use the Final option to check subsumption if a w is known to be final, and
// should assumed to be closed.
//
// Use the Raw option to do a low-level subsumption, taking defaults into
// account.
//
// Value v and w must be obtained from the same build. TODO: remove this
// requirement.
func (v Value) Subsume(w Value, opts ...Option) error {
o := getOptions(opts)
p := subsume.CUE
switch {
case o.final && o.ignoreClosedness:
p = subsume.FinalOpen
case o.final:
p = subsume.Final
case o.ignoreClosedness:
p = subsume.API
}
if !o.raw {
p.Defaults = true
}
ctx := v.ctx()
return p.Value(ctx, v.v, w.v)
}
// Deprecated: use Subsume.
//
// Subsumes reports whether w is an instance of v.
//
// Without options, Subsumes checks whether v is a backwards compatbile schema
// of w.
//
// By default, Subsumes tests whether two values are compatible
// Value v and w must be obtained from the same build.
// TODO: remove this requirement.
func (v hiddenValue) Subsumes(w Value) bool {
ctx := v.ctx()
p := subsume.Profile{Defaults: true}
return p.Check(ctx, v.v, w.v)
}
func allowed(ctx *adt.OpContext, parent, n *adt.Vertex) *adt.Bottom {
if !parent.IsClosedList() && !parent.IsClosedStruct() {
return nil
}
for _, a := range n.Arcs {
if !parent.Accept(ctx, a.Label) {
defer ctx.PopArc(ctx.PushArc(parent))
label := a.Label.SelectorString(ctx)
parent.Accept(ctx, a.Label)
return ctx.NewErrf("field not allowed: %s", label)
}
}
return nil
}
func addConjuncts(dst, src *adt.Vertex) {
c := adt.MakeRootConjunct(nil, src)
if src.Closed {
var root adt.CloseInfo
c.CloseInfo = root.SpawnRef(src, src.Closed, nil)
}
dst.AddConjunct(c)
}
// Unify reports the greatest lower bound of v and w.
//
// Value v and w must be obtained from the same build.
// TODO: remove this requirement.
func (v Value) Unify(w Value) Value {
if v.v == nil {
return w
}
if w.v == nil {
return v
}
n := &adt.Vertex{}
addConjuncts(n, v.v)
addConjuncts(n, w.v)
ctx := newContext(v.idx)
n.Finalize(ctx)
n.Parent = v.v.Parent
n.Label = v.v.Label
n.Closed = v.v.Closed || w.v.Closed
if err := n.Err(ctx, adt.Finalized); err != nil {
return makeValue(v.idx, n, v.parent_)
}
if err := allowed(ctx, v.v, n); err != nil {
return newErrValue(w, err)
}
if err := allowed(ctx, w.v, n); err != nil {
return newErrValue(v, err)
}
return makeValue(v.idx, n, v.parent_)
}
// UnifyAccept is as v.Unify(w), but will disregard any field that is allowed
// in the Value accept.
func (v Value) UnifyAccept(w Value, accept Value) Value {
if v.v == nil {
return w
}
if w.v == nil {
return v
}
if accept.v == nil {
panic("accept must exist")
}
n := &adt.Vertex{}
n.AddConjunct(adt.MakeRootConjunct(nil, v.v))
n.AddConjunct(adt.MakeRootConjunct(nil, w.v))
ctx := newContext(v.idx)
n.Finalize(ctx)
n.Parent = v.v.Parent
n.Label = v.v.Label
if err := n.Err(ctx, adt.Finalized); err != nil {
return makeValue(v.idx, n, v.parent_)
}
if err := allowed(ctx, accept.v, n); err != nil {
return newErrValue(accept, err)
}
return makeValue(v.idx, n, v.parent_)
}
// Equals reports whether two values are equal, ignoring optional fields.
// The result is undefined for incomplete values.
func (v Value) Equals(other Value) bool {
if v.v == nil || other.v == nil {
return false
}
return adt.Equal(v.ctx(), v.v, other.v, 0)
}
func (v Value) instance() *Instance {
if v.v == nil {
return nil
}
return getImportFromNode(v.idx, v.v)
}
// Reference returns the instance and path referred to by this value such that
// inst.Lookup(path) resolves to the same value, or no path if this value is not
// a reference. If a reference contains index selection (foo[bar]), it will
// only return a reference if the index resolves to a concrete value.
//
// Deprecated: use ReferencePath
func (v hiddenValue) Reference() (inst *Instance, path []string) {
root, p := v.ReferencePath()
if !root.Exists() {
return nil, nil
}
inst = getImportFromNode(v.idx, root.v)
for _, sel := range p.Selectors() {
switch x := sel.sel.(type) {
case stringSelector:
path = append(path, string(x))
default:
path = append(path, sel.String())
}
}
return inst, path
}
// ReferencePath returns the value and path referred to by this value such that
// value.LookupPath(path) resolves to the same value, or no path if this value
// is not a reference.
func (v Value) ReferencePath() (root Value, p Path) {
// TODO: don't include references to hidden fields.
if v.v == nil || len(v.v.Conjuncts) != 1 {
return Value{}, Path{}
}
ctx := v.ctx()
c := v.v.Conjuncts[0]
x, path := reference(v.idx, ctx, c.Env, c.Expr())
if x == nil {
return Value{}, Path{}
}
// NOTE: due to structure sharing, the path of the referred node may end
// up different from the one explicitly pointed to. The value will be the
// same, but the scope may differ.
// TODO(structureshare): see if we can construct the original path. This
// only has to be done if structures are being shared.
return makeValue(v.idx, x, nil), Path{path: path}
}
func reference(rt *runtime.Runtime, c *adt.OpContext, env *adt.Environment, r adt.Expr) (inst *adt.Vertex, path []Selector) {
ctx := c
defer ctx.PopState(ctx.PushState(env, r.Source()))
switch x := r.(type) {
// TODO: do we need to handle Vertex as well, in case this is hard-wired?
// Probably not, as this results from dynamic content.
case *adt.NodeLink:
// TODO: consider getting rid of NodeLink.
inst, path = mkPath(rt, nil, x.Node)
case *adt.FieldReference:
env := ctx.Env(x.UpCount)
inst, path = mkPath(rt, nil, env.Vertex)
path = appendSelector(path, featureToSel(x.Label, rt))
case *adt.LabelReference:
env := ctx.Env(x.UpCount)
return mkPath(rt, nil, env.Vertex)
case *adt.DynamicReference:
env := ctx.Env(x.UpCount)
inst, path = mkPath(rt, nil, env.Vertex)
v, _ := ctx.Evaluate(env, x.Label)
path = appendSelector(path, valueToSel(v))
case *adt.ImportReference:
inst, _ = rt.LoadImport(rt.LabelStr(x.ImportPath))
case *adt.SelectorExpr:
inst, path = reference(rt, c, env, x.X)
path = appendSelector(path, featureToSel(x.Sel, rt))
case *adt.IndexExpr:
inst, path = reference(rt, c, env, x.X)
v, _ := ctx.Evaluate(env, x.Index)
path = appendSelector(path, valueToSel(v))
}
if inst == nil {
return nil, nil
}
return inst, path
}
func mkPath(r *runtime.Runtime, a []Selector, v *adt.Vertex) (root *adt.Vertex, path []Selector) {
if v.Parent == nil {
return v, a
}
root, path = mkPath(r, a, v.Parent)
path = appendSelector(path, featureToSel(v.Label, r))
return root, path
}
type options struct {
concrete bool // enforce that values are concrete
raw bool // show original values
hasHidden bool
omitHidden bool
omitDefinitions bool
omitOptional bool
omitAttrs bool
resolveReferences bool
final bool
ignoreClosedness bool // used for comparing APIs
docs bool
disallowCycles bool // implied by concrete
allowScalar bool
}
// An Option defines modes of evaluation.
type Option option
type option func(p *options)
// Final indicates a value is final. It implicitly closes all structs and lists
// in a value and selects defaults.
func Final() Option {
return func(o *options) {
o.final = true
o.omitDefinitions = true
o.omitOptional = true
o.omitHidden = true
}
}
// Schema specifies the input is a Schema. Used by Subsume.
func Schema() Option {
return func(o *options) {
o.ignoreClosedness = true
}
}
// Concrete ensures that all values are concrete.
//
// For Validate this means it returns an error if this is not the case.
// In other cases a non-concrete value will be replaced with an error.
func Concrete(concrete bool) Option {
return func(p *options) {
if concrete {
p.concrete = true
p.final = true
if !p.hasHidden {
p.omitHidden = true
p.omitDefinitions = true
}
}
}
}
// DisallowCycles forces validation in the precense of cycles, even if
// non-concrete values are allowed. This is implied by Concrete(true).
func DisallowCycles(disallow bool) Option {
return func(p *options) { p.disallowCycles = disallow }
}
// ResolveReferences forces the evaluation of references when outputting.
// This implies the input cannot have cycles.
func ResolveReferences(resolve bool) Option {
return func(p *options) { p.resolveReferences = resolve }
}
// Raw tells Syntax to generate the value as is without any simplifications.
func Raw() Option {
return func(p *options) { p.raw = true }
}
// All indicates that all fields and values should be included in processing
// even if they can be elided or omitted.
func All() Option {
return func(p *options) {
p.omitAttrs = false
p.omitHidden = false
p.omitDefinitions = false
p.omitOptional = false
}
}
// Docs indicates whether docs should be included.
func Docs(include bool) Option {
return func(p *options) { p.docs = true }
}
// Definitions indicates whether definitions should be included.
//
// Definitions may still be included for certain functions if they are referred
// to by other other values.
func Definitions(include bool) Option {
return func(p *options) {
p.hasHidden = true
p.omitDefinitions = !include
}
}
// Hidden indicates that definitions and hidden fields should be included.
func Hidden(include bool) Option {
return func(p *options) {
p.hasHidden = true
p.omitHidden = !include
p.omitDefinitions = !include
}
}
// Optional indicates that optional fields should be included.
func Optional(include bool) Option {
return func(p *options) { p.omitOptional = !include }
}
// Attributes indicates that attributes should be included.
func Attributes(include bool) Option {
return func(p *options) { p.omitAttrs = !include }
}
func getOptions(opts []Option) (o options) {
o.updateOptions(opts)
return
}
func (o *options) updateOptions(opts []Option) {
for _, fn := range opts {
fn(o)
}
}
// Validate reports any errors, recursively. The returned error may represent
// more than one error, retrievable with errors.Errors, if more than one
// exists.
func (v Value) Validate(opts ...Option) error {
o := options{}
o.updateOptions(opts)
cfg := &validate.Config{
Concrete: o.concrete,
DisallowCycles: o.disallowCycles,
AllErrors: true,
}
b := validate.Validate(v.ctx(), v.v, cfg)
if b != nil {
return b.Err
}
return nil
}
// Walk descends into all values of v, calling f. If f returns false, Walk
// will not descent further. It only visits values that are part of the data
// model, so this excludes optional fields, hidden fields, and definitions.
func (v Value) Walk(before func(Value) bool, after func(Value)) {
ctx := v.ctx()
switch v.Kind() {
case StructKind:
if before != nil && !before(v) {
return
}
obj, _ := v.structValData(ctx)
for i := 0; i < obj.Len(); i++ {
_, v := obj.At(i)
v.Walk(before, after)
}
case ListKind:
if before != nil && !before(v) {
return
}
list, _ := v.List()
for list.Next() {
list.Value().Walk(before, after)
}
default:
if before != nil {
before(v)
}
}
if after != nil {
after(v)
}
}
// Expr reports the operation of the underlying expression and the values it
// operates on.
//
// For unary expressions, it returns the single value of the expression.
//
// For binary expressions it returns first the left and right value, in that
// order. For associative operations however, (for instance '&' and '|'), it may
// return more than two values, where the operation is to be applied in
// sequence.
//
// For selector and index expressions it returns the subject and then the index.
// For selectors, the index is the string value of the identifier.
//
// For interpolations it returns a sequence of values to be concatenated, some
// of which will be literal strings and some unevaluated expressions.
//
// A builtin call expression returns the value of the builtin followed by the
// args of the call.
func (v Value) Expr() (Op, []Value) {
// TODO: return v if this is complete? Yes for now
if v.v == nil {
return NoOp, nil
}
var expr adt.Expr
var env *adt.Environment
if v.v.IsData() {
expr = v.v.Value()
} else {
switch len(v.v.Conjuncts) {
case 0:
if v.v.BaseValue == nil {
return NoOp, []Value{makeValue(v.idx, v.v, v.parent_)} // TODO: v?
}
expr = v.v.Value()
case 1:
// the default case, processed below.
c := v.v.Conjuncts[0]
env = c.Env
expr = c.Expr()
if w, ok := expr.(*adt.Vertex); ok {
return Value{v.idx, w, v.parent_}.Expr()
}
default:
a := []Value{}
ctx := v.ctx()
for _, c := range v.v.Conjuncts {
// Keep parent here. TODO: do we need remove the requirement
// from other conjuncts?
n := &adt.Vertex{
Parent: v.v.Parent,
Label: v.v.Label,
}
n.AddConjunct(c)
n.Finalize(ctx)
a = append(a, makeValue(v.idx, n, v.parent_))
}
return adt.AndOp, a
}
}
// TODO: replace appends with []Value{}. For not leave.
a := []Value{}
op := NoOp
switch x := expr.(type) {
case *adt.BinaryExpr:
a = append(a, remakeValue(v, env, x.X))
a = append(a, remakeValue(v, env, x.Y))
op = x.Op
case *adt.UnaryExpr:
a = append(a, remakeValue(v, env, x.X))
op = x.Op
case *adt.BoundExpr:
a = append(a, remakeValue(v, env, x.Expr))
op = x.Op
case *adt.BoundValue:
a = append(a, remakeValue(v, env, x.Value))
op = x.Op
case *adt.Conjunction:
// pre-expanded unification
for _, conjunct := range x.Values {
a = append(a, remakeValue(v, env, conjunct))
}
op = AndOp
case *adt.Disjunction:
count := 0
outer:
for i, disjunct := range x.Values {
if i < x.NumDefaults {
for _, n := range x.Values[x.NumDefaults:] {
if subsume.Value(v.ctx(), n, disjunct) == nil {
continue outer
}
}
}
count++
a = append(a, remakeValue(v, env, disjunct))
}
if count > 1 {
op = OrOp
}
case *adt.DisjunctionExpr:
// Filter defaults that are subsumed by another value.
count := 0
outerExpr:
for _, disjunct := range x.Values {
if disjunct.Default {
for _, n := range x.Values {
a := adt.Vertex{
Label: v.v.Label,
}
b := a
a.AddConjunct(adt.MakeRootConjunct(env, n.Val))
b.AddConjunct(adt.MakeRootConjunct(env, disjunct.Val))
ctx := eval.NewContext(v.idx, nil)
ctx.Unify(&a, adt.Finalized)
ctx.Unify(&b, adt.Finalized)
if allowed(ctx, v.v, &b) != nil {
// Everything subsumed bottom
continue outerExpr
}
if allowed(ctx, v.v, &a) != nil {
// An error doesn't subsume anything except another error.
continue
}
a.Parent = v.v.Parent
if !n.Default && subsume.Value(ctx, &a, &b) == nil {
continue outerExpr
}
}
}
count++
a = append(a, remakeValue(v, env, disjunct.Val))
}
if count > 1 {
op = adt.OrOp
}
case *adt.Interpolation:
for _, p := range x.Parts {
a = append(a, remakeValue(v, env, p))
}
op = InterpolationOp
case *adt.FieldReference:
// TODO: allow hard link
ctx := v.ctx()
f := ctx.PushState(env, x.Src)
env := ctx.Env(x.UpCount)
a = append(a, remakeValue(v, nil, &adt.NodeLink{Node: env.Vertex}))
a = append(a, remakeValue(v, nil, ctx.NewString(x.Label.SelectorString(ctx))))
_ = ctx.PopState(f)
op = SelectorOp
case *adt.SelectorExpr:
a = append(a, remakeValue(v, env, x.X))
// A string selector is quoted.
a = append(a, remakeValue(v, env, &adt.String{
Str: x.Sel.SelectorString(v.idx),
}))
op = SelectorOp
case *adt.IndexExpr:
a = append(a, remakeValue(v, env, x.X))
a = append(a, remakeValue(v, env, x.Index))
op = IndexOp
case *adt.SliceExpr:
a = append(a, remakeValue(v, env, x.X))
a = append(a, remakeValue(v, env, x.Lo))
a = append(a, remakeValue(v, env, x.Hi))
op = SliceOp
case *adt.CallExpr:
// Interpret "and" and "or" builtin semantically.
if fn, ok := x.Fun.(*adt.Builtin); ok && len(x.Args) == 1 &&
(fn.Name == "or" || fn.Name == "and") {
iter, _ := remakeValue(v, env, x.Args[0]).List()
for iter.Next() {
a = append(a, iter.Value())
}
op = OrOp
if fn.Name == "and" {
op = AndOp
}
break
}
a = append(a, remakeValue(v, env, x.Fun))
for _, arg := range x.Args {
a = append(a, remakeValue(v, env, arg))
}
op = CallOp
case *adt.BuiltinValidator:
a = append(a, remakeValue(v, env, x.Builtin))
for _, arg := range x.Args {
a = append(a, remakeValue(v, env, arg))
}
op = CallOp
case *adt.StructLit:
// Simulate old embeddings.
envEmbed := &adt.Environment{
Up: env,
Vertex: v.v,
}
fields := []adt.Decl{}
ctx := v.ctx()
for _, d := range x.Decls {
switch x := d.(type) {
case adt.Expr:
// embedding
n := &adt.Vertex{Label: v.v.Label}
c := adt.MakeRootConjunct(envEmbed, x)
n.AddConjunct(c)
n.Finalize(ctx)
n.Parent = v.v.Parent
a = append(a, makeValue(v.idx, n, v.parent_))
default:
fields = append(fields, d)
}
}
if len(a) == 0 {
a = append(a, v)
break
}
if len(fields) > 0 {
n := &adt.Vertex{
Label: v.v.Label,
}
c := adt.MakeRootConjunct(env, &adt.StructLit{
Decls: fields,
})
n.AddConjunct(c)
n.Finalize(ctx)
n.Parent = v.v.Parent
a = append(a, makeValue(v.idx, n, v.parent_))
}
op = adt.AndOp
default:
a = append(a, v)
}
return op, a
}