cuelang.org/go@v0.10.1/internal/pkg/context.go (about) 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 pkg 16 17 import ( 18 "io" 19 "math/big" 20 21 "github.com/cockroachdb/apd/v3" 22 23 "cuelang.org/go/cue" 24 "cuelang.org/go/cue/token" 25 "cuelang.org/go/internal/core/adt" 26 "cuelang.org/go/internal/value" 27 ) 28 29 // CallCtxt is passed to builtin implementations that need to use a cue.Value. This is an internal type. Its interface may change. 30 type CallCtxt struct { 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 := value.Make(c.ctx, c.args[i]) 54 // TODO: remove default 55 // v, _ = v.Default() 56 if !v.IsConcrete() { 57 c.errcf(adt.IncompleteError, "non-concrete argument %d", i) 58 } 59 return v 60 } 61 62 func (c *CallCtxt) Struct(i int) Struct { 63 x := c.args[i] 64 switch v, ok := x.(*adt.Vertex); { 65 case ok && !v.IsList(): 66 v.CompleteArcs(c.ctx) 67 return Struct{c.ctx, v} 68 69 case v != nil: 70 x = v.Value() 71 } 72 if x.Kind()&adt.StructKind == 0 { 73 var err error 74 if b, ok := x.(*adt.Bottom); ok { 75 err = &callError{b} 76 } 77 c.invalidArgType(c.args[i], i, "struct", err) 78 } else { 79 err := c.ctx.NewErrf("non-concrete struct for argument %d", i) 80 err.Code = adt.IncompleteError 81 c.Err = &callError{err} 82 } 83 return Struct{} 84 } 85 86 func (c *CallCtxt) Int(i int) int { return int(c.intValue(i, 64, "int64")) } 87 func (c *CallCtxt) Int8(i int) int8 { return int8(c.intValue(i, 8, "int8")) } 88 func (c *CallCtxt) Int16(i int) int16 { return int16(c.intValue(i, 16, "int16")) } 89 func (c *CallCtxt) Int32(i int) int32 { return int32(c.intValue(i, 32, "int32")) } 90 func (c *CallCtxt) Rune(i int) rune { return rune(c.intValue(i, 32, "rune")) } 91 func (c *CallCtxt) Int64(i int) int64 { return int64(c.intValue(i, 64, "int64")) } 92 93 func (c *CallCtxt) intValue(i, bits int, typ string) int64 { 94 arg := c.args[i] 95 x := value.Make(c.ctx, arg) 96 n, err := x.Int(nil) 97 if err != nil { 98 c.invalidArgType(arg, i, typ, err) 99 return 0 100 } 101 if n.BitLen() > bits { 102 c.errf(err, "int %s overflows %s in argument %d in call to %s", 103 n, typ, i, c.Name()) 104 } 105 res, _ := x.Int64() 106 return res 107 } 108 109 func (c *CallCtxt) Uint(i int) uint { return uint(c.uintValue(i, 64, "uint64")) } 110 func (c *CallCtxt) Uint8(i int) uint8 { return uint8(c.uintValue(i, 8, "uint8")) } 111 func (c *CallCtxt) Byte(i int) uint8 { return byte(c.uintValue(i, 8, "byte")) } 112 func (c *CallCtxt) Uint16(i int) uint16 { return uint16(c.uintValue(i, 16, "uint16")) } 113 func (c *CallCtxt) Uint32(i int) uint32 { return uint32(c.uintValue(i, 32, "uint32")) } 114 func (c *CallCtxt) Uint64(i int) uint64 { return uint64(c.uintValue(i, 64, "uint64")) } 115 116 func (c *CallCtxt) uintValue(i, bits int, typ string) uint64 { 117 x := value.Make(c.ctx, c.args[i]) 118 n, err := x.Int(nil) 119 if err != nil || n.Sign() < 0 { 120 c.invalidArgType(c.args[i], i, typ, err) 121 return 0 122 } 123 if n.BitLen() > bits { 124 c.errf(err, "int %s overflows %s in argument %d in call to %s", 125 n, typ, i, c.Name()) 126 } 127 res, _ := x.Uint64() 128 return res 129 } 130 131 func (c *CallCtxt) Decimal(i int) *apd.Decimal { 132 x := value.Make(c.ctx, c.args[i]) 133 res, err := x.Decimal() 134 if err != nil { 135 c.invalidArgType(c.args[i], i, "Decimal", err) 136 return nil 137 } 138 return res 139 } 140 141 func (c *CallCtxt) Float64(i int) float64 { 142 x := value.Make(c.ctx, c.args[i]) 143 res, err := x.Float64() 144 if err != nil { 145 c.invalidArgType(c.args[i], i, "float64", err) 146 return 0 147 } 148 return res 149 } 150 151 func (c *CallCtxt) BigInt(i int) *big.Int { 152 x := value.Make(c.ctx, c.args[i]) 153 n, err := x.Int(nil) 154 if err != nil { 155 c.invalidArgType(c.args[i], i, "int", err) 156 return nil 157 } 158 return n 159 } 160 161 var ten = big.NewInt(10) 162 163 func (c *CallCtxt) BigFloat(i int) *big.Float { 164 x := value.Make(c.ctx, c.args[i]) 165 var mant big.Int 166 exp, err := x.MantExp(&mant) 167 if err != nil { 168 c.invalidArgType(c.args[i], i, "float", err) 169 return nil 170 } 171 f := &big.Float{} 172 f.SetInt(&mant) 173 if exp != 0 { 174 var g big.Float 175 e := big.NewInt(int64(exp)) 176 f.Mul(f, g.SetInt(e.Exp(ten, e, nil))) 177 } 178 return f 179 } 180 181 func (c *CallCtxt) String(i int) string { 182 // TODO: use Evaluate instead. 183 x := value.Make(c.ctx, c.args[i]) 184 v, err := x.String() 185 if err != nil { 186 c.invalidArgType(c.args[i], i, "string", err) 187 return "" 188 } 189 return v 190 } 191 192 func (c *CallCtxt) Bytes(i int) []byte { 193 x := value.Make(c.ctx, c.args[i]) 194 v, err := x.Bytes() 195 if err != nil { 196 c.invalidArgType(c.args[i], i, "bytes", err) 197 return nil 198 } 199 return v 200 } 201 202 func (c *CallCtxt) Reader(i int) io.Reader { 203 x := value.Make(c.ctx, c.args[i]) 204 // TODO: optimize for string and bytes cases 205 r, err := x.Reader() 206 if err != nil { 207 c.invalidArgType(c.args[i], i, "bytes|string", err) 208 return nil 209 } 210 return r 211 } 212 213 func (c *CallCtxt) Bool(i int) bool { 214 x := value.Make(c.ctx, c.args[i]) 215 b, err := x.Bool() 216 if err != nil { 217 c.invalidArgType(c.args[i], i, "bool", err) 218 return false 219 } 220 return b 221 } 222 223 func (c *CallCtxt) List(i int) (a []cue.Value) { 224 arg := c.args[i] 225 x := value.Make(c.ctx, arg) 226 v, err := x.List() 227 if err != nil { 228 c.invalidArgType(c.args[i], i, "list", err) 229 return a 230 } 231 for v.Next() { 232 a = append(a, v.Value()) 233 } 234 return a 235 } 236 237 func (c *CallCtxt) CueList(i int) List { 238 v := c.getList(i) 239 if v == nil { 240 return List{} 241 } 242 return List{c.ctx, v, v.BaseValue.(*adt.ListMarker).IsOpen} 243 } 244 245 func (c *CallCtxt) Iter(i int) (a cue.Iterator) { 246 arg := c.args[i] 247 x := value.Make(c.ctx, arg) 248 v, err := x.List() 249 if err != nil { 250 c.invalidArgType(c.args[i], i, "list", err) 251 } 252 return v 253 } 254 255 func (c *CallCtxt) getList(i int) *adt.Vertex { 256 x := c.args[i] 257 switch v, ok := x.(*adt.Vertex); { 258 case ok && v.IsList(): 259 v.Finalize(c.ctx) 260 return v 261 262 case v != nil: 263 x = v.Value() 264 } 265 if x.Kind()&adt.ListKind == 0 { 266 var err error 267 if b, ok := x.(*adt.Bottom); ok { 268 err = &callError{b} 269 } 270 c.invalidArgType(c.args[i], i, "list", err) 271 } else { 272 err := c.ctx.NewErrf("non-concrete list for argument %d", i) 273 err.Code = adt.IncompleteError 274 c.Err = &callError{err} 275 } 276 return nil 277 } 278 279 func (c *CallCtxt) DecimalList(i int) (a []*apd.Decimal) { 280 v := c.getList(i) 281 if v == nil { 282 return nil 283 } 284 285 for j, w := range v.Elems() { 286 w.Finalize(c.ctx) // defensive 287 switch x := adt.Unwrap(adt.Default(w.Value())).(type) { 288 case *adt.Num: 289 a = append(a, &x.X) 290 291 case *adt.Bottom: 292 if x.IsIncomplete() { 293 c.Err = x 294 return nil 295 } 296 297 default: 298 if k := w.Kind(); k&adt.NumberKind == 0 { 299 err := c.ctx.NewErrf( 300 "invalid list element %d in argument %d to call: cannot use value %v (%s) as number", 301 j, i, w, k) 302 c.Err = &callError{err} 303 return a 304 } 305 306 err := c.ctx.NewErrf( 307 "non-concrete value %v for element %d of number list argument %d", 308 w, j, i) 309 err.Code = adt.IncompleteError 310 c.Err = &callError{err} 311 return nil 312 } 313 } 314 return a 315 } 316 317 func (c *CallCtxt) StringList(i int) (a []string) { 318 v := c.getList(i) 319 if v == nil { 320 return nil 321 } 322 323 for j, w := range v.Elems() { 324 w.Finalize(c.ctx) // defensive 325 switch x := adt.Unwrap(adt.Default(w.Value())).(type) { 326 case *adt.String: 327 a = append(a, x.Str) 328 329 case *adt.Bottom: 330 if x.IsIncomplete() { 331 c.Err = x 332 return nil 333 } 334 335 default: 336 if k := w.Kind(); k&adt.StringKind == 0 { 337 err := c.ctx.NewErrf( 338 "invalid list element %d in argument %d to call: cannot use value %v (%s) as string", 339 j, i, w, k) 340 c.Err = &callError{err} 341 return a 342 } 343 344 err := c.ctx.NewErrf( 345 "non-concrete value %v for element %d of string list argument %d", 346 w, j, i) 347 err.Code = adt.IncompleteError 348 c.Err = &callError{err} 349 return nil 350 } 351 } 352 return a 353 }