| // Copyright 2020 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 compile |
| |
| import ( |
| "strconv" |
| |
| "cuelang.org/go/cue/ast" |
| "cuelang.org/go/cue/token" |
| "cuelang.org/go/internal/core/adt" |
| ) |
| |
| func predeclared(n *ast.Ident) adt.Expr { |
| // TODO: consider supporting GraphQL-style names: |
| // String, Bytes, Boolean, Integer, Number. |
| // These names will not conflict with idiomatic camel-case JSON. |
| switch n.Name { |
| case "_": |
| return &adt.Top{Src: n} |
| case "string", "__string": |
| return &adt.BasicType{Src: n, K: adt.StringKind} |
| case "bytes", "__bytes": |
| return &adt.BasicType{Src: n, K: adt.BytesKind} |
| case "bool", "__bool": |
| return &adt.BasicType{Src: n, K: adt.BoolKind} |
| case "int", "__int": |
| return &adt.BasicType{Src: n, K: adt.IntKind} |
| case "float", "__float": |
| return &adt.BasicType{Src: n, K: adt.FloatKind} |
| case "number", "__number": |
| return &adt.BasicType{Src: n, K: adt.NumKind} |
| |
| case "len", "__len": |
| return lenBuiltin |
| case "close", "__close": |
| return closeBuiltin |
| case "and", "__and": |
| return andBuiltin |
| case "or", "__or": |
| return orBuiltin |
| case "div", "__div": |
| return divBuiltin |
| case "mod", "__mod": |
| return modBuiltin |
| case "quo", "__quo": |
| return quoBuiltin |
| case "rem", "__rem": |
| return remBuiltin |
| } |
| |
| if r, ok := predefinedRanges[n.Name]; ok { |
| return r |
| } |
| |
| return nil |
| } |
| |
| // LookupRange returns a CUE expressions for the given predeclared identifier |
| // representing a range, such as uint8, int128, and float64. |
| func LookupRange(name string) adt.Expr { |
| return predefinedRanges[name] |
| } |
| |
| var predefinedRanges = map[string]adt.Expr{ |
| "rune": mkIntRange("0", strconv.Itoa(0x10FFFF)), |
| "int8": mkIntRange("-128", "127"), |
| "int16": mkIntRange("-32768", "32767"), |
| "int32": mkIntRange("-2147483648", "2147483647"), |
| "int64": mkIntRange("-9223372036854775808", "9223372036854775807"), |
| "int128": mkIntRange( |
| "-170141183460469231731687303715884105728", |
| "170141183460469231731687303715884105727"), |
| |
| // Do not include an alias for "byte", as it would be too easily confused |
| // with the builtin "bytes". |
| "uint": mkUint(), |
| "uint8": mkIntRange("0", "255"), |
| "uint16": mkIntRange("0", "65535"), |
| "uint32": mkIntRange("0", "4294967295"), |
| "uint64": mkIntRange("0", "18446744073709551615"), |
| "uint128": mkIntRange("0", "340282366920938463463374607431768211455"), |
| |
| // 2**127 * (2**24 - 1) / 2**23 |
| "float32": mkFloatRange( |
| "-3.40282346638528859811704183484516925440e+38", |
| "3.40282346638528859811704183484516925440e+38", |
| ), |
| // 2**1023 * (2**53 - 1) / 2**52 |
| "float64": mkFloatRange( |
| "-1.797693134862315708145274237317043567981e+308", |
| "1.797693134862315708145274237317043567981e+308", |
| ), |
| } |
| |
| func init() { |
| for k, v := range predefinedRanges { |
| predefinedRanges["__"+k] = v |
| } |
| } |
| |
| // TODO: use an adt.BoundValue here. and conjunctions here. |
| |
| func mkUint() adt.Expr { |
| from := newBound(adt.GreaterEqualOp, adt.IntKind, parseInt("0")) |
| ident := ast.NewIdent("__int") |
| src := ast.NewBinExpr(token.AND, ident, from.Src) |
| return &adt.Conjunction{ |
| Src: src, |
| Values: []adt.Value{ |
| &adt.BasicType{Src: ident, K: adt.IntKind}, from, |
| }, |
| } |
| } |
| |
| func mkIntRange(a, b string) adt.Expr { |
| from := newBound(adt.GreaterEqualOp, adt.IntKind, parseInt(a)) |
| to := newBound(adt.LessEqualOp, adt.IntKind, parseInt(b)) |
| ident := ast.NewIdent("__int") |
| src := ast.NewBinExpr(token.AND, ident, from.Src, to.Src) |
| return &adt.Conjunction{ |
| Src: src, |
| Values: []adt.Value{ |
| &adt.BasicType{Src: ident, K: adt.IntKind}, from, to, |
| }, |
| } |
| } |
| |
| func mkFloatRange(a, b string) adt.Expr { |
| from := newBound(adt.GreaterEqualOp, adt.NumKind, parseFloat(a)) |
| to := newBound(adt.LessEqualOp, adt.NumKind, parseFloat(b)) |
| src := ast.NewBinExpr(token.AND, from.Src, to.Src) |
| return &adt.Conjunction{Src: src, Values: []adt.Value{from, to}} |
| } |
| |
| func newBound(op adt.Op, k adt.Kind, v adt.Value) *adt.BoundValue { |
| src := &ast.UnaryExpr{Op: op.Token(), X: v.Source().(ast.Expr)} |
| return &adt.BoundValue{Src: src, Op: op, Value: v} |
| } |
| |
| func parseInt(s string) *adt.Num { |
| n := parseNum(adt.IntKind, s) |
| n.Src = &ast.BasicLit{Kind: token.INT, Value: s} |
| return n |
| } |
| |
| func parseFloat(s string) *adt.Num { |
| n := parseNum(adt.FloatKind, s) |
| n.Src = &ast.BasicLit{Kind: token.FLOAT, Value: s} |
| return n |
| } |
| |
| func parseNum(k adt.Kind, s string) *adt.Num { |
| num := &adt.Num{K: k} |
| _, _, err := num.X.SetString(s) |
| if err != nil { |
| panic(err) |
| } |
| return num |
| } |