...

Source file src/cuelang.org/go/internal/core/adt/kind.go

Documentation: cuelang.org/go/internal/core/adt

     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  	NumberKind = IntKind | FloatKind
    75  
    76  	BottomKind Kind = 0
    77  
    78  	NumKind          = IntKind | FloatKind
    79  	TopKind     Kind = (allKinds - 1) // all kinds, but not references
    80  	ScalarKinds      = NullKind | BoolKind |
    81  		IntKind | FloatKind | StringKind | BytesKind
    82  
    83  	CompositKind = StructKind | ListKind
    84  )
    85  
    86  func kind(v Value) Kind {
    87  	if v == nil {
    88  		return BottomKind
    89  	}
    90  	return v.Kind()
    91  }
    92  
    93  // IsAnyOf reports whether k is any of the given kinds.
    94  //
    95  // For instances, k.IsAnyOf(String|Bytes) reports whether k overlaps with
    96  // the String or Bytes kind.
    97  func (k Kind) IsAnyOf(of Kind) bool {
    98  	return k&of != BottomKind
    99  }
   100  
   101  // CanString reports whether the given type can convert to a string.
   102  func (k Kind) CanString() bool {
   103  	return k&StringKind|ScalarKinds != BottomKind
   104  }
   105  
   106  // String returns the representation of the Kind as
   107  // a CUE expression. For example:
   108  //
   109  //	(IntKind|ListKind).String()
   110  //
   111  // will return:
   112  //
   113  //	(int|[...])
   114  func (k Kind) String() string {
   115  	return toString(k, kindStrs)
   116  }
   117  
   118  // TypeString is like String, but returns a string representation of a valid
   119  // CUE type.
   120  func (k Kind) TypeString() string {
   121  	return toString(k, typeStrs)
   122  }
   123  
   124  func toString(k Kind, m map[Kind]string) string {
   125  	if k == BottomKind {
   126  		return "_|_"
   127  	}
   128  	if k == TopKind {
   129  		return "_"
   130  	}
   131  	if (k & NumberKind) == NumberKind {
   132  		k = (k &^ NumberKind) | _numberKind
   133  	}
   134  	var buf strings.Builder
   135  	multiple := bits.OnesCount(uint(k)) > 1
   136  	if multiple {
   137  		buf.WriteByte('(')
   138  	}
   139  	for count := 0; ; count++ {
   140  		n := bits.TrailingZeros(uint(k))
   141  		if n == bits.UintSize {
   142  			break
   143  		}
   144  		bit := Kind(1 << uint(n))
   145  		k &^= bit
   146  		s, ok := m[bit]
   147  		if !ok {
   148  			s = fmt.Sprintf("bad(%d)", n)
   149  		}
   150  		if count > 0 {
   151  			buf.WriteByte('|')
   152  		}
   153  		buf.WriteString(s)
   154  	}
   155  	if multiple {
   156  		buf.WriteByte(')')
   157  	}
   158  	return buf.String()
   159  }
   160  
   161  var kindStrs = map[Kind]string{
   162  	NullKind:    "null",
   163  	BoolKind:    "bool",
   164  	IntKind:     "int",
   165  	FloatKind:   "float",
   166  	StringKind:  "string",
   167  	BytesKind:   "bytes",
   168  	FuncKind:    "func",
   169  	StructKind:  "struct",
   170  	ListKind:    "list",
   171  	_numberKind: "number",
   172  }
   173  
   174  // used to generate a parseable CUE type.
   175  var typeStrs = map[Kind]string{
   176  	NullKind:    "null",
   177  	BoolKind:    "bool",
   178  	IntKind:     "int",
   179  	FloatKind:   "float",
   180  	StringKind:  "string",
   181  	BytesKind:   "bytes",
   182  	FuncKind:    "_",
   183  	StructKind:  "{...}",
   184  	ListKind:    "[...]",
   185  	_numberKind: "number",
   186  }
   187  

View as plain text