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