| // 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" |
| "strconv" |
| "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/format" |
| "cuelang.org/go/cue/token" |
| "cuelang.org/go/internal" |
| "cuelang.org/go/internal/core/adt" |
| "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" |
| ) |
| |
| // 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 *context |
| v Value |
| obj *adt.Vertex |
| features []adt.Feature |
| } |
| |
| // Len reports the number of fields in this struct. |
| func (o *structValue) 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 *structValue) At(i int) (key string, v Value) { |
| f := o.features[i] |
| return o.ctx.LabelStr(f), newChildValue(o, i) |
| } |
| |
| func (o *structValue) 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.opCtx, arc) |
| arc.Finalize(o.ctx.opCtx) |
| 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 *structValue) Lookup(key string) Value { |
| f := o.ctx.StrLabel(key) |
| i := 0 |
| len := o.Len() |
| for ; i < len; i++ { |
| if o.features[i] == f { |
| break |
| } |
| } |
| if i == len { |
| // TODO: better message. |
| ctx := o.ctx |
| x := ctx.mkErr(o.obj, codeNotExist, "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 *bottom |
| } |
| |
| func toMarshalErr(v Value, b *bottom) error { |
| return &marshalError{v.toErr(b), b} |
| } |
| |
| func marshalErrf(v Value, src source, code errCode, msg string, args ...interface{}) error { |
| arguments := append([]interface{}{code, msg}, args...) |
| b := v.idx.mkErr(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 |
| ctx *context |
| arcs []field |
| p int |
| cur Value |
| f label |
| isOpt bool |
| } |
| |
| 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.opCtx) |
| i.cur = makeValue(i.val.idx, f.arc) |
| 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 |
| } |
| |
| func (i *Iterator) Feature() adt.Feature { |
| return i.f |
| } |
| |
| // Label reports the label of the value if i iterates over struct fields and |
| // "" otherwise. |
| func (i *Iterator) Label() string { |
| if i.f == 0 { |
| return "" |
| } |
| return i.ctx.LabelStr(i.f) |
| } |
| |
| // IsHidden reports if a field is hidden from the data model. |
| func (i *Iterator) 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. |
| func (i *Iterator) 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 kind) (*numLit, 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).(*numLit) |
| 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(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 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. |
| 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(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(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(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(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(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 |
| } |
| |
| func (v Value) appendPath(a []string) []string { |
| for _, f := range v.v.Path() { |
| switch f.Typ() { |
| case adt.IntLabel: |
| a = append(a, strconv.FormatInt(int64(f.Index()), 10)) |
| |
| case adt.StringLabel: |
| label := v.idx.LabelStr(f) |
| if !f.IsDef() && !f.IsHidden() { |
| if !ast.IsValidIdent(label) { |
| label = strconv.Quote(label) |
| } |
| } |
| a = append(a, label) |
| default: |
| a = append(a, f.SelectorString(v.idx.Index)) |
| } |
| } |
| return a |
| } |
| |
| // Value holds any value, which may be a Boolean, Error, List, Null, Number, |
| // Struct, or String. |
| type Value struct { |
| idx *index |
| v *adt.Vertex |
| } |
| |
| func newErrValue(v Value, b *bottom) Value { |
| node := &adt.Vertex{Value: 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 makeValue(v.idx, node) |
| } |
| |
| func newVertexRoot(ctx *context, x *adt.Vertex) Value { |
| if ctx.opCtx != nil { |
| // This is indicative of an zero Value. In some cases this is called |
| // with an error value. |
| x.Finalize(ctx.opCtx) |
| } else { |
| x.UpdateStatus(adt.Finalized) |
| } |
| return makeValue(ctx.index, x) |
| } |
| |
| func newValueRoot(ctx *context, x value) Value { |
| if n, ok := x.(*adt.Vertex); ok { |
| return newVertexRoot(ctx, n) |
| } |
| node := &adt.Vertex{} |
| node.AddConjunct(adt.MakeRootConjunct(nil, x)) |
| return newVertexRoot(ctx, node) |
| } |
| |
| func newChildValue(o *structValue, i int) Value { |
| arc, _ := o.at(i) |
| return makeValue(o.v.idx, 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.opCtx.Resolve(c.Env, r) |
| if b != nil { |
| return newErrValue(v, b) |
| } |
| 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. |
| // |
| // 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)", |
| v.Status(), v.Value)) |
| } |
| return Value{idx, v} |
| } |
| |
| func remakeValue(base Value, env *adt.Environment, v value) 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} |
| } |
| n := &adt.Vertex{Label: base.v.Label} |
| n.AddConjunct(adt.MakeRootConjunct(env, v)) |
| n = base.ctx().manifest(n) |
| n.Parent = base.v.Parent |
| return makeValue(base.idx, n) |
| } |
| |
| func remakeFinal(base Value, env *adt.Environment, v adt.Value) Value { |
| n := &adt.Vertex{Parent: base.v.Parent, Label: base.v.Label, Value: v} |
| n.UpdateStatus(adt.Finalized) |
| return makeValue(base.idx, n) |
| } |
| |
| func (v Value) ctx() *context { |
| return v.idx.newContext() |
| } |
| |
| func (v Value) makeChild(ctx *context, i uint32, a arc) Value { |
| a.Parent = v.v |
| return makeValue(v.idx, a) |
| } |
| |
| // 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().opCtx) |
| x = x.ToDataSingle() |
| return makeValue(v.idx, x) |
| // 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), 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 Value) 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.Value |
| if !adt.IsConcrete(c) { |
| return BottomKind |
| } |
| if v.IncompleteKind() == adt.ListKind && !v.IsClosed() { |
| 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 := v.idx.newContext() |
| x := v.eval(ctx) |
| |
| if _, ok := x.(adt.Resolver); ok { |
| return nil, marshalErrf(v, x, codeIncomplete, "value %q contains unresolved references", ctx.str(x)) |
| } |
| if !adt.IsConcrete(x) { |
| return nil, marshalErrf(v, x, codeIncomplete, "cannot convert incomplete value %q to JSON", ctx.str(x)) |
| } |
| |
| // TODO: implement marshalles in value. |
| switch k := x.Kind(); k { |
| case nullKind: |
| return json.Marshal(nil) |
| case boolKind: |
| return json.Marshal(x.(*boolLit).B) |
| case intKind, floatKind, numKind: |
| b, err := x.(*numLit).X.MarshalText() |
| b = bytes.TrimLeft(b, "+") |
| return b, err |
| case stringKind: |
| return json.Marshal(x.(*stringLit).Str) |
| case bytesKind: |
| return json.Marshal(x.(*bytesLit).B) |
| case listKind: |
| i, _ := v.List() |
| return marshalList(&i) |
| case structKind: |
| obj, err := v.structValData(ctx) |
| if err != nil { |
| return nil, toMarshalErr(v, err) |
| } |
| return obj.marshalJSON() |
| case bottomKind: |
| return nil, toMarshalErr(v, x.(*bottom)) |
| default: |
| return nil, marshalErrf(v, x, 0, "cannot convert value %q of type %T to JSON", ctx.str(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, |
| } |
| |
| // 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.Runtime, v.v) |
| if err != nil { |
| return nil |
| } |
| |
| // This introduces gratuitous unshadowing! |
| f, err = astutil.ToFile(expr) |
| if err != nil { |
| return nil |
| } |
| // return expr |
| } else { |
| f, err = p.Def(v.idx.Runtime, v.v) |
| if err != nil { |
| panic(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, |
| } |
| } |
| |
| // Decode initializes x with Value v. If x is a struct, it will validate the |
| // constraints specified in the field tags. |
| func (v Value) Decode(x interface{}) error { |
| // TODO: optimize |
| b, err := v.MarshalJSON() |
| if err != nil { |
| return err |
| } |
| return json.Unmarshal(b, x) |
| } |
| |
| // // EncodeJSON generates JSON for the given value. |
| // func (v Value) EncodeJSON(w io.Writer, v Value) error { |
| // return nil |
| // } |
| |
| // 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 Value) 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(), 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. |
| func (v Value) IsClosed() bool { |
| if v.v == nil { |
| return false |
| } |
| return v.v.IsClosed(v.ctx().opCtx) |
| } |
| |
| // 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.Value.(*adt.Bottom); ok { |
| return !b.IsIncomplete() |
| } |
| if !adt.IsConcrete(v.v) { |
| return false |
| } |
| if v.IncompleteKind() == adt.ListKind && !v.IsClosed() { |
| 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 |
| } |
| return exists(v.v.Value) |
| } |
| |
| func (v Value) checkKind(ctx *context, want kind) *bottom { |
| if v.v == nil { |
| return errNotExists |
| } |
| // TODO: use checkKind |
| x := v.eval(ctx) |
| if b, ok := x.(*bottom); ok { |
| return b |
| } |
| k := x.Kind() |
| if want != bottomKind { |
| if k&want == bottomKind { |
| return ctx.mkErr(x, "cannot use value %v (type %s) as %s", |
| ctx.opCtx.Str(x), k, want) |
| } |
| if !adt.IsConcrete(x) { |
| return ctx.mkErr(x, codeIncomplete, "non-concrete value %v", k) |
| } |
| } |
| return nil |
| } |
| |
| func makeInt(v Value, x int64) Value { |
| n := &adt.Num{K: 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() { |
| ctx := v.ctx() |
| n := &adt.Num{K: intKind} |
| n.X.SetInt64(int64(len(x.Elems()))) |
| if x.IsClosed(ctx.opCtx) { |
| 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 *bytesLit: |
| return makeInt(v, int64(len(x.B))) |
| case *stringLit: |
| return makeInt(v, int64(len([]rune(x.Str)))) |
| } |
| } |
| const msg = "len not supported for type %v" |
| return remakeValue(v, nil, v.ctx().mkErr(v.v, msg, v.Kind())) |
| |
| } |
| |
| // Elem returns the value of undefined element types of lists and structs. |
| func (v Value) Elem() (Value, bool) { |
| if v.v == nil { |
| return Value{}, false |
| } |
| ctx := v.ctx().opCtx |
| x := &adt.Vertex{ |
| Parent: v.v, |
| Label: 0, |
| } |
| v.v.Finalize(ctx) |
| v.v.MatchAndInsert(ctx, x) |
| if len(x.Conjuncts) == 0 { |
| return Value{}, false |
| } |
| x.Finalize(ctx) |
| return makeValue(v.idx, x), true |
| } |
| |
| // // BulkOptionals returns all bulk optional fields as key-value pairs. |
| // // See also Elem and Template. |
| // func (v Value) BulkOptionals() [][2]Value { |
| // x, ok := v.path.cache.(*structLit) |
| // if !ok { |
| // return nil |
| // } |
| // return v.appendBulk(nil, x.optionals) |
| // } |
| |
| // func (v Value) appendBulk(a [][2]Value, x *optionals) [][2]Value { |
| // if x == nil { |
| // return a |
| // } |
| // a = v.appendBulk(a, x.left) |
| // a = v.appendBulk(a, x.right) |
| // for _, set := range x.fields { |
| // if set.key != nil { |
| // ctx := v.ctx() |
| // fn, ok := ctx.manifest(set.value).(*lambdaExpr) |
| // if !ok { |
| // // create error |
| // continue |
| // } |
| // x := fn.call(ctx, set.value, &basicType{K: stringKind}) |
| |
| // a = append(a, [2]Value{v.makeElem(set.key), v.makeElem(x)}) |
| // } |
| // } |
| // return a |
| // } |
| |
| // 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, listKind); err != nil { |
| return Iterator{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{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(), 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, boolKind); err != nil { |
| return false, v.toErr(err) |
| } |
| return v.eval(ctx).(*boolLit).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, stringKind); err != nil { |
| return "", v.toErr(err) |
| } |
| return v.eval(ctx).(*stringLit).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 *bytesLit: |
| return append([]byte(nil), x.B...), nil |
| case *stringLit: |
| return []byte(x.Str), nil |
| } |
| return nil, v.toErr(v.checkKind(ctx, bytesKind|stringKind)) |
| } |
| |
| // Reader returns a new Reader if v is a string or bytes type and an error |
| // otherwise. |
| func (v Value) Reader() (io.Reader, error) { |
| v, _ = v.Default() |
| ctx := v.ctx() |
| switch x := v.eval(ctx).(type) { |
| case *bytesLit: |
| return bytes.NewReader(x.B), nil |
| case *stringLit: |
| return strings.NewReader(x.Str), nil |
| } |
| return nil, v.toErr(v.checkKind(ctx, stringKind|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 *context) (structValue, *bottom) { |
| return v.structValOpts(ctx, options{ |
| omitHidden: true, |
| omitDefinitions: true, |
| omitOptional: true, |
| }) |
| } |
| |
| func (v Value) structValFull(ctx *context) (structValue, *bottom) { |
| return v.structValOpts(ctx, options{}) |
| } |
| |
| // structVal returns an structVal or an error if v is not a struct. |
| func (v Value) structValOpts(ctx *context, o options) (structValue, *bottom) { |
| v, _ = v.Default() |
| |
| 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.opCtx, &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 Value) Struct() (*Struct, error) { |
| 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() (*structLit, *bottom) { |
| ctx := v.ctx() |
| if err := v.checkKind(ctx, structKind); err != nil { |
| if !err.ChildError { |
| return nil, err |
| } |
| } |
| return v.v, nil |
| } |
| |
| // Struct represents a CUE struct value. |
| type Struct struct { |
| structValue |
| } |
| |
| // 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 *Struct) Len() int { |
| return s.structValue.Len() |
| } |
| |
| // field reports information about the ith field, i < o.Len(). |
| func (s *Struct) Field(i int) FieldInfo { |
| a, opt := s.at(i) |
| ctx := s.v.ctx() |
| |
| v := makeValue(s.v.idx, a) |
| name := ctx.LabelStr(a.Label) |
| str := a.Label.SelectorString(ctx.opCtx) |
| 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 *Struct) FieldByName(name string, isIdent bool) (FieldInfo, error) { |
| f := s.v.ctx().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 *Struct) 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{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{ctx: ctx, val: v, arcs: arcs}, nil |
| } |
| |
| // Lookup reports the value at a path starting from v. The empty path returns v |
| // itself. Use LookupDef for definitions or LookupField for any kind of field. |
| // |
| // 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. |
| func (v Value) 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 |
| } |
| |
| // LookupDef reports the definition with the given name within struct v. The |
| // Exists method of the returned value will report false if the definition did |
| // not exist. The Err method reports if any error occurred during evaluation. |
| func (v Value) LookupDef(name string) Value { |
| ctx := v.ctx() |
| o, err := v.structValFull(ctx) |
| if err != nil { |
| return newErrValue(v, err) |
| } |
| |
| f := v.ctx().Label(name, true) |
| for i, a := range o.features { |
| if a == f { |
| if f.IsHidden() || !f.IsDef() { // optional not possible for now |
| break |
| } |
| return newChildValue(&o, i) |
| } |
| } |
| if !strings.HasPrefix(name, "#") { |
| alt := v.LookupDef("#" + name) |
| // Use the original error message if this resulted in an error as well. |
| if alt.Err() == nil { |
| return alt |
| } |
| } |
| return newErrValue(v, ctx.mkErr(v.v, "definition %q not found", 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. |
| func (v Value) 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: this API does not work with new-style definitions. Use FieldByName. |
| func (v Value) 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. |
| func (v Value) Fill(x interface{}, path ...string) Value { |
| if v.v == nil { |
| return v |
| } |
| ctx := v.ctx() |
| for i := len(path) - 1; i >= 0; i-- { |
| x = map[string]interface{}{path[i]: x} |
| } |
| var value = convert.GoValueToValue(ctx.opCtx, x, true) |
| n, _ := value.(*adt.Vertex) |
| if n == nil { |
| n = &adt.Vertex{Label: v.v.Label} |
| n.AddConjunct(adt.MakeRootConjunct(nil, value)) |
| } else { |
| n.Label = v.v.Label |
| } |
| n.Finalize(ctx.opCtx) |
| n.Parent = v.v.Parent |
| w := makeValue(v.idx, n) |
| 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. |
| func (v Value) Template() func(label string) Value { |
| // TODO: rename to optional. |
| if v.v == nil { |
| return nil |
| } |
| |
| types := v.v.OptionalTypes() |
| if types&(adt.HasAdditional|adt.HasPattern) == 0 { |
| return nil |
| } |
| |
| parent := v.v |
| ctx := v.ctx().opCtx |
| return func(label string) Value { |
| f := ctx.StringLabel(label) |
| arc := &adt.Vertex{Parent: parent, Label: f} |
| v.v.MatchAndInsert(ctx, arc) |
| if len(arc.Conjuncts) == 0 { |
| return Value{} |
| } |
| arc.Finalize(ctx) |
| return makeValue(v.idx, arc) |
| } |
| } |
| |
| // 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() to indicate that the subsumed value is data, and that |
| // |
| // Use the Final option to check subsumption if a w is known to be final, |
| // and should assumed to be closed. |
| // |
| // Options are currently ignored and the function will panic if any are passed. |
| // |
| // 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 |
| } |
| p.Defaults = true |
| ctx := v.ctx().opCtx |
| 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 Value) Subsumes(w Value) bool { |
| p := subsume.Profile{Defaults: true} |
| return p.Check(v.ctx().opCtx, v.v, w.v) |
| } |
| |
| // 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 { |
| // ctx := v.ctx() |
| if v.v == nil { |
| return w |
| } |
| if w.v == nil { |
| return v |
| } |
| n := &adt.Vertex{Label: v.v.Label} |
| n.AddConjunct(adt.MakeRootConjunct(nil, v.v)) |
| n.AddConjunct(adt.MakeRootConjunct(nil, w.v)) |
| |
| ctx := v.idx.newContext() |
| n.Finalize(ctx.opCtx) |
| |
| // We do not set the parent until here as we don't want to "inherit" the |
| // closedness setting from v. |
| n.Parent = v.v.Parent |
| return makeValue(v.idx, n) |
| } |
| |
| // 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{Parent: v.v.Parent, Label: v.v.Label} |
| n.AddConjunct(adt.MakeRootConjunct(nil, v.v)) |
| n.AddConjunct(adt.MakeRootConjunct(nil, w.v)) |
| |
| e := eval.New(v.idx.Runtime) |
| ctx := e.NewContext(n) |
| e.UnifyAccept(ctx, n, adt.Finalized, accept.v.Closed) // check for nil. |
| |
| // ctx := v.idx.newContext() |
| n.Closed = accept.v.Closed |
| n.Finalize(ctx) |
| return makeValue(v.idx, n) |
| } |
| |
| // 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 eval.Equal(v.ctx().opCtx, v.v, other.v) |
| |
| } |
| |
| // Format prints a debug version of a value. |
| func (v Value) Format(state fmt.State, verb rune) { |
| ctx := v.ctx() |
| if v.v == nil { |
| fmt.Fprint(state, "<nil>") |
| return |
| } |
| switch { |
| case state.Flag('#'): |
| _, _ = io.WriteString(state, ctx.str(v.v)) |
| case state.Flag('+'): |
| _, _ = io.WriteString(state, ctx.opCtx.Str(v.v)) |
| default: |
| n, _ := export.Raw.Expr(v.idx.Runtime, v.v) |
| b, _ := format.Node(n) |
| _, _ = state.Write(b) |
| } |
| } |
| |
| func (v Value) instance() *Instance { |
| if v.v == nil { |
| return nil |
| } |
| return v.ctx().getImportFromNode(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. |
| func (v Value) Reference() (inst *Instance, path []string) { |
| // TODO: don't include references to hidden fields. |
| if v.v == nil || len(v.v.Conjuncts) != 1 { |
| return nil, nil |
| } |
| ctx := v.ctx() |
| c := v.v.Conjuncts[0] |
| |
| return reference(ctx, c.Env, c.Expr()) |
| } |
| |
| func reference(c *context, env *adt.Environment, r adt.Expr) (inst *Instance, path []string) { |
| ctx := c.opCtx |
| defer ctx.PopState(ctx.PushState(env, r.Source())) |
| |
| switch x := r.(type) { |
| case *adt.FieldReference: |
| env := ctx.Env(x.UpCount) |
| inst, path = mkPath(c, nil, env.Vertex) |
| path = append(path, x.Label.SelectorString(c.Index)) |
| |
| case *adt.LabelReference: |
| env := ctx.Env(x.UpCount) |
| return mkPath(c, nil, env.Vertex) |
| |
| case *adt.DynamicReference: |
| env := ctx.Env(x.UpCount) |
| inst, path = mkPath(c, nil, env.Vertex) |
| v, _ := ctx.Evaluate(env, x.Label) |
| str := ctx.StringValue(v) |
| path = append(path, str) |
| |
| case *adt.ImportReference: |
| imp := x.ImportPath.StringValue(ctx) |
| inst = c.index.getImportFromPath(imp) |
| |
| case *adt.SelectorExpr: |
| inst, path = reference(c, env, x.X) |
| path = append(path, x.Sel.SelectorString(ctx)) |
| |
| case *adt.IndexExpr: |
| inst, path = reference(c, env, x.X) |
| v, _ := ctx.Evaluate(env, x.Index) |
| str := ctx.StringValue(v) |
| path = append(path, str) |
| } |
| if inst == nil { |
| return nil, nil |
| } |
| return inst, path |
| } |
| |
| func mkPath(ctx *context, a []string, v *adt.Vertex) (inst *Instance, path []string) { |
| if v.Parent == nil { |
| return ctx.index.getImportFromNode(v), a |
| } |
| inst, path = mkPath(ctx, a, v.Parent) |
| path = append(path, v.Label.SelectorString(ctx.opCtx)) |
| return inst, path |
| } |
| |
| // // References reports all references used to evaluate this value. It does not |
| // // report references for sub fields if v is a struct. |
| // // |
| // // Deprecated: can be implemented in terms of Reference and Expr. |
| // func (v Value) References() [][]string { |
| // panic("deprecated") |
| // } |
| |
| 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 |
| } |
| |
| // 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. |
| // |
| // Deprecated: Hidden fields are deprecated. |
| 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().opCtx, 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) |
| } |
| } |
| |
| // Attribute returns the attribute data for the given key. |
| // The returned attribute will return an error for any of its methods if there |
| // is no attribute for the requested key. |
| func (v Value) Attribute(key string) Attribute { |
| // look up the attributes |
| if v.v == nil { |
| return Attribute{internal.NewNonExisting(key)} |
| } |
| // look up the attributes |
| for _, a := range export.ExtractFieldAttrs(v.v.Conjuncts) { |
| k, body := a.Split() |
| if key != k { |
| continue |
| } |
| return Attribute{internal.ParseAttrBody(token.NoPos, body)} |
| } |
| |
| return Attribute{internal.NewNonExisting(key)} |
| } |
| |
| // An Attribute contains meta data about a field. |
| type Attribute struct { |
| attr internal.Attr |
| } |
| |
| // Err returns the error associated with this Attribute or nil if this |
| // attribute is valid. |
| func (a *Attribute) Err() error { |
| return a.attr.Err |
| } |
| |
| // String reports the possibly empty string value at the given position or |
| // an error the attribute is invalid or if the position does not exist. |
| func (a *Attribute) String(pos int) (string, error) { |
| return a.attr.String(pos) |
| } |
| |
| // Int reports the integer at the given position or an error if the attribute is |
| // invalid, the position does not exist, or the value at the given position is |
| // not an integer. |
| func (a *Attribute) Int(pos int) (int64, error) { |
| return a.attr.Int(pos) |
| } |
| |
| // Flag reports whether an entry with the given name exists at position pos or |
| // onwards or an error if the attribute is invalid or if the first pos-1 entries |
| // are not defined. |
| func (a *Attribute) Flag(pos int, key string) (bool, error) { |
| return a.attr.Flag(pos, key) |
| } |
| |
| // Lookup searches for an entry of the form key=value from position pos onwards |
| // and reports the value if found. It reports an error if the attribute is |
| // invalid or if the first pos-1 entries are not defined. |
| func (a *Attribute) Lookup(pos int, key string) (val string, found bool, err error) { |
| return a.attr.Lookup(pos, key) |
| } |
| |
| // 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() { |
| switch x := v.v.Value.(type) { |
| case *adt.ListMarker, *adt.StructMarker: |
| expr = v.v |
| default: |
| expr = x |
| } |
| |
| } else { |
| switch len(v.v.Conjuncts) { |
| case 0: |
| if v.v.Value == nil { |
| return NoOp, []Value{makeValue(v.idx, v.v)} |
| } |
| switch x := v.v.Value.(type) { |
| case *adt.ListMarker, *adt.StructMarker: |
| expr = v.v |
| default: |
| expr = x |
| } |
| |
| 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}.Expr() |
| } |
| |
| default: |
| a := []Value{} |
| ctx := v.ctx().opCtx |
| 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)) |
| } |
| return adt.AndOp, a |
| } |
| } |
| |
| // TODO: replace appends with []Value{}. For not leave. |
| a := []Value{} |
| op := NoOp |
| switch x := expr.(type) { |
| case *binaryExpr: |
| a = append(a, remakeValue(v, env, x.X)) |
| a = append(a, remakeValue(v, env, x.Y)) |
| op = x.Op |
| case *unaryExpr: |
| a = append(a, remakeValue(v, env, x.X)) |
| op = x.Op |
| case *boundExpr: |
| a = append(a, remakeValue(v, env, x.Expr)) |
| op = x.Op |
| case *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().opCtx, 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, |
| Closed: v.v.Closed, |
| } |
| b := a |
| a.AddConjunct(adt.MakeRootConjunct(env, n.Val)) |
| b.AddConjunct(adt.MakeRootConjunct(env, disjunct.Val)) |
| |
| e := eval.New(v.idx.Runtime) |
| ctx := e.NewContext(nil) |
| e.UnifyAccept(ctx, &a, adt.Finalized, v.v.Closed) |
| e.UnifyAccept(ctx, &b, adt.Finalized, v.v.Closed) |
| 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 *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().opCtx |
| 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 *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.Index), |
| })) |
| op = SelectorOp |
| |
| case *indexExpr: |
| a = append(a, remakeValue(v, env, x.X)) |
| a = append(a, remakeValue(v, env, x.Index)) |
| op = IndexOp |
| case *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 *callExpr: |
| a = append(a, remakeValue(v, env, x.Fun)) |
| for _, arg := range x.Args { |
| a = append(a, remakeValue(v, env, arg)) |
| } |
| op = CallOp |
| case *customValidator: |
| 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().opCtx |
| 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)) |
| |
| 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)) |
| } |
| |
| op = adt.AndOp |
| |
| default: |
| a = append(a, v) |
| } |
| return op, a |
| } |