1package tengo 2 3import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "time" 8) 9 10var ( 11 // MaxStringLen is the maximum byte-length for string value. Note this 12 // limit applies to all compiler/VM instances in the process. 13 MaxStringLen = 2147483647 14 15 // MaxBytesLen is the maximum length for bytes value. Note this limit 16 // applies to all compiler/VM instances in the process. 17 MaxBytesLen = 2147483647 18) 19 20const ( 21 // GlobalsSize is the maximum number of global variables for a VM. 22 GlobalsSize = 1024 23 24 // StackSize is the maximum stack size for a VM. 25 StackSize = 2048 26 27 // MaxFrames is the maximum number of function frames for a VM. 28 MaxFrames = 1024 29) 30 31// CallableFunc is a function signature for the callable functions. 32type CallableFunc = func(args ...Object) (ret Object, err error) 33 34// CountObjects returns the number of objects that a given object o contains. 35// For scalar value types, it will always be 1. For compound value types, 36// this will include its elements and all of their elements recursively. 37func CountObjects(o Object) (c int) { 38 c = 1 39 switch o := o.(type) { 40 case *Array: 41 for _, v := range o.Value { 42 c += CountObjects(v) 43 } 44 case *ImmutableArray: 45 for _, v := range o.Value { 46 c += CountObjects(v) 47 } 48 case *Map: 49 for _, v := range o.Value { 50 c += CountObjects(v) 51 } 52 case *ImmutableMap: 53 for _, v := range o.Value { 54 c += CountObjects(v) 55 } 56 case *Error: 57 c += CountObjects(o.Value) 58 } 59 return 60} 61 62// ToString will try to convert object o to string value. 63func ToString(o Object) (v string, ok bool) { 64 if o == UndefinedValue { 65 return 66 } 67 ok = true 68 if str, isStr := o.(*String); isStr { 69 v = str.Value 70 } else { 71 v = o.String() 72 } 73 return 74} 75 76// ToInt will try to convert object o to int value. 77func ToInt(o Object) (v int, ok bool) { 78 switch o := o.(type) { 79 case *Int: 80 v = int(o.Value) 81 ok = true 82 case *Float: 83 v = int(o.Value) 84 ok = true 85 case *Char: 86 v = int(o.Value) 87 ok = true 88 case *Bool: 89 if o == TrueValue { 90 v = 1 91 } 92 ok = true 93 case *String: 94 c, err := strconv.ParseInt(o.Value, 10, 64) 95 if err == nil { 96 v = int(c) 97 ok = true 98 } 99 } 100 return 101} 102 103// ToInt64 will try to convert object o to int64 value. 104func ToInt64(o Object) (v int64, ok bool) { 105 switch o := o.(type) { 106 case *Int: 107 v = o.Value 108 ok = true 109 case *Float: 110 v = int64(o.Value) 111 ok = true 112 case *Char: 113 v = int64(o.Value) 114 ok = true 115 case *Bool: 116 if o == TrueValue { 117 v = 1 118 } 119 ok = true 120 case *String: 121 c, err := strconv.ParseInt(o.Value, 10, 64) 122 if err == nil { 123 v = c 124 ok = true 125 } 126 } 127 return 128} 129 130// ToFloat64 will try to convert object o to float64 value. 131func ToFloat64(o Object) (v float64, ok bool) { 132 switch o := o.(type) { 133 case *Int: 134 v = float64(o.Value) 135 ok = true 136 case *Float: 137 v = o.Value 138 ok = true 139 case *String: 140 c, err := strconv.ParseFloat(o.Value, 64) 141 if err == nil { 142 v = c 143 ok = true 144 } 145 } 146 return 147} 148 149// ToBool will try to convert object o to bool value. 150func ToBool(o Object) (v bool, ok bool) { 151 ok = true 152 v = !o.IsFalsy() 153 return 154} 155 156// ToRune will try to convert object o to rune value. 157func ToRune(o Object) (v rune, ok bool) { 158 switch o := o.(type) { 159 case *Int: 160 v = rune(o.Value) 161 ok = true 162 case *Char: 163 v = o.Value 164 ok = true 165 } 166 return 167} 168 169// ToByteSlice will try to convert object o to []byte value. 170func ToByteSlice(o Object) (v []byte, ok bool) { 171 switch o := o.(type) { 172 case *Bytes: 173 v = o.Value 174 ok = true 175 case *String: 176 v = []byte(o.Value) 177 ok = true 178 } 179 return 180} 181 182// ToTime will try to convert object o to time.Time value. 183func ToTime(o Object) (v time.Time, ok bool) { 184 switch o := o.(type) { 185 case *Time: 186 v = o.Value 187 ok = true 188 case *Int: 189 v = time.Unix(o.Value, 0) 190 ok = true 191 } 192 return 193} 194 195// ToInterface attempts to convert an object o to an interface{} value 196func ToInterface(o Object) (res interface{}) { 197 switch o := o.(type) { 198 case *Int: 199 res = o.Value 200 case *String: 201 res = o.Value 202 case *Float: 203 res = o.Value 204 case *Bool: 205 res = o == TrueValue 206 case *Char: 207 res = o.Value 208 case *Bytes: 209 res = o.Value 210 case *Array: 211 res = make([]interface{}, len(o.Value)) 212 for i, val := range o.Value { 213 res.([]interface{})[i] = ToInterface(val) 214 } 215 case *ImmutableArray: 216 res = make([]interface{}, len(o.Value)) 217 for i, val := range o.Value { 218 res.([]interface{})[i] = ToInterface(val) 219 } 220 case *Map: 221 res = make(map[string]interface{}) 222 for key, v := range o.Value { 223 res.(map[string]interface{})[key] = ToInterface(v) 224 } 225 case *ImmutableMap: 226 res = make(map[string]interface{}) 227 for key, v := range o.Value { 228 res.(map[string]interface{})[key] = ToInterface(v) 229 } 230 case *Time: 231 res = o.Value 232 case *Error: 233 res = errors.New(o.String()) 234 case *Undefined: 235 res = nil 236 case Object: 237 return o 238 } 239 return 240} 241 242// FromInterface will attempt to convert an interface{} v to a Tengo Object 243func FromInterface(v interface{}) (Object, error) { 244 switch v := v.(type) { 245 case nil: 246 return UndefinedValue, nil 247 case string: 248 if len(v) > MaxStringLen { 249 return nil, ErrStringLimit 250 } 251 return &String{Value: v}, nil 252 case int64: 253 return &Int{Value: v}, nil 254 case int: 255 return &Int{Value: int64(v)}, nil 256 case bool: 257 if v { 258 return TrueValue, nil 259 } 260 return FalseValue, nil 261 case rune: 262 return &Char{Value: v}, nil 263 case byte: 264 return &Char{Value: rune(v)}, nil 265 case float64: 266 return &Float{Value: v}, nil 267 case []byte: 268 if len(v) > MaxBytesLen { 269 return nil, ErrBytesLimit 270 } 271 return &Bytes{Value: v}, nil 272 case error: 273 return &Error{Value: &String{Value: v.Error()}}, nil 274 case map[string]Object: 275 return &Map{Value: v}, nil 276 case map[string]interface{}: 277 kv := make(map[string]Object) 278 for vk, vv := range v { 279 vo, err := FromInterface(vv) 280 if err != nil { 281 return nil, err 282 } 283 kv[vk] = vo 284 } 285 return &Map{Value: kv}, nil 286 case []Object: 287 return &Array{Value: v}, nil 288 case []interface{}: 289 arr := make([]Object, len(v)) 290 for i, e := range v { 291 vo, err := FromInterface(e) 292 if err != nil { 293 return nil, err 294 } 295 arr[i] = vo 296 } 297 return &Array{Value: arr}, nil 298 case time.Time: 299 return &Time{Value: v}, nil 300 case Object: 301 return v, nil 302 case CallableFunc: 303 return &UserFunction{Value: v}, nil 304 } 305 return nil, fmt.Errorf("cannot convert to object: %T", v) 306} 307