...

Source file src/cuelang.org/go/internal/core/compile/builtin.go

Documentation: cuelang.org/go/internal/core/compile

     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  	"cuelang.org/go/cue/errors"
    19  	"cuelang.org/go/internal/core/adt"
    20  )
    21  
    22  // This file contains predeclared builtins.
    23  
    24  const supportedByLen = adt.StructKind | adt.BytesKind | adt.StringKind | adt.ListKind
    25  
    26  var (
    27  	stringParam = adt.Param{Value: &adt.BasicType{K: adt.StringKind}}
    28  	structParam = adt.Param{Value: &adt.BasicType{K: adt.StructKind}}
    29  	listParam   = adt.Param{Value: &adt.BasicType{K: adt.ListKind}}
    30  	intParam    = adt.Param{Value: &adt.BasicType{K: adt.IntKind}}
    31  )
    32  
    33  var lenBuiltin = &adt.Builtin{
    34  	Name:   "len",
    35  	Params: []adt.Param{{Value: &adt.BasicType{K: supportedByLen}}},
    36  	Result: adt.IntKind,
    37  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
    38  		v := args[0]
    39  		if x, ok := v.(*adt.Vertex); ok {
    40  			x.LockArcs = true
    41  			switch x.BaseValue.(type) {
    42  			case nil:
    43  				// This should not happen, but be defensive.
    44  				return c.NewErrf("unevaluated vertex")
    45  			case *adt.ListMarker:
    46  				return c.NewInt64(int64(len(x.Elems())), v)
    47  
    48  			case *adt.StructMarker:
    49  				n := 0
    50  				v, _ := v.(*adt.Vertex)
    51  				for _, a := range v.Arcs {
    52  					if a.Label.IsRegular() && a.IsDefined(c) {
    53  						n++
    54  					}
    55  				}
    56  				return c.NewInt64(int64(n), v)
    57  
    58  			default:
    59  				v = x.Value()
    60  			}
    61  		}
    62  
    63  		switch x := v.(type) {
    64  		case *adt.Bytes:
    65  			return c.NewInt64(int64(len(x.B)), v)
    66  		case *adt.String:
    67  			return c.NewInt64(int64(len(x.Str)), v)
    68  		default:
    69  			k := x.Kind()
    70  			if k&supportedByLen == adt.BottomKind {
    71  				return c.NewErrf("invalid argument type %v", k)
    72  			}
    73  			b := c.NewErrf("incomplete argument %s (type %v)", v, k)
    74  			b.Code = adt.IncompleteError
    75  			return b
    76  		}
    77  	},
    78  }
    79  
    80  var closeBuiltin = &adt.Builtin{
    81  	Name:   "close",
    82  	Params: []adt.Param{structParam},
    83  	Result: adt.StructKind,
    84  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
    85  		s, ok := args[0].(*adt.Vertex)
    86  		if !ok {
    87  			return c.NewErrf("struct argument must be concrete")
    88  		}
    89  		if m, ok := s.BaseValue.(*adt.StructMarker); ok && m.NeedClose {
    90  			return s
    91  		}
    92  		v := s.Clone()
    93  		// TODO(perf): do not copy the arc, but rather find a way to mark the
    94  		// calling nodeContext.
    95  		v.BaseValue = &adt.StructMarker{NeedClose: true}
    96  		return v
    97  	},
    98  }
    99  
   100  var andBuiltin = &adt.Builtin{
   101  	Name:   "and",
   102  	Params: []adt.Param{listParam},
   103  	Result: adt.IntKind,
   104  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   105  		list := c.RawElems(args[0])
   106  		if len(list) == 0 {
   107  			return &adt.Top{}
   108  		}
   109  		a := []adt.Value{}
   110  		for _, c := range list {
   111  			a = append(a, c)
   112  		}
   113  		return &adt.Conjunction{Values: a}
   114  	},
   115  }
   116  
   117  var orBuiltin = &adt.Builtin{
   118  	Name:   "or",
   119  	Params: []adt.Param{listParam},
   120  	Result: adt.IntKind,
   121  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   122  		d := []adt.Disjunct{}
   123  		for _, c := range c.RawElems(args[0]) {
   124  			d = append(d, adt.Disjunct{Val: c, Default: false})
   125  		}
   126  		if len(d) == 0 {
   127  			// TODO(manifest): This should not be unconditionally incomplete,
   128  			// but it requires results from comprehensions and all to have
   129  			// some special status. Maybe this can be solved by having results
   130  			// of list comprehensions be open if they result from iterating over
   131  			// an open list or struct. This would actually be exactly what
   132  			// that means. The error here could then only add an incomplete
   133  			// status if the source is open.
   134  			return &adt.Bottom{
   135  				Code: adt.IncompleteError,
   136  				Err:  errors.Newf(c.Pos(), "empty list in call to or"),
   137  			}
   138  		}
   139  		v := &adt.Vertex{}
   140  		// TODO: make a Disjunction.
   141  		closeInfo := c.CloseInfo()
   142  		v.AddConjunct(adt.MakeConjunct(nil,
   143  			&adt.DisjunctionExpr{Values: d, HasDefaults: false},
   144  			closeInfo,
   145  		))
   146  		v.CompleteArcs(c)
   147  		return v
   148  	},
   149  }
   150  
   151  var divBuiltin = &adt.Builtin{
   152  	Name:   "div",
   153  	Params: []adt.Param{intParam, intParam},
   154  	Result: adt.IntKind,
   155  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   156  		const name = "argument to div builtin"
   157  
   158  		return intDivOp(c, (*adt.OpContext).IntDiv, name, args)
   159  	},
   160  }
   161  
   162  var modBuiltin = &adt.Builtin{
   163  	Name:   "mod",
   164  	Params: []adt.Param{intParam, intParam},
   165  	Result: adt.IntKind,
   166  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   167  		const name = "argument to mod builtin"
   168  
   169  		return intDivOp(c, (*adt.OpContext).IntMod, name, args)
   170  	},
   171  }
   172  
   173  var quoBuiltin = &adt.Builtin{
   174  	Name:   "quo",
   175  	Params: []adt.Param{intParam, intParam},
   176  	Result: adt.IntKind,
   177  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   178  		const name = "argument to quo builtin"
   179  
   180  		return intDivOp(c, (*adt.OpContext).IntQuo, name, args)
   181  	},
   182  }
   183  
   184  var remBuiltin = &adt.Builtin{
   185  	Name:   "rem",
   186  	Params: []adt.Param{intParam, intParam},
   187  	Result: adt.IntKind,
   188  	Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
   189  		const name = "argument to rem builtin"
   190  
   191  		return intDivOp(c, (*adt.OpContext).IntRem, name, args)
   192  	},
   193  }
   194  
   195  type intFunc func(c *adt.OpContext, x, y *adt.Num) adt.Value
   196  
   197  func intDivOp(c *adt.OpContext, fn intFunc, name string, args []adt.Value) adt.Value {
   198  	a := c.Num(args[0], name)
   199  	b := c.Num(args[1], name)
   200  
   201  	if c.HasErr() {
   202  		return nil
   203  	}
   204  
   205  	return fn(c, a, b)
   206  }
   207  

View as plain text