this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

pkg/internal: copy cue builtin code to separate package

Mostly a copy and reorg. Contain minor modifications
to make it compile.

Adds Register function to facilitate registring.

Change-Id: I1494f9f057130277e82cb62d04973488de916473
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6884
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>

+609
+212
pkg/internal/builtin.go
··· 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 internal 16 + 17 + import ( 18 + "encoding/json" 19 + "fmt" 20 + 21 + "cuelang.org/go/cue/errors" 22 + "cuelang.org/go/cue/parser" 23 + "cuelang.org/go/cue/token" 24 + "cuelang.org/go/internal" 25 + "cuelang.org/go/internal/core/adt" 26 + "cuelang.org/go/internal/core/compile" 27 + "cuelang.org/go/internal/core/convert" 28 + ) 29 + 30 + // A Builtin is a Builtin function or constant. 31 + // 32 + // A function may return and a constant may be any of the following types: 33 + // 34 + // error (translates to bottom) 35 + // nil (translates to null) 36 + // bool 37 + // int* 38 + // uint* 39 + // float64 40 + // string 41 + // *big.Float 42 + // *big.Int 43 + // 44 + // For any of the above, including interface{} and these types recursively: 45 + // []T 46 + // map[string]T 47 + // 48 + type Builtin struct { 49 + Name string 50 + Pkg adt.Feature 51 + Params []adt.Kind 52 + Result adt.Kind 53 + Func func(c *CallCtxt) 54 + Const string 55 + } 56 + 57 + type Package struct { 58 + Native []*Builtin 59 + CUE string 60 + } 61 + 62 + func (p *Package) MustCompile(ctx *adt.OpContext, pkgName string) *adt.Vertex { 63 + obj := &adt.Vertex{} 64 + pkgLabel := ctx.StringLabel(pkgName) 65 + st := &adt.StructLit{} 66 + if len(p.Native) > 0 { 67 + obj.AddConjunct(adt.MakeConjunct(nil, st)) 68 + } 69 + for _, b := range p.Native { 70 + b.Pkg = pkgLabel 71 + 72 + f := ctx.StringLabel(b.Name) // never starts with _ 73 + // n := &node{baseValue: newBase(imp.Path)} 74 + var v adt.Expr = toBuiltin(ctx, b) 75 + if b.Const != "" { 76 + v = mustParseConstBuiltin(ctx, b.Name, b.Const) 77 + } 78 + st.Decls = append(st.Decls, &adt.Field{ 79 + Label: f, 80 + Value: v, 81 + }) 82 + } 83 + 84 + // Parse builtin CUE 85 + if p.CUE != "" { 86 + expr, err := parser.ParseExpr(pkgName, p.CUE) 87 + if err != nil { 88 + panic(fmt.Errorf("could not parse %v: %v", p.CUE, err)) 89 + } 90 + c, err := compile.Expr(nil, ctx.Runtime, expr) 91 + if err != nil { 92 + panic(fmt.Errorf("could compile parse %v: %v", p.CUE, err)) 93 + } 94 + obj.AddConjunct(c) 95 + } 96 + 97 + // We could compile lazily, but this is easier for debugging. 98 + obj.Finalize(ctx) 99 + if err := obj.Err(ctx, adt.Finalized); err != nil { 100 + panic(err.Err) 101 + } 102 + 103 + return obj 104 + } 105 + 106 + func toBuiltin(ctx *adt.OpContext, b *Builtin) *adt.Builtin { 107 + x := &adt.Builtin{ 108 + Params: b.Params, 109 + Result: b.Result, 110 + Package: b.Pkg, 111 + Name: b.Name, 112 + } 113 + x.Func = func(ctx *adt.OpContext, args []adt.Value) (ret adt.Expr) { 114 + // call, _ := ctx.Source().(*ast.CallExpr) 115 + c := &CallCtxt{ 116 + // src: call, 117 + ctx: ctx, 118 + args: args, 119 + builtin: b, 120 + } 121 + defer func() { 122 + var errVal interface{} = c.Err 123 + if err := recover(); err != nil { 124 + errVal = err 125 + } 126 + ret = processErr(c, errVal, ret) 127 + }() 128 + b.Func(c) 129 + switch v := c.Ret.(type) { 130 + case adt.Value: 131 + return v 132 + case bottomer: 133 + return v.Bottom() 134 + } 135 + if c.Err != nil { 136 + return nil 137 + } 138 + return convert.GoValueToValue(ctx, c.Ret, true) 139 + } 140 + return x 141 + } 142 + 143 + // newConstBuiltin parses and creates any CUE expression that does not have 144 + // fields. 145 + func mustParseConstBuiltin(ctx adt.Runtime, name, val string) adt.Expr { 146 + expr, err := parser.ParseExpr("<builtin:"+name+">", val) 147 + if err != nil { 148 + panic(err) 149 + } 150 + c, err := compile.Expr(nil, ctx, expr) 151 + if err != nil { 152 + panic(err) 153 + } 154 + return c.Expr() 155 + 156 + } 157 + 158 + func pos(n adt.Node) (p token.Pos) { 159 + if n == nil { 160 + return 161 + } 162 + src := n.Source() 163 + if src == nil { 164 + return 165 + } 166 + return src.Pos() 167 + } 168 + 169 + func (x *Builtin) name(ctx *adt.OpContext) string { 170 + if x.Pkg == 0 { 171 + return x.Name 172 + } 173 + return fmt.Sprintf("%s.%s", x.Pkg.StringValue(ctx), x.Name) 174 + } 175 + 176 + func (x *Builtin) isValidator() bool { 177 + return len(x.Params) == 1 && x.Result == adt.BoolKind 178 + } 179 + 180 + func processErr(call *CallCtxt, errVal interface{}, ret adt.Expr) adt.Expr { 181 + ctx := call.ctx 182 + switch err := errVal.(type) { 183 + case nil: 184 + case *callError: 185 + ret = err.b 186 + case *json.MarshalerError: 187 + if err, ok := err.Err.(bottomer); ok { 188 + if b := err.Bottom(); b != nil { 189 + ret = b 190 + } 191 + } 192 + case bottomer: 193 + ret = wrapCallErr(call, err.Bottom()) 194 + case errors.Error: 195 + ret = wrapCallErr(call, &adt.Bottom{Err: err}) 196 + case error: 197 + if call.Err == internal.ErrIncomplete { 198 + err := ctx.NewErrf("incomplete value") 199 + err.Code = adt.IncompleteError 200 + ret = err 201 + } else { 202 + // TODO: store the underlying error explicitly 203 + ret = wrapCallErr(call, &adt.Bottom{Err: errors.Promote(err, "")}) 204 + } 205 + default: 206 + // Likely a string passed to panic. 207 + ret = wrapCallErr(call, &adt.Bottom{ 208 + Err: errors.Newf(call.Pos(), "%s", err), 209 + }) 210 + } 211 + return ret 212 + }
+269
pkg/internal/context.go
··· 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 internal 16 + 17 + import ( 18 + "io" 19 + "math/big" 20 + 21 + "cuelang.org/go/cue" 22 + "cuelang.org/go/cue/errors" 23 + "cuelang.org/go/cue/token" 24 + "cuelang.org/go/internal/core/adt" 25 + "github.com/cockroachdb/apd/v2" 26 + ) 27 + 28 + // CallCtxt is passed to builtin implementations that need to use a cue.Value. This is an internal type. It's interface may change. 29 + type CallCtxt struct { 30 + src adt.Expr 31 + ctx *adt.OpContext 32 + builtin *Builtin 33 + Err interface{} 34 + Ret interface{} 35 + 36 + args []adt.Value 37 + } 38 + 39 + func (c *CallCtxt) Pos() token.Pos { 40 + return c.ctx.Pos() 41 + } 42 + 43 + func (c *CallCtxt) Name() string { 44 + return c.builtin.name(c.ctx) 45 + } 46 + 47 + // Do returns whether the call should be done. 48 + func (c *CallCtxt) Do() bool { 49 + return c.Err == nil 50 + } 51 + 52 + func (c *CallCtxt) Value(i int) cue.Value { 53 + v := cue.MakeValue(c.ctx, c.args[i]) 54 + // TODO: remove default 55 + // v, _ = v.Default() 56 + if !v.IsConcrete() { 57 + c.errcf(c.src, adt.IncompleteError, "non-concrete argument %d", i) 58 + } 59 + return v 60 + } 61 + 62 + func (c *CallCtxt) Struct(i int) *cue.Struct { 63 + v := cue.MakeValue(c.ctx, c.args[i]) 64 + s, err := v.Struct() 65 + if err != nil { 66 + c.invalidArgType(c.args[i], i, "struct", err) 67 + return nil 68 + } 69 + return s 70 + } 71 + 72 + func (c *CallCtxt) Int(i int) int { return int(c.intValue(i, 64, "int64")) } 73 + func (c *CallCtxt) Int8(i int) int8 { return int8(c.intValue(i, 8, "int8")) } 74 + func (c *CallCtxt) Int16(i int) int16 { return int16(c.intValue(i, 16, "int16")) } 75 + func (c *CallCtxt) Int32(i int) int32 { return int32(c.intValue(i, 32, "int32")) } 76 + func (c *CallCtxt) Rune(i int) rune { return rune(c.intValue(i, 32, "rune")) } 77 + func (c *CallCtxt) Int64(i int) int64 { return int64(c.intValue(i, 64, "int64")) } 78 + 79 + func (c *CallCtxt) intValue(i, bits int, typ string) int64 { 80 + arg := c.args[i] 81 + x := cue.MakeValue(c.ctx, arg) 82 + n, err := x.Int(nil) 83 + if err != nil { 84 + c.invalidArgType(arg, i, typ, err) 85 + return 0 86 + } 87 + if n.BitLen() > bits { 88 + c.errf(c.src, err, "int %s overflows %s in argument %d in call to %s", 89 + n, typ, i, c.Name()) 90 + } 91 + res, _ := x.Int64() 92 + return res 93 + } 94 + 95 + func (c *CallCtxt) Uint(i int) uint { return uint(c.uintValue(i, 64, "uint64")) } 96 + func (c *CallCtxt) Uint8(i int) uint8 { return uint8(c.uintValue(i, 8, "uint8")) } 97 + func (c *CallCtxt) Byte(i int) uint8 { return byte(c.uintValue(i, 8, "byte")) } 98 + func (c *CallCtxt) Uint16(i int) uint16 { return uint16(c.uintValue(i, 16, "uint16")) } 99 + func (c *CallCtxt) Uint32(i int) uint32 { return uint32(c.uintValue(i, 32, "uint32")) } 100 + func (c *CallCtxt) Uint64(i int) uint64 { return uint64(c.uintValue(i, 64, "uint64")) } 101 + 102 + func (c *CallCtxt) uintValue(i, bits int, typ string) uint64 { 103 + x := cue.MakeValue(c.ctx, c.args[i]) 104 + n, err := x.Int(nil) 105 + if err != nil || n.Sign() < 0 { 106 + c.invalidArgType(c.args[i], i, typ, err) 107 + return 0 108 + } 109 + if n.BitLen() > bits { 110 + c.errf(c.src, err, "int %s overflows %s in argument %d in call to %s", 111 + n, typ, i, c.Name()) 112 + } 113 + res, _ := x.Uint64() 114 + return res 115 + } 116 + 117 + func (c *CallCtxt) Decimal(i int) *apd.Decimal { 118 + x := cue.MakeValue(c.ctx, c.args[i]) 119 + if _, err := x.MantExp(nil); err != nil { 120 + c.invalidArgType(c.args[i], i, "Decimal", err) 121 + return nil 122 + } 123 + return &c.args[i].(*adt.Num).X 124 + } 125 + 126 + func (c *CallCtxt) Float64(i int) float64 { 127 + x := cue.MakeValue(c.ctx, c.args[i]) 128 + res, err := x.Float64() 129 + if err != nil { 130 + c.invalidArgType(c.args[i], i, "float64", err) 131 + return 0 132 + } 133 + return res 134 + } 135 + 136 + func (c *CallCtxt) BigInt(i int) *big.Int { 137 + x := cue.MakeValue(c.ctx, c.args[i]) 138 + n, err := x.Int(nil) 139 + if err != nil { 140 + c.invalidArgType(c.args[i], i, "int", err) 141 + return nil 142 + } 143 + return n 144 + } 145 + 146 + var ten = big.NewInt(10) 147 + 148 + func (c *CallCtxt) BigFloat(i int) *big.Float { 149 + x := cue.MakeValue(c.ctx, c.args[i]) 150 + var mant big.Int 151 + exp, err := x.MantExp(&mant) 152 + if err != nil { 153 + c.invalidArgType(c.args[i], i, "float", err) 154 + return nil 155 + } 156 + f := &big.Float{} 157 + f.SetInt(&mant) 158 + if exp != 0 { 159 + var g big.Float 160 + e := big.NewInt(int64(exp)) 161 + f.Mul(f, g.SetInt(e.Exp(ten, e, nil))) 162 + } 163 + return f 164 + } 165 + 166 + func (c *CallCtxt) String(i int) string { 167 + x := cue.MakeValue(c.ctx, c.args[i]) 168 + v, err := x.String() 169 + if err != nil { 170 + c.invalidArgType(c.args[i], i, "string", err) 171 + return "" 172 + } 173 + return v 174 + } 175 + 176 + func (c *CallCtxt) Bytes(i int) []byte { 177 + x := cue.MakeValue(c.ctx, c.args[i]) 178 + v, err := x.Bytes() 179 + if err != nil { 180 + c.invalidArgType(c.args[i], i, "bytes", err) 181 + return nil 182 + } 183 + return v 184 + } 185 + 186 + func (c *CallCtxt) Reader(i int) io.Reader { 187 + x := cue.MakeValue(c.ctx, c.args[i]) 188 + // TODO: optimize for string and bytes cases 189 + r, err := x.Reader() 190 + if err != nil { 191 + c.invalidArgType(c.args[i], i, "bytes|string", err) 192 + return nil 193 + } 194 + return r 195 + } 196 + 197 + func (c *CallCtxt) Bool(i int) bool { 198 + x := cue.MakeValue(c.ctx, c.args[i]) 199 + b, err := x.Bool() 200 + if err != nil { 201 + c.invalidArgType(c.args[i], i, "bool", err) 202 + return false 203 + } 204 + return b 205 + } 206 + 207 + func (c *CallCtxt) List(i int) (a []cue.Value) { 208 + arg := c.args[i] 209 + x := cue.MakeValue(c.ctx, arg) 210 + v, err := x.List() 211 + if err != nil { 212 + c.invalidArgType(c.args[i], i, "list", err) 213 + return a 214 + } 215 + for v.Next() { 216 + a = append(a, v.Value()) 217 + } 218 + return a 219 + } 220 + 221 + func (c *CallCtxt) Iter(i int) (a cue.Iterator) { 222 + arg := c.args[i] 223 + x := cue.MakeValue(c.ctx, arg) 224 + v, err := x.List() 225 + if err != nil { 226 + c.invalidArgType(c.args[i], i, "list", err) 227 + } 228 + return v 229 + } 230 + 231 + func (c *CallCtxt) DecimalList(i int) (a []*apd.Decimal) { 232 + arg := c.args[i] 233 + x := cue.MakeValue(c.ctx, arg) 234 + v, err := x.List() 235 + if err != nil { 236 + c.invalidArgType(c.args[i], i, "list", err) 237 + return nil 238 + } 239 + for j := 0; v.Next(); j++ { 240 + num, err := v.Value().Decimal() 241 + if err != nil { 242 + c.errf(c.src, err, "invalid list element %d in argument %d to %s: %v", 243 + j, i, c.Name(), err) 244 + break 245 + } 246 + a = append(a, num) 247 + } 248 + return a 249 + } 250 + 251 + func (c *CallCtxt) StringList(i int) (a []string) { 252 + arg := c.args[i] 253 + x := cue.MakeValue(c.ctx, arg) 254 + v, err := x.List() 255 + if err != nil { 256 + c.invalidArgType(c.args[i], i, "list", err) 257 + return nil 258 + } 259 + for j := 0; v.Next(); j++ { 260 + str, err := v.Value().String() 261 + if err != nil { 262 + c.Err = errors.Wrapf(err, c.Pos(), 263 + "element %d of list argument %d", j, i) 264 + break 265 + } 266 + a = append(a, str) 267 + } 268 + return a 269 + }
+128
pkg/internal/errors.go
··· 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 internal 16 + 17 + import ( 18 + "encoding/json" 19 + "fmt" 20 + 21 + "cuelang.org/go/cue/errors" 22 + "cuelang.org/go/cue/token" 23 + "cuelang.org/go/internal" 24 + "cuelang.org/go/internal/core/adt" 25 + ) 26 + 27 + type bottomer interface { 28 + error 29 + Bottom() *adt.Bottom 30 + } 31 + 32 + type callError struct { 33 + b *adt.Bottom 34 + } 35 + 36 + func (e *callError) Error() string { 37 + return fmt.Sprint(e.b) 38 + } 39 + 40 + func (c *CallCtxt) errf(src adt.Node, underlying error, format string, args ...interface{}) { 41 + var errs errors.Error 42 + if err, ok := underlying.(bottomer); ok { 43 + errs = err.Bottom().Err 44 + } 45 + errs = errors.Wrapf(errs, c.ctx.Pos(), format, args...) 46 + c.Err = &callError{&adt.Bottom{Err: errs}} 47 + } 48 + 49 + func (c *CallCtxt) errcf(src adt.Node, code adt.ErrorCode, format string, args ...interface{}) { 50 + err := c.ctx.NewErrf(format, args...) 51 + err.Code = code 52 + c.Err = &callError{err} 53 + } 54 + 55 + func wrapCallErr(c *CallCtxt, b *adt.Bottom) *adt.Bottom { 56 + pos := token.NoPos 57 + if c.src != nil { 58 + if src := c.src.Source(); src != nil { 59 + pos = src.Pos() 60 + } 61 + } 62 + const msg = "error in call to %s" 63 + return &adt.Bottom{ 64 + Code: b.Code, 65 + Err: errors.Wrapf(b.Err, pos, msg, c.builtin.name(c.ctx)), 66 + } 67 + } 68 + 69 + func (c *CallCtxt) convertError(x interface{}, name string) *adt.Bottom { 70 + var err errors.Error 71 + switch v := x.(type) { 72 + case nil: 73 + return nil 74 + 75 + case *adt.Bottom: 76 + return v 77 + 78 + case *json.MarshalerError: 79 + err = errors.Promote(v, "marshal error") 80 + 81 + case errors.Error: 82 + err = v 83 + 84 + case error: 85 + if name != "" { 86 + err = errors.Newf(c.Pos(), "%s: %v", name, v) 87 + } else { 88 + err = errors.Newf(c.Pos(), "error in call to %s: %v", c.Name(), v) 89 + } 90 + 91 + default: 92 + err = errors.Newf(token.NoPos, "%s", name) 93 + } 94 + if err != internal.ErrIncomplete { 95 + return &adt.Bottom{ 96 + // Wrap to preserve position information. 97 + Err: errors.Wrapf(err, c.Pos(), "error in call to %s", c.Name()), 98 + } 99 + } 100 + return &adt.Bottom{ 101 + Code: adt.IncompleteError, 102 + Err: errors.Newf(c.Pos(), "incomplete values in call to %s", c.Name()), 103 + } 104 + } 105 + 106 + func (c *CallCtxt) invalidArgType(arg adt.Expr, i int, typ string, err error) { 107 + if ve, ok := err.(bottomer); ok && ve.Bottom().IsIncomplete() { 108 + c.Err = ve 109 + return 110 + } 111 + v, ok := arg.(adt.Value) 112 + // TODO: make these permanent errors if the value did not originate from 113 + // a reference. 114 + if !ok { 115 + c.errf(c.src, nil, 116 + "cannot use incomplete value %s as %s in argument %d to %s: %v", 117 + c.ctx.Str(arg), typ, i, c.Name(), err) 118 + } 119 + if err != nil { 120 + c.errf(c.src, err, 121 + "cannot use %s (type %s) as %s in argument %d to %s: %v", 122 + c.ctx.Str(arg), v.Kind(), typ, i, c.Name(), err) 123 + } else { 124 + c.errf(c.src, err, 125 + "cannot use %s (type %s) as %s in argument %d to %s", 126 + c.ctx.Str(arg), v.Kind(), typ, i, c.Name()) 127 + } 128 + }