blob: 72f466d25f5b98a9eb6ba7a32405c19942ae6547 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// 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
Marcel van Lohuizen7b5d2fd2018-12-11 16:34:56 +010015//go:generate go run gen.go
Marcel van Lohuizend4847d92019-02-18 23:27:34 +010016//go:generate goimports -w builtins.go
Marcel van Lohuizen7b5d2fd2018-12-11 16:34:56 +010017
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010018package cue
19
20import (
21 "fmt"
22 "io"
23 "math/big"
24 "path"
25 "reflect"
26 "sort"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010027 "strings"
28
29 "cuelang.org/go/cue/ast"
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +020030 "cuelang.org/go/cue/parser"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010031 "github.com/cockroachdb/apd"
32)
33
34// A builtin is a builtin function or constant.
35//
36// A function may return and a constant may be any of the following types:
37//
38// error (translates to bottom)
39// nil (translates to null)
40// bool
41// int*
42// uint*
43// float64
44// string
45// *big.Float
46// *big.Int
47//
48// For any of the above, including interface{} and these types recursively:
49// []T
50// map[string]T
51//
52type builtin struct {
53 baseValue
54 Name string
55 Params []kind
56 Result kind
57 Func func(c *callCtxt)
58 // Const interface{}
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +020059 Const string
60}
61
Marcel van Lohuizen57333362019-04-01 14:35:09 +020062type builtinPkg struct {
63 native []*builtin
64 cue string
65}
66
67func mustCompileBuiltins(ctx *context, p *builtinPkg) *structLit {
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +020068 obj := &structLit{}
Marcel van Lohuizen57333362019-04-01 14:35:09 +020069 for _, b := range p.native {
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +020070 f := ctx.label(b.Name, false) // never starts with _
71 // n := &node{baseValue: newBase(imp.Path)}
72 var v evaluated = b
73 if b.Const != "" {
74 v = mustParseConstBuiltin(ctx, b.Name, b.Const)
75 }
76 obj.arcs = append(obj.arcs, arc{feature: f, v: v})
77 }
78 sort.Sort(obj)
Marcel van Lohuizen57333362019-04-01 14:35:09 +020079
80 // Parse builtin CUE
81 if p.cue != "" {
82 expr, err := parser.ParseExpr(ctx.index.fset, "<builtinPkg>", p.cue)
83 if err != nil {
84 fmt.Println(p.cue)
85 panic(err)
86 }
87 pkg := evalExpr(ctx.index, obj, expr).(*structLit)
88 for _, a := range pkg.arcs {
89 // Discard option status and attributes at top level.
90 // TODO: filter on capitalized fields?
91 obj.insertValue(ctx, a.feature, false, a.v, nil)
92 }
93 }
94
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +020095 return obj
96}
97
98// newConstBuiltin parses and creates any CUE expression that does not have
99// fields.
100func mustParseConstBuiltin(ctx *context, name, val string) evaluated {
101 expr, err := parser.ParseExpr(ctx.index.fset, "<builtin:"+name+">", val)
102 if err != nil {
103 panic(err)
104 }
105 v := newVisitor(ctx.index, nil, nil, nil)
106 value := v.walk(expr)
107 return value.evalPartial(ctx)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100108}
109
110var _ caller = &builtin{}
111
112var lenBuiltin = &builtin{
113 Name: "len",
114 Params: []kind{stringKind | bytesKind | listKind | structKind},
115 Result: intKind,
116 Func: func(c *callCtxt) {
117 v := c.value(0)
118 switch v.Kind() {
119 case StructKind:
120 s, _ := v.structVal(c.ctx)
121 c.ret = s.Len()
122 case ListKind:
123 i := 0
124 iter, _ := v.List()
125 for ; iter.Next(); i++ {
126 }
127 c.ret = i
128 case BytesKind:
129 b, _ := v.Bytes()
130 c.ret = len(b)
131 case StringKind:
132 s, _ := v.String()
133 c.ret = len(s)
134 }
135 },
136}
137
138func (x *builtin) kind() kind {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100139 return lambdaKind
140}
141
142func (x *builtin) evalPartial(ctx *context) evaluated {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100143 return x
144}
145
146func (x *builtin) subsumesImpl(ctx *context, v value, mode subsumeMode) bool {
147 if y, ok := v.(*builtin); ok {
148 return x == y
149 }
150 return false
151}
152
153func (x *builtin) call(ctx *context, src source, args ...evaluated) (ret value) {
154 if x.Func == nil {
155 return ctx.mkErr(x, "Builtin %q is not a function", x.Name)
156 }
157 if len(x.Params) != len(args) {
158 return ctx.mkErr(src, x, "number of arguments does not match (%d vs %d)",
159 len(x.Params), len(args))
160 }
161 for i, a := range args {
162 if x.Params[i] != bottomKind {
163 if unifyType(x.Params[i], a.kind()) == bottomKind {
164 return ctx.mkErr(src, x, "argument %d requires type %v, found %v", i+1, x.Params[i], a.kind())
165 }
166 }
167 }
168 call := callCtxt{src: src, ctx: ctx, args: args}
169 defer func() {
170 var errVal interface{} = call.err
171 if err := recover(); err != nil {
172 errVal = err
173 }
174 switch err := errVal.(type) {
175 case nil:
176 case *bottom:
177 ret = err
178 default:
179 ret = ctx.mkErr(src, x, "call error: %v", err)
180 }
181 }()
182 x.Func(&call)
183 return convert(ctx, x, call.ret)
184}
185
186// callCtxt is passed to builtin implementations.
187type callCtxt struct {
188 src source
189 ctx *context
190 args []evaluated
191 err error
192 ret interface{}
193}
194
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +0200195var builtins = map[string]*structLit{}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100196
Marcel van Lohuizen57333362019-04-01 14:35:09 +0200197func initBuiltins(pkgs map[string]*builtinPkg) {
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +0200198 ctx := sharedIndex.newContext()
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100199 for k, b := range pkgs {
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +0200200 e := mustCompileBuiltins(ctx, b)
201 builtins[k] = e
202 builtins["-/"+path.Base(k)] = e
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100203 }
204}
205
206func getBuiltinShorthandPkg(ctx *context, shorthand string) *structLit {
207 return getBuiltinPkg(ctx, "-/"+shorthand)
208}
209
210func getBuiltinPkg(ctx *context, path string) *structLit {
211 p, ok := builtins[path]
212 if !ok {
213 return nil
214 }
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +0200215 return p
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100216}
217
218// do returns whether the call should be done.
219func (c *callCtxt) do() bool {
220 return c.err == nil
221}
222
223func (c *callCtxt) value(i int) Value {
224 return newValueRoot(c.ctx, c.args[i])
225}
226
227func (c *callCtxt) int(i int) int { return int(c.intValue(i, 64)) }
228func (c *callCtxt) int8(i int) int8 { return int8(c.intValue(i, 8)) }
229func (c *callCtxt) int16(i int) int16 { return int16(c.intValue(i, 16)) }
230func (c *callCtxt) int32(i int) int32 { return int32(c.intValue(i, 32)) }
231func (c *callCtxt) rune(i int) rune { return rune(c.intValue(i, 32)) }
232func (c *callCtxt) int64(i int) int64 { return int64(c.intValue(i, 64)) }
233
234func (c *callCtxt) intValue(i, bits int) int64 {
235 x := newValueRoot(c.ctx, c.args[i])
236 n, err := x.Int(nil)
237 if err != nil {
238 c.err = c.ctx.mkErr(c.src, "argument %d must be in int, found number", i)
239 return 0
240 }
241 if n.BitLen() > bits {
242 c.err = c.ctx.mkErr(c.src, err, "argument %d out of range: has %d > %d bits", n.BitLen(), bits)
243 }
244 res, _ := x.Int64()
245 return res
246}
247
248func (c *callCtxt) uint(i int) uint { return uint(c.uintValue(i, 64)) }
249func (c *callCtxt) uint8(i int) uint8 { return uint8(c.uintValue(i, 8)) }
250func (c *callCtxt) byte(i int) uint8 { return byte(c.uintValue(i, 8)) }
251func (c *callCtxt) uint16(i int) uint16 { return uint16(c.uintValue(i, 16)) }
252func (c *callCtxt) uint32(i int) uint32 { return uint32(c.uintValue(i, 32)) }
253func (c *callCtxt) uint64(i int) uint64 { return uint64(c.uintValue(i, 64)) }
254
255func (c *callCtxt) uintValue(i, bits int) uint64 {
256 x := newValueRoot(c.ctx, c.args[i])
257 n, err := x.Int(nil)
258 if err != nil {
259 c.err = c.ctx.mkErr(c.src, "argument %d must be an integer", i)
260 return 0
261 }
262 if n.Sign() < 0 {
263 c.err = c.ctx.mkErr(c.src, "argument %d must be a positive integer", i)
264 return 0
265 }
266 if n.BitLen() > bits {
267 c.err = c.ctx.mkErr(c.src, err, "argument %d out of range: has %d > %d bits", i, n.BitLen(), bits)
268 }
269 res, _ := x.Uint64()
270 return res
271}
272
273func (c *callCtxt) float64(i int) float64 {
274 x := newValueRoot(c.ctx, c.args[i])
275 res, err := x.Float64()
276 if err != nil {
277 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
278 return 0
279 }
280 return res
281}
282
283func (c *callCtxt) bigInt(i int) *big.Int {
284 x := newValueRoot(c.ctx, c.args[i])
285 n, err := x.Int(nil)
286 if err != nil {
287 c.err = c.ctx.mkErr(c.src, "argument %d must be in int, found number", i)
288 return nil
289 }
290 return n
291}
292
293func (c *callCtxt) bigFloat(i int) *big.Float {
294 x := newValueRoot(c.ctx, c.args[i])
295 var mant big.Int
296 exp, err := x.MantExp(&mant)
297 if err != nil {
298 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
299 return nil
300 }
301 f := &big.Float{}
302 f.SetInt(&mant)
303 if exp != 0 {
304 var g big.Float
305 e := big.NewInt(int64(exp))
306 f.Mul(f, g.SetInt(e.Exp(ten, e, nil)))
307 }
308 return f
309}
310
311func (c *callCtxt) string(i int) string {
312 x := newValueRoot(c.ctx, c.args[i])
313 v, err := x.String()
314 if err != nil {
315 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
316 return ""
317 }
318 return v
319}
320
321func (c *callCtxt) bytes(i int) []byte {
322 x := newValueRoot(c.ctx, c.args[i])
323 v, err := x.Bytes()
324 if err != nil {
325 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
326 return nil
327 }
328 return v
329}
330
331func (c *callCtxt) reader(i int) io.Reader {
332 x := newValueRoot(c.ctx, c.args[i])
333 // TODO: optimize for string and bytes cases
334 r, err := x.Reader()
335 if err != nil {
336 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
337 return nil
338 }
339 return r
340}
341
342func (c *callCtxt) bool(i int) bool {
343 x := newValueRoot(c.ctx, c.args[i])
344 b, err := x.Bool()
345 if err != nil {
346 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
347 return false
348 }
349 return b
350}
351
352func (c *callCtxt) error(i int) error {
353 x := newValueRoot(c.ctx, c.args[i])
354 return x.Err()
355}
356
357func (c *callCtxt) list(i int) (a Iterator) {
358 x := newValueRoot(c.ctx, c.args[i])
359 v, err := x.List()
360 if err != nil {
361 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
362 return Iterator{ctx: c.ctx}
363 }
364 return v
365}
366
367func (c *callCtxt) strList(i int) (a []string) {
368 x := newValueRoot(c.ctx, c.args[i])
369 v, err := x.List()
370 if err != nil {
371 c.err = c.ctx.mkErr(c.src, err, "invalid argument %d: %v", i, err)
372 return nil
373 }
374 for i := 0; v.Next(); i++ {
375 str, err := v.Value().String()
376 if err != nil {
377 c.err = c.ctx.mkErr(c.src, err, "list element %d: %v", i, err)
378 }
379 a = append(a, str)
380 }
381 return a
382}
383
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100384func convert(ctx *context, src source, x interface{}) evaluated {
385 switch v := x.(type) {
386 case evaluated:
387 return v
388 case nil:
389 return &nullLit{src.base()}
Marcel van Lohuizend4847d92019-02-18 23:27:34 +0100390 case ast.Expr:
391 x := newVisitorCtx(ctx, nil, nil, nil)
392 return ctx.manifest(x.walk(v))
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100393 case error:
394 return ctx.mkErr(src, v.Error())
395 case bool:
396 return &boolLit{src.base(), v}
397 case string:
398 return &stringLit{src.base(), v}
399 case []byte:
400 return &bytesLit{src.base(), v}
401 case int:
402 return toInt(ctx, src, int64(v))
403 case int8:
404 return toInt(ctx, src, int64(v))
405 case int16:
406 return toInt(ctx, src, int64(v))
407 case int32:
408 return toInt(ctx, src, int64(v))
409 case int64:
410 return toInt(ctx, src, int64(v))
411 case uint:
412 return toUint(ctx, src, uint64(v))
413 case uint8:
414 return toUint(ctx, src, uint64(v))
415 case uint16:
416 return toUint(ctx, src, uint64(v))
417 case uint32:
418 return toUint(ctx, src, uint64(v))
419 case uint64:
420 return toUint(ctx, src, uint64(v))
421 case float64:
422 r := newNum(src, floatKind)
423 r.v.SetString(fmt.Sprintf("%g", v))
424 return r
425 case *big.Int:
426 n := newNum(src, intKind)
427 n.v.Coeff.Set(v)
428 if v.Sign() < 0 {
429 n.v.Coeff.Neg(&n.v.Coeff)
430 n.v.Negative = true
431 }
432 return n
433 case *big.Rat:
434 n := newNum(src, numKind)
435 ctx.Quo(&n.v, apd.NewWithBigInt(v.Num(), 0), apd.NewWithBigInt(v.Denom(), 0))
436 if !v.IsInt() {
437 n.k = floatKind
438 }
439 return n
440 case *big.Float:
441 n := newNum(src, floatKind)
442 n.v.SetString(v.String())
443 return n
444 case *apd.Decimal:
445 n := newNum(src, floatKind|intKind)
446 n.v.Set(v)
447 if !n.isInt(ctx) {
448 n.k = floatKind
449 }
450 return n
451 case reflect.Value:
452 if v.CanInterface() {
453 return convert(ctx, src, v.Interface())
454 }
455
456 default:
457 value := reflect.ValueOf(v)
458 switch value.Kind() {
459 case reflect.Ptr:
460 if value.IsNil() {
461 return &nullLit{src.base()}
462 }
463 return convert(ctx, src, value.Elem().Interface())
464 case reflect.Struct:
465 obj := newStruct(src)
466 t := value.Type()
467 for i := 0; i < value.NumField(); i++ {
468 t := t.Field(i)
469 if t.PkgPath != "" {
470 continue
471 }
472 sub := convert(ctx, src, value.Field(i).Interface())
473 // leave errors like we do during normal evaluation or do we
474 // want to return the error?
475 name := t.Name
476 for _, s := range []string{"cue", "json", "protobuf"} {
477 if tag, ok := t.Tag.Lookup(s); ok {
478 if p := strings.Index(tag, ","); p >= 0 {
479 tag = tag[:p]
480 }
481 if tag != "" {
482 name = tag
483 break
484 }
485 }
486 }
487 f := ctx.strLabel(name)
488 obj.arcs = append(obj.arcs, arc{feature: f, v: sub})
489 }
490 sort.Sort(obj)
491 return obj
492
493 case reflect.Map:
494 obj := newStruct(src)
495 t := value.Type()
496 if t.Key().Kind() != reflect.String {
497 return ctx.mkErr(src, "builtin map key not a string, but unsupported type %s", t.Key().String())
498 }
499 keys := []string{}
500 for _, k := range value.MapKeys() {
501 keys = append(keys, k.String())
502 }
503 sort.Strings(keys)
504 for _, k := range keys {
505 sub := convert(ctx, src, value.MapIndex(reflect.ValueOf(k)).Interface())
506 // leave errors like we do during normal evaluation or do we
507 // want to return the error?
508 f := ctx.strLabel(k)
509 obj.arcs = append(obj.arcs, arc{feature: f, v: sub})
510 }
511 sort.Sort(obj)
512 return obj
513
514 case reflect.Slice, reflect.Array:
515 list := &list{baseValue: src.base()}
516 for i := 0; i < value.Len(); i++ {
517 x := convert(ctx, src, value.Index(i).Interface())
518 if isBottom(x) {
519 return x
520 }
521 list.a = append(list.a, x)
522 }
523 list.initLit()
524 // There is no need to set the type of the list, as the list will
525 // be of fixed size and all elements will already have a defined
526 // value.
527 return list
528 }
529 }
530 return ctx.mkErr(src, "builtin returned unsupported type %T", x)
531}
532
533func toInt(ctx *context, src source, x int64) evaluated {
534 n := newNum(src, intKind)
535 n.v.SetInt64(x)
536 return n
537}
538
539func toUint(ctx *context, src source, x uint64) evaluated {
540 n := newNum(src, floatKind)
541 n.v.Coeff.SetUint64(x)
542 return n
543}