cuelang.org/go@v0.10.1/internal/core/adt/kind.go (about)

     1  // Copyright 2018 The CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package adt
    16  
    17  import (
    18  	"fmt"
    19  	"math/bits"
    20  	"strings"
    21  )
    22  
    23  // Concreteness is a measure of the level of concreteness of a value, where
    24  // lower values mean more concrete.
    25  type Concreteness int
    26  
    27  const (
    28  	BottomLevel Concreteness = iota
    29  
    30  	// Concrete indicates a concrete scalar value, list or struct.
    31  	Concrete
    32  
    33  	// Constraint indicates a non-concrete scalar value that is more specific,
    34  	// than a top-level type.
    35  	Constraint
    36  
    37  	// PrimitiveType indicates a top-level specific type, for instance, string,
    38  	// bytes, number, or bool.
    39  	Type
    40  
    41  	// Any indicates any value, or top.
    42  	Any
    43  )
    44  
    45  // IsConcrete returns whether a value is concrete.
    46  func IsConcrete(v Value) bool {
    47  	if x, ok := v.(*Vertex); ok {
    48  		return x.IsConcrete()
    49  	}
    50  	if v == nil {
    51  		return false
    52  	}
    53  	return v.Concreteness() <= Concrete
    54  }
    55  
    56  // Kind reports the Value kind.
    57  type Kind uint16
    58  
    59  const (
    60  	NullKind Kind = (1 << iota)
    61  	BoolKind
    62  	IntKind
    63  	FloatKind
    64  	StringKind
    65  	BytesKind
    66  	FuncKind
    67  	ListKind
    68  	StructKind
    69  
    70  	allKinds
    71  
    72  	_numberKind
    73  
    74  	BottomKind Kind = 0
    75  
    76  	NumberKind       = IntKind | FloatKind
    77  	TopKind     Kind = (allKinds - 1) // all kinds, but not references
    78  	ScalarKinds      = NullKind | BoolKind |
    79  		IntKind | FloatKind | StringKind | BytesKind
    80  
    81  	CompositeKind = StructKind | ListKind
    82  )
    83  
    84  func kind(v Value) Kind {
    85  	if v == nil {
    86  		return BottomKind
    87  	}
    88  	return v.Kind()
    89  }
    90  
    91  // IsAnyOf reports whether k is any of the given kinds.
    92  //
    93  // For instances, k.IsAnyOf(String|Bytes) reports whether k overlaps with
    94  // the String or Bytes kind.
    95  func (k Kind) IsAnyOf(of Kind) bool {
    96  	return k&of != BottomKind
    97  }
    98  
    99  // CanString reports whether the given type can convert to a string.
   100  func (k Kind) CanString() bool {
   101  	return k&StringKind|ScalarKinds != BottomKind
   102  }
   103  
   104  // String returns the representation of the Kind as
   105  // a CUE expression. For example:
   106  //
   107  //	(IntKind|ListKind).String()
   108  //
   109  // will return:
   110  //
   111  //	(int|[...])
   112  func (k Kind) String() string {
   113  	return toString(k, kindStrs)
   114  }
   115  
   116  // TypeString is like String, but returns a string representation of a valid
   117  // CUE type.
   118  func (k Kind) TypeString() string {
   119  	return toString(k, typeStrs)
   120  }
   121  
   122  func toString(k Kind, m map[Kind]string) string {
   123  	if k == BottomKind {
   124  		return "_|_"
   125  	}
   126  	if k == TopKind {
   127  		return "_"
   128  	}
   129  	if (k & NumberKind) == NumberKind {
   130  		k = (k &^ NumberKind) | _numberKind
   131  	}
   132  	var buf strings.Builder
   133  	multiple := bits.OnesCount(uint(k)) > 1
   134  	if multiple {
   135  		buf.WriteByte('(')
   136  	}
   137  	for count := 0; ; count++ {
   138  		n := bits.TrailingZeros(uint(k))
   139  		if n == bits.UintSize {
   140  			break
   141  		}
   142  		bit := Kind(1 << uint(n))
   143  		k &^= bit
   144  		s, ok := m[bit]
   145  		if !ok {
   146  			s = fmt.Sprintf("bad(%d)", n)
   147  		}
   148  		if count > 0 {
   149  			buf.WriteByte('|')
   150  		}
   151  		buf.WriteString(s)
   152  	}
   153  	if multiple {
   154  		buf.WriteByte(')')
   155  	}
   156  	return buf.String()
   157  }
   158  
   159  var kindStrs = map[Kind]string{
   160  	NullKind:    "null",
   161  	BoolKind:    "bool",
   162  	IntKind:     "int",
   163  	FloatKind:   "float",
   164  	StringKind:  "string",
   165  	BytesKind:   "bytes",
   166  	FuncKind:    "func",
   167  	StructKind:  "struct",
   168  	ListKind:    "list",
   169  	_numberKind: "number",
   170  }
   171  
   172  // used to generate a parseable CUE type.
   173  var typeStrs = map[Kind]string{
   174  	NullKind:    "null",
   175  	BoolKind:    "bool",
   176  	IntKind:     "int",
   177  	FloatKind:   "float",
   178  	StringKind:  "string",
   179  	BytesKind:   "bytes",
   180  	FuncKind:    "_",
   181  	StructKind:  "{...}",
   182  	ListKind:    "[...]",
   183  	_numberKind: "number",
   184  }