forked from lug/matterbridge
		
	
		
			
				
	
	
		
			307 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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
 | 
						|
)
 | 
						|
 | 
						|
// 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)
 | 
						|
}
 |