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