| // 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 adt |
| |
| import ( |
| "fmt" |
| "math/bits" |
| "strings" |
| ) |
| |
| // Concreteness is a measure of the level of concreteness of a value, where |
| // lower values mean more concrete. |
| type Concreteness int |
| |
| const ( |
| BottomLevel Concreteness = iota |
| |
| // Concrete indicates a concrete scalar value, list or struct. |
| Concrete |
| |
| // Constraint indicates a non-concrete scalar value that is more specific, |
| // than a top-level type. |
| Constraint |
| |
| // PrimitiveType indicates a top-level specific type, for instance, string, |
| // bytes, number, or bool. |
| Type |
| |
| // Any indicates any value, or top. |
| Any |
| ) |
| |
| // IsConcrete returns whether a value is concrete. |
| func IsConcrete(v Value) bool { |
| if x, ok := v.(*Vertex); ok { |
| return x.IsConcrete() |
| } |
| if v == nil { |
| return false |
| } |
| return v.Concreteness() <= Concrete |
| } |
| |
| // Kind reports the Value kind. |
| type Kind uint16 |
| |
| const ( |
| NullKind Kind = (1 << iota) |
| BoolKind |
| IntKind |
| FloatKind |
| StringKind |
| BytesKind |
| FuncKind |
| ListKind |
| StructKind |
| |
| allKinds |
| |
| _numberKind |
| |
| NumberKind = IntKind | FloatKind |
| |
| BottomKind Kind = 0 |
| |
| NumKind = IntKind | FloatKind |
| TopKind Kind = (allKinds - 1) // all kinds, but not references |
| ScalarKinds = NullKind | BoolKind | |
| IntKind | FloatKind | StringKind | BytesKind |
| ) |
| |
| func kind(v Value) Kind { |
| if v == nil { |
| return BottomKind |
| } |
| return v.Kind() |
| } |
| |
| // IsAnyOf reports whether k is any of the given kinds. |
| // |
| // For instances, k.IsAnyOf(String|Bytes) reports whether k overlaps with |
| // the String or Bytes kind. |
| func (k Kind) IsAnyOf(of Kind) bool { |
| return k&of != BottomKind |
| } |
| |
| // CanString reports whether the given type can convert to a string. |
| func (k Kind) CanString() bool { |
| return k&StringKind|ScalarKinds != BottomKind |
| } |
| |
| // String returns the representation of the Kind as |
| // a CUE expression. For example: |
| // |
| // (IntKind|ListKind).String() |
| // |
| // will return: |
| // |
| // (int|[...]) |
| func (k Kind) String() string { |
| return toString(k, kindStrs) |
| } |
| |
| // TypeString is like String, but returns a string representation of a valid |
| // CUE type. |
| func (k Kind) TypeString() string { |
| return toString(k, typeStrs) |
| } |
| |
| func toString(k Kind, m map[Kind]string) string { |
| if k == BottomKind { |
| return "_|_" |
| } |
| if k == TopKind { |
| return "_" |
| } |
| if (k & NumberKind) == NumberKind { |
| k = (k &^ NumberKind) | _numberKind |
| } |
| var buf strings.Builder |
| multiple := bits.OnesCount(uint(k)) > 1 |
| if multiple { |
| buf.WriteByte('(') |
| } |
| for count := 0; ; count++ { |
| n := bits.TrailingZeros(uint(k)) |
| if n == bits.UintSize { |
| break |
| } |
| bit := Kind(1 << uint(n)) |
| k &^= bit |
| s, ok := m[bit] |
| if !ok { |
| s = fmt.Sprintf("bad(%d)", n) |
| } |
| if count > 0 { |
| buf.WriteByte('|') |
| } |
| buf.WriteString(s) |
| } |
| if multiple { |
| buf.WriteByte(')') |
| } |
| return buf.String() |
| } |
| |
| var kindStrs = map[Kind]string{ |
| NullKind: "null", |
| BoolKind: "bool", |
| IntKind: "int", |
| FloatKind: "float", |
| StringKind: "string", |
| BytesKind: "bytes", |
| FuncKind: "func", |
| StructKind: "struct", |
| ListKind: "list", |
| _numberKind: "number", |
| } |
| |
| // used to generate a parseable CUE type. |
| var typeStrs = map[Kind]string{ |
| NullKind: "null", |
| BoolKind: "bool", |
| IntKind: "int", |
| FloatKind: "float", |
| StringKind: "string", |
| BytesKind: "bytes", |
| FuncKind: "_", |
| StructKind: "{...}", |
| ListKind: "[...]", |
| _numberKind: "number", |
| } |