123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- package tengo
- import (
- "errors"
- "fmt"
- "strconv"
- "time"
- )
- var (
- // MaxStringLen is the maximum byte-length for string value. Note this
- // limit applies to all compiler/VM instances in the process.
- MaxStringLen = 2147483647
- // MaxBytesLen is the maximum length for bytes value. Note this limit
- // applies to all compiler/VM instances in the process.
- MaxBytesLen = 2147483647
- )
- const (
- // GlobalsSize is the maximum number of global variables for a VM.
- GlobalsSize = 1024
- // StackSize is the maximum stack size for a VM.
- StackSize = 2048
- // MaxFrames is the maximum number of function frames for a VM.
- MaxFrames = 1024
- // SourceFileExtDefault is the default extension for source files.
- SourceFileExtDefault = ".tengo"
- )
- // CallableFunc is a function signature for the callable functions.
- type CallableFunc = func(args ...Object) (ret Object, err error)
- // CountObjects returns the number of objects that a given object o contains.
- // For scalar value types, it will always be 1. For compound value types,
- // this will include its elements and all of their elements recursively.
- func CountObjects(o Object) (c int) {
- c = 1
- switch o := o.(type) {
- case *Array:
- for _, v := range o.Value {
- c += CountObjects(v)
- }
- case *ImmutableArray:
- for _, v := range o.Value {
- c += CountObjects(v)
- }
- case *Map:
- for _, v := range o.Value {
- c += CountObjects(v)
- }
- case *ImmutableMap:
- for _, v := range o.Value {
- c += CountObjects(v)
- }
- case *Error:
- c += CountObjects(o.Value)
- }
- return
- }
- // ToString will try to convert object o to string value.
- func ToString(o Object) (v string, ok bool) {
- if o == UndefinedValue {
- return
- }
- ok = true
- if str, isStr := o.(*String); isStr {
- v = str.Value
- } else {
- v = o.String()
- }
- return
- }
- // ToInt will try to convert object o to int value.
- func ToInt(o Object) (v int, ok bool) {
- switch o := o.(type) {
- case *Int:
- v = int(o.Value)
- ok = true
- case *Float:
- v = int(o.Value)
- ok = true
- case *Char:
- v = int(o.Value)
- ok = true
- case *Bool:
- if o == TrueValue {
- v = 1
- }
- ok = true
- case *String:
- c, err := strconv.ParseInt(o.Value, 10, 64)
- if err == nil {
- v = int(c)
- ok = true
- }
- }
- return
- }
- // ToInt64 will try to convert object o to int64 value.
- func ToInt64(o Object) (v int64, ok bool) {
- switch o := o.(type) {
- case *Int:
- v = o.Value
- ok = true
- case *Float:
- v = int64(o.Value)
- ok = true
- case *Char:
- v = int64(o.Value)
- ok = true
- case *Bool:
- if o == TrueValue {
- v = 1
- }
- ok = true
- case *String:
- c, err := strconv.ParseInt(o.Value, 10, 64)
- if err == nil {
- v = c
- ok = true
- }
- }
- return
- }
- // ToFloat64 will try to convert object o to float64 value.
- func ToFloat64(o Object) (v float64, ok bool) {
- switch o := o.(type) {
- case *Int:
- v = float64(o.Value)
- ok = true
- case *Float:
- v = o.Value
- ok = true
- case *String:
- c, err := strconv.ParseFloat(o.Value, 64)
- if err == nil {
- v = c
- ok = true
- }
- }
- return
- }
- // ToBool will try to convert object o to bool value.
- func ToBool(o Object) (v bool, ok bool) {
- ok = true
- v = !o.IsFalsy()
- return
- }
- // ToRune will try to convert object o to rune value.
- func ToRune(o Object) (v rune, ok bool) {
- switch o := o.(type) {
- case *Int:
- v = rune(o.Value)
- ok = true
- case *Char:
- v = o.Value
- ok = true
- }
- return
- }
- // ToByteSlice will try to convert object o to []byte value.
- func ToByteSlice(o Object) (v []byte, ok bool) {
- switch o := o.(type) {
- case *Bytes:
- v = o.Value
- ok = true
- case *String:
- v = []byte(o.Value)
- ok = true
- }
- return
- }
- // ToTime will try to convert object o to time.Time value.
- func ToTime(o Object) (v time.Time, ok bool) {
- switch o := o.(type) {
- case *Time:
- v = o.Value
- ok = true
- case *Int:
- v = time.Unix(o.Value, 0)
- ok = true
- }
- return
- }
- // ToInterface attempts to convert an object o to an interface{} value
- func ToInterface(o Object) (res interface{}) {
- switch o := o.(type) {
- case *Int:
- res = o.Value
- case *String:
- res = o.Value
- case *Float:
- res = o.Value
- case *Bool:
- res = o == TrueValue
- case *Char:
- res = o.Value
- case *Bytes:
- res = o.Value
- case *Array:
- res = make([]interface{}, len(o.Value))
- for i, val := range o.Value {
- res.([]interface{})[i] = ToInterface(val)
- }
- case *ImmutableArray:
- res = make([]interface{}, len(o.Value))
- for i, val := range o.Value {
- res.([]interface{})[i] = ToInterface(val)
- }
- case *Map:
- res = make(map[string]interface{})
- for key, v := range o.Value {
- res.(map[string]interface{})[key] = ToInterface(v)
- }
- case *ImmutableMap:
- res = make(map[string]interface{})
- for key, v := range o.Value {
- res.(map[string]interface{})[key] = ToInterface(v)
- }
- case *Time:
- res = o.Value
- case *Error:
- res = errors.New(o.String())
- case *Undefined:
- res = nil
- case Object:
- return o
- }
- return
- }
- // FromInterface will attempt to convert an interface{} v to a Tengo Object
- func FromInterface(v interface{}) (Object, error) {
- switch v := v.(type) {
- case nil:
- return UndefinedValue, nil
- case string:
- if len(v) > MaxStringLen {
- return nil, ErrStringLimit
- }
- return &String{Value: v}, nil
- case int64:
- return &Int{Value: v}, nil
- case int:
- return &Int{Value: int64(v)}, nil
- case bool:
- if v {
- return TrueValue, nil
- }
- return FalseValue, nil
- case rune:
- return &Char{Value: v}, nil
- case byte:
- return &Char{Value: rune(v)}, nil
- case float64:
- return &Float{Value: v}, nil
- case []byte:
- if len(v) > MaxBytesLen {
- return nil, ErrBytesLimit
- }
- return &Bytes{Value: v}, nil
- case error:
- return &Error{Value: &String{Value: v.Error()}}, nil
- case map[string]Object:
- return &Map{Value: v}, nil
- case map[string]interface{}:
- kv := make(map[string]Object)
- for vk, vv := range v {
- vo, err := FromInterface(vv)
- if err != nil {
- return nil, err
- }
- kv[vk] = vo
- }
- return &Map{Value: kv}, nil
- case []Object:
- return &Array{Value: v}, nil
- case []interface{}:
- arr := make([]Object, len(v))
- for i, e := range v {
- vo, err := FromInterface(e)
- if err != nil {
- return nil, err
- }
- arr[i] = vo
- }
- return &Array{Value: arr}, nil
- case time.Time:
- return &Time{Value: v}, nil
- case Object:
- return v, nil
- case CallableFunc:
- return &UserFunction{Value: v}, nil
- }
- return nil, fmt.Errorf("cannot convert to object: %T", v)
- }
|