github.com/solo-io/cue@v0.4.7/internal/core/compile/predeclared.go (about)

     1  // Copyright 2020 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 compile
    16  
    17  import (
    18  	"strconv"
    19  
    20  	"github.com/solo-io/cue/cue/ast"
    21  	"github.com/solo-io/cue/cue/token"
    22  	"github.com/solo-io/cue/internal/core/adt"
    23  )
    24  
    25  func predeclared(n *ast.Ident) adt.Expr {
    26  	// TODO: consider supporting GraphQL-style names:
    27  	// String, Bytes, Boolean, Integer, Number.
    28  	// These names will not conflict with idiomatic camel-case JSON.
    29  	switch n.Name {
    30  	case "_":
    31  		return &adt.Top{Src: n}
    32  	case "string", "__string":
    33  		return &adt.BasicType{Src: n, K: adt.StringKind}
    34  	case "bytes", "__bytes":
    35  		return &adt.BasicType{Src: n, K: adt.BytesKind}
    36  	case "bool", "__bool":
    37  		return &adt.BasicType{Src: n, K: adt.BoolKind}
    38  	case "int", "__int":
    39  		return &adt.BasicType{Src: n, K: adt.IntKind}
    40  	case "float", "__float":
    41  		return &adt.BasicType{Src: n, K: adt.FloatKind}
    42  	case "number", "__number":
    43  		return &adt.BasicType{Src: n, K: adt.NumKind}
    44  
    45  	case "len", "__len":
    46  		return lenBuiltin
    47  	case "close", "__close":
    48  		return closeBuiltin
    49  	case "and", "__and":
    50  		return andBuiltin
    51  	case "or", "__or":
    52  		return orBuiltin
    53  	case "div", "__div":
    54  		return divBuiltin
    55  	case "mod", "__mod":
    56  		return modBuiltin
    57  	case "quo", "__quo":
    58  		return quoBuiltin
    59  	case "rem", "__rem":
    60  		return remBuiltin
    61  	}
    62  
    63  	if r, ok := predefinedRanges[n.Name]; ok {
    64  		return r
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // LookupRange returns a CUE expressions for the given predeclared identifier
    71  // representing a range, such as uint8, int128, and float64.
    72  func LookupRange(name string) adt.Expr {
    73  	return predefinedRanges[name]
    74  }
    75  
    76  var predefinedRanges = map[string]adt.Expr{
    77  	"rune":  mkIntRange("0", strconv.Itoa(0x10FFFF)),
    78  	"int8":  mkIntRange("-128", "127"),
    79  	"int16": mkIntRange("-32768", "32767"),
    80  	"int32": mkIntRange("-2147483648", "2147483647"),
    81  	"int64": mkIntRange("-9223372036854775808", "9223372036854775807"),
    82  	"int128": mkIntRange(
    83  		"-170141183460469231731687303715884105728",
    84  		"170141183460469231731687303715884105727"),
    85  
    86  	// Do not include an alias for "byte", as it would be too easily confused
    87  	// with the builtin "bytes".
    88  	"uint":    mkUint(),
    89  	"uint8":   mkIntRange("0", "255"),
    90  	"uint16":  mkIntRange("0", "65535"),
    91  	"uint32":  mkIntRange("0", "4294967295"),
    92  	"uint64":  mkIntRange("0", "18446744073709551615"),
    93  	"uint128": mkIntRange("0", "340282366920938463463374607431768211455"),
    94  
    95  	// 2**127 * (2**24 - 1) / 2**23
    96  	"float32": mkFloatRange(
    97  		"-3.40282346638528859811704183484516925440e+38",
    98  		"3.40282346638528859811704183484516925440e+38",
    99  	),
   100  	// 2**1023 * (2**53 - 1) / 2**52
   101  	"float64": mkFloatRange(
   102  		"-1.797693134862315708145274237317043567981e+308",
   103  		"1.797693134862315708145274237317043567981e+308",
   104  	),
   105  }
   106  
   107  func init() {
   108  	for k, v := range predefinedRanges {
   109  		predefinedRanges["__"+k] = v
   110  	}
   111  }
   112  
   113  // TODO: use an adt.BoundValue here. and conjunctions here.
   114  
   115  func mkUint() adt.Expr {
   116  	from := newBound(adt.GreaterEqualOp, adt.IntKind, parseInt("0"))
   117  	ident := ast.NewIdent("__int")
   118  	src := ast.NewBinExpr(token.AND, ident, from.Src)
   119  	return &adt.Conjunction{
   120  		Src: src,
   121  		Values: []adt.Value{
   122  			&adt.BasicType{Src: ident, K: adt.IntKind}, from,
   123  		},
   124  	}
   125  }
   126  
   127  func mkIntRange(a, b string) adt.Expr {
   128  	from := newBound(adt.GreaterEqualOp, adt.IntKind, parseInt(a))
   129  	to := newBound(adt.LessEqualOp, adt.IntKind, parseInt(b))
   130  	ident := ast.NewIdent("__int")
   131  	src := ast.NewBinExpr(token.AND, ident, from.Src, to.Src)
   132  	return &adt.Conjunction{
   133  		Src: src,
   134  		Values: []adt.Value{
   135  			&adt.BasicType{Src: ident, K: adt.IntKind}, from, to,
   136  		},
   137  	}
   138  }
   139  
   140  func mkFloatRange(a, b string) adt.Expr {
   141  	from := newBound(adt.GreaterEqualOp, adt.NumKind, parseFloat(a))
   142  	to := newBound(adt.LessEqualOp, adt.NumKind, parseFloat(b))
   143  	src := ast.NewBinExpr(token.AND, from.Src, to.Src)
   144  	return &adt.Conjunction{Src: src, Values: []adt.Value{from, to}}
   145  }
   146  
   147  func newBound(op adt.Op, k adt.Kind, v adt.Value) *adt.BoundValue {
   148  	src := &ast.UnaryExpr{Op: op.Token(), X: v.Source().(ast.Expr)}
   149  	return &adt.BoundValue{Src: src, Op: op, Value: v}
   150  }
   151  
   152  func parseInt(s string) *adt.Num {
   153  	n := parseNum(adt.IntKind, s)
   154  	n.Src = &ast.BasicLit{Kind: token.INT, Value: s}
   155  	return n
   156  }
   157  
   158  func parseFloat(s string) *adt.Num {
   159  	n := parseNum(adt.FloatKind, s)
   160  	n.Src = &ast.BasicLit{Kind: token.FLOAT, Value: s}
   161  	return n
   162  }
   163  
   164  func parseNum(k adt.Kind, s string) *adt.Num {
   165  	num := &adt.Num{K: k}
   166  	_, _, err := num.X.SetString(s)
   167  	if err != nil {
   168  		panic(err)
   169  	}
   170  	return num
   171  }