cuelang.org/go@v0.13.0/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 *adt.CallContext 32 ctx *adt.OpContext 33 builtin *Builtin 34 Err interface{} 35 Ret interface{} 36 37 args []adt.Value 38 } 39 40 func (c *CallCtxt) Pos() token.Pos { 41 return c.ctx.Pos() 42 } 43 44 func (c *CallCtxt) Name() string { 45 return c.builtin.name(c.ctx) 46 } 47 48 // Do returns whether the call should be done. 49 func (c *CallCtxt) Do() bool { 50 return c.Err == nil 51 } 52 53 // Schema returns the ith argument as is, without converting it to a cue.Value. 54 // 55 // TODO: Schema should use CallContext.Expr to capture cycle information. 56 // However, this only makes sense if functions also use the same OpContext for 57 // further evaluation. We should enforce as we port the old calls. 58 func (c *CallCtxt) Schema(i int) Schema { 59 v := c.Expr(i) 60 return value.Make(c.ctx, v) 61 } 62 63 // Value returns a finalized cue.Value for the ith argument. 64 func (c *CallCtxt) Value(i int) cue.Value { 65 v := value.Make(c.ctx, c.args[i]) 66 if c.builtin.NonConcrete { 67 // In case NonConcrete is false, the concreteness is already checked 68 // at call time. We may want to use finalize semantics in both cases, 69 // though. 70 _, f := value.ToInternal(v) 71 f = f.ToDataAll(c.ctx) 72 v = value.Make(c.ctx, f) 73 } 74 if !v.IsConcrete() { 75 c.errcf(adt.IncompleteError, "non-concrete argument %d", i) 76 } 77 return v 78 } 79 80 func (c *CallCtxt) Struct(i int) Struct { 81 x := c.args[i] 82 if c.builtin.NonConcrete { 83 x = adt.Default(x) 84 } 85 switch v, ok := x.(*adt.Vertex); { 86 case ok && !v.IsList(): 87 v.CompleteArcs(c.ctx) 88 return Struct{c.ctx, v} 89 90 case v != nil: 91 x = v.Value() 92 } 93 if x.Kind()&adt.StructKind == 0 { 94 var err error 95 if b, ok := x.(*adt.Bottom); ok { 96 err = &callError{b} 97 } 98 c.invalidArgType(c.args[i], i, "struct", err) 99 } else { 100 err := c.ctx.NewErrf("non-concrete struct for argument %d", i) 101 err.Code = adt.IncompleteError 102 c.Err = &callError{err} 103 } 104 return Struct{} 105 } 106 107 func (c *CallCtxt) Int(i int) int { return int(c.intValue(i, 64, "int64")) } 108 func (c *CallCtxt) Int8(i int) int8 { return int8(c.intValue(i, 8, "int8")) } 109 func (c *CallCtxt) Int16(i int) int16 { return int16(c.intValue(i, 16, "int16")) } 110 func (c *CallCtxt) Int32(i int) int32 { return int32(c.intValue(i, 32, "int32")) } 111 func (c *CallCtxt) Rune(i int) rune { return rune(c.intValue(i, 32, "rune")) } 112 func (c *CallCtxt) Int64(i int) int64 { return c.intValue(i, 64, "int64") } 113 114 func (c *CallCtxt) intValue(i, bits int, typ string) int64 { 115 arg := c.args[i] 116 x := value.Make(c.ctx, arg) 117 n, err := x.Int(nil) 118 if err != nil { 119 c.invalidArgType(arg, i, typ, err) 120 return 0 121 } 122 if n.BitLen() > bits { 123 c.errf(err, "int %s overflows %s in argument %d in call to %s", 124 n, typ, i, c.Name()) 125 } 126 res, _ := x.Int64() 127 return res 128 } 129 130 func (c *CallCtxt) Uint(i int) uint { return uint(c.uintValue(i, 64, "uint64")) } 131 func (c *CallCtxt) Uint8(i int) uint8 { return uint8(c.uintValue(i, 8, "uint8")) } 132 func (c *CallCtxt) Byte(i int) uint8 { return byte(c.uintValue(i, 8, "byte")) } 133 func (c *CallCtxt) Uint16(i int) uint16 { return uint16(c.uintValue(i, 16, "uint16")) } 134 func (c *CallCtxt) Uint32(i int) uint32 { return uint32(c.uintValue(i, 32, "uint32")) } 135 func (c *CallCtxt) Uint64(i int) uint64 { return c.uintValue(i, 64, "uint64") } 136 137 func (c *CallCtxt) uintValue(i, bits int, typ string) uint64 { 138 x := value.Make(c.ctx, c.args[i]) 139 n, err := x.Int(nil) 140 if err != nil || n.Sign() < 0 { 141 c.invalidArgType(c.args[i], i, typ, err) 142 return 0 143 } 144 if n.BitLen() > bits { 145 c.errf(err, "int %s overflows %s in argument %d in call to %s", 146 n, typ, i, c.Name()) 147 } 148 res, _ := x.Uint64() 149 return res 150 } 151 152 func (c *CallCtxt) Decimal(i int) *apd.Decimal { 153 x := value.Make(c.ctx, c.args[i]) 154 res, err := x.Decimal() 155 if err != nil { 156 c.invalidArgType(c.args[i], i, "Decimal", err) 157 return nil 158 } 159 return res 160 } 161 162 func (c *CallCtxt) Float64(i int) float64 { 163 x := value.Make(c.ctx, c.args[i]) 164 res, err := x.Float64() 165 if err != nil { 166 c.invalidArgType(c.args[i], i, "float64", err) 167 return 0 168 } 169 return res 170 } 171 172 func (c *CallCtxt) BigInt(i int) *big.Int { 173 x := value.Make(c.ctx, c.args[i]) 174 n, err := x.Int(nil) 175 if err != nil { 176 c.invalidArgType(c.args[i], i, "int", err) 177 return nil 178 } 179 return n 180 } 181 182 var ten = big.NewInt(10) 183 184 func (c *CallCtxt) BigFloat(i int) *big.Float { 185 x := value.Make(c.ctx, c.args[i]) 186 var mant big.Int 187 exp, err := x.MantExp(&mant) 188 if err != nil { 189 c.invalidArgType(c.args[i], i, "float", err) 190 return nil 191 } 192 f := &big.Float{} 193 f.SetInt(&mant) 194 if exp != 0 { 195 var g big.Float 196 e := big.NewInt(int64(exp)) 197 f.Mul(f, g.SetInt(e.Exp(ten, e, nil))) 198 } 199 return f 200 } 201 202 func (c *CallCtxt) String(i int) string { 203 // TODO: use Evaluate instead. 204 x := value.Make(c.ctx, c.args[i]) 205 v, err := x.String() 206 if err != nil { 207 c.invalidArgType(c.args[i], i, "string", err) 208 return "" 209 } 210 return v 211 } 212 213 func (c *CallCtxt) Bytes(i int) []byte { 214 x := value.Make(c.ctx, c.args[i]) 215 v, err := x.Bytes() 216 if err != nil { 217 c.invalidArgType(c.args[i], i, "bytes", err) 218 return nil 219 } 220 return v 221 } 222 223 func (c *CallCtxt) Reader(i int) io.Reader { 224 x := value.Make(c.ctx, c.args[i]) 225 // TODO: optimize for string and bytes cases 226 r, err := x.Reader() 227 if err != nil { 228 c.invalidArgType(c.args[i], i, "bytes|string", err) 229 return nil 230 } 231 return r 232 } 233 234 func (c *CallCtxt) Bool(i int) bool { 235 x := value.Make(c.ctx, c.args[i]) 236 b, err := x.Bool() 237 if err != nil { 238 c.invalidArgType(c.args[i], i, "bool", err) 239 return false 240 } 241 return b 242 } 243 244 func (c *CallCtxt) List(i int) (a []cue.Value) { 245 arg := c.args[i] 246 x := value.Make(c.ctx, arg) 247 v, err := x.List() 248 if err != nil { 249 c.invalidArgType(c.args[i], i, "list", err) 250 return a 251 } 252 for v.Next() { 253 a = append(a, v.Value()) 254 } 255 return a 256 } 257 258 func (c *CallCtxt) CueList(i int) List { 259 v := c.getList(i) 260 if v == nil { 261 return List{} 262 } 263 return List{c.ctx, v, v.BaseValue.(*adt.ListMarker).IsOpen} 264 } 265 266 func (c *CallCtxt) Iter(i int) (a cue.Iterator) { 267 arg := c.args[i] 268 x := value.Make(c.ctx, arg) 269 v, err := x.List() 270 if err != nil { 271 c.invalidArgType(c.args[i], i, "list", err) 272 } 273 return v 274 } 275 276 func (c *CallCtxt) getList(i int) *adt.Vertex { 277 x := c.args[i] 278 if c.builtin.NonConcrete { 279 x = adt.Default(x) 280 } 281 switch v, ok := x.(*adt.Vertex); { 282 case ok && v.IsList(): 283 v.Finalize(c.ctx) 284 if err := v.Bottom(); err != nil { 285 c.Err = &callError{err} 286 return nil 287 } 288 return v 289 290 case v != nil: 291 x = v.Value() 292 } 293 294 if x.Kind()&adt.ListKind == 0 { 295 var err error 296 if b, ok := x.(*adt.Bottom); ok { 297 err = &callError{b} 298 } 299 c.invalidArgType(c.args[i], i, "list", err) 300 } else { 301 err := c.ctx.NewErrf("non-concrete list for argument %d", i) 302 err.Code = adt.IncompleteError 303 c.Err = &callError{err} 304 } 305 return nil 306 } 307 308 func (c *CallCtxt) DecimalList(i int) (a []*apd.Decimal) { 309 v := c.getList(i) 310 if v == nil { 311 return nil 312 } 313 314 for j, w := range v.Elems() { 315 w.Finalize(c.ctx) // defensive 316 switch x := adt.Unwrap(adt.Default(w.Value())).(type) { 317 case *adt.Num: 318 a = append(a, &x.X) 319 320 case *adt.Bottom: 321 if x.IsIncomplete() { 322 c.Err = x 323 return nil 324 } 325 326 default: 327 if k := w.Kind(); k&adt.NumberKind == 0 { 328 err := c.ctx.NewErrf( 329 "invalid list element %d in argument %d to call: cannot use value %v (%s) as number", 330 j, i, w, k) 331 c.Err = &callError{err} 332 return a 333 } 334 335 err := c.ctx.NewErrf( 336 "non-concrete value %v for element %d of number list argument %d", 337 w, j, i) 338 err.Code = adt.IncompleteError 339 c.Err = &callError{err} 340 return nil 341 } 342 } 343 return a 344 } 345 346 func (c *CallCtxt) StringList(i int) (a []string) { 347 v := c.getList(i) 348 if v == nil { 349 return nil 350 } 351 352 for j, w := range v.Elems() { 353 w.Finalize(c.ctx) // defensive 354 switch x := adt.Unwrap(adt.Default(w.Value())).(type) { 355 case *adt.String: 356 a = append(a, x.Str) 357 358 case *adt.Bottom: 359 if x.IsIncomplete() { 360 c.Err = x 361 return nil 362 } 363 364 default: 365 if k := w.Kind(); k&adt.StringKind == 0 { 366 err := c.ctx.NewErrf( 367 "invalid list element %d in argument %d to call: cannot use value %v (%s) as string", 368 j, i, w, k) 369 c.Err = &callError{err} 370 return a 371 } 372 373 err := c.ctx.NewErrf( 374 "non-concrete value %v for element %d of string list argument %d", 375 w, j, i) 376 err.Code = adt.IncompleteError 377 c.Err = &callError{err} 378 return nil 379 } 380 } 381 return a 382 }