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  }