aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/value.go
blob: 90c1406040eb0add3f582ad3e4b6e5e29f70ec3b (plain) (tree)
1
2
3
4
5
6
7
8
9
10









                       
                   

       
                                        
                 



                    


                                                   





                                                     
                        


                         

                                      








                                                            
                                                                                     
  

                                                                                      
                                                
                         





                                       
                                   
                                       





                                                             
                      



                                                                             
                                           



                                                                               
                                           



                                                   
                                     



                                                                     
                                      






                                            
                                     



                    











                                                                                 
                         
                                  

                                                               
          


                               


                          
                                                                                      

                                               
                                                                                                              
         



                                        

 

                                                                                                        
                                  
                                                                   



                          

                                                                                           
                      
                                                                             
         



                                        








                                                                                
                                         



                                                              
                                        














                                                                    
                                          



                                                              
                                        



                                                   
                                        



                                                      
                                      


















                                                                                                 
                                      





                                           
                                      





                                              
                                      





                                                       
                                      





                                                        
                                      





                                                       
                                      





                                                     
                                      





                                                       
                                      







                                                                      
                 

                            
                                                                                                                      
                         
                                                                                                                   
                           
                                                                                                                     

















































                                                                         
                              







                                                                                                                       
                                              





































                                                                                  
                 
                                                                                    







                                                                      
                                       



                     











                                                                                                                               
                                     



                          




                                                  











                                                                                                                           
                                        













                                                                                                                           
                                             



                          











                                                                                                                                               
                                       






























                                                                                                                                                 







                                            






































































                                                                          
                             


                            
                       


                                       

                                









                                                                           
                                                 
                          
                                             









                                                      
                             


                            
                       


                                       

                                





                                                   
                                                 
                          
                                             











                                                                  

                                                                    

                                                                
                     
  

                                                      











                                                                
                          




























                                                            


                                               




                                                                            
                                                                  
 
                                                         





                                                    
                                               
                                                
                                                 
                                                                   

                                                 
 
                                                              
                         
 
                                                                                









                                                                                              













                                                                                        




                           



























                                                                        
                          





























                                                          

                                                                                  
                                                                             














                                                                                                                     
                     


                                                         



                                                                                          
                                                                                                    


                                                             

                                           




                                                                                                     

                                           




                                                                                                      

                                           




                                                                                                      
                                    



                                                                                          
                                                                                                    


                                                               
                                  



                                                                                          
                                                                                                     


                                                              

                                           




                                                                                                      

                                           




                                                                                                       

                                           




                                                                                                       
                                      







                                                                                                       

                                        



                                    
                                                                                               



                                                                                                        

                                        
                                                           




























                                                                                 

         

                                                                                                       





















































































                                                                                   

                                                                                      
 
package otto

import (
    "fmt"
    "math"
    "reflect"
    "strconv"
    "unicode/utf16"
)

type _valueKind int

const (
    valueUndefined _valueKind = iota
    valueNull
    valueNumber
    valueString
    valueBoolean
    valueObject

    // These are invalid outside of the runtime
    valueEmpty
    valueResult
    valueReference
)

// Value is the representation of a JavaScript value.
type Value struct {
    kind  _valueKind
    value interface{}
}

func (value Value) safe() bool {
    return value.kind < valueEmpty
}

var (
    emptyValue = Value{kind: valueEmpty}
    nullValue  = Value{kind: valueNull}
    falseValue = Value{kind: valueBoolean, value: false}
    trueValue  = Value{kind: valueBoolean, value: true}
)

// ToValue will convert an interface{} value to a value digestible by otto/JavaScript
//
// This function will not work for advanced types (struct, map, slice/array, etc.) and
// you should use Otto.ToValue instead.
func ToValue(value interface{}) (Value, error) {
    result := Value{}
    err := catchPanic(func() {
        result = toValue(value)
    })
    return result, err
}

func (value Value) isEmpty() bool {
    return value.kind == valueEmpty
}

// Undefined

// UndefinedValue will return a Value representing undefined.
func UndefinedValue() Value {
    return Value{}
}

// IsDefined will return false if the value is undefined, and true otherwise.
func (value Value) IsDefined() bool {
    return value.kind != valueUndefined
}

// IsUndefined will return true if the value is undefined, and false otherwise.
func (value Value) IsUndefined() bool {
    return value.kind == valueUndefined
}

// NullValue will return a Value representing null.
func NullValue() Value {
    return Value{kind: valueNull}
}

// IsNull will return true if the value is null, and false otherwise.
func (value Value) IsNull() bool {
    return value.kind == valueNull
}

// ---

func (value Value) isCallable() bool {
    switch value := value.value.(type) {
    case *_object:
        return value.isCall()
    }
    return false
}

// Call the value as a function with the given this value and argument list and
// return the result of invocation. It is essentially equivalent to:
//
//      value.apply(thisValue, argumentList)
//
// An undefined value and an error will result if:
//
//      1. There is an error during conversion of the argument list
//      2. The value is not actually a function
//      3. An (uncaught) exception is thrown
//
func (value Value) Call(this Value, argumentList ...interface{}) (Value, error) {
    result := Value{}
    err := catchPanic(func() {
        // FIXME
        result = value.call(nil, this, argumentList...)
    })
    if !value.safe() {
        value = Value{}
    }
    return result, err
}

func (value Value) call(rt *_runtime, this Value, argumentList ...interface{}) Value {
    switch function := value.value.(type) {
    case *_object:
        return function.call(this, function.runtime.toValueArray(argumentList...), false, nativeFrame)
    }
    if rt == nil {
        panic("FIXME TypeError")
    }
    panic(rt.panicTypeError())
}

func (value Value) constructSafe(rt *_runtime, this Value, argumentList ...interface{}) (Value, error) {
    result := Value{}
    err := catchPanic(func() {
        result = value.construct(rt, this, argumentList...)
    })
    return result, err
}

func (value Value) construct(rt *_runtime, this Value, argumentList ...interface{}) Value {
    switch fn := value.value.(type) {
    case *_object:
        return fn.construct(fn.runtime.toValueArray(argumentList...))
    }
    if rt == nil {
        panic("FIXME TypeError")
    }
    panic(rt.panicTypeError())
}

// IsPrimitive will return true if value is a primitive (any kind of primitive).
func (value Value) IsPrimitive() bool {
    return !value.IsObject()
}

// IsBoolean will return true if value is a boolean (primitive).
func (value Value) IsBoolean() bool {
    return value.kind == valueBoolean
}

// IsNumber will return true if value is a number (primitive).
func (value Value) IsNumber() bool {
    return value.kind == valueNumber
}

// IsNaN will return true if value is NaN (or would convert to NaN).
func (value Value) IsNaN() bool {
    switch value := value.value.(type) {
    case float64:
        return math.IsNaN(value)
    case float32:
        return math.IsNaN(float64(value))
    case int, int8, int32, int64:
        return false
    case uint, uint8, uint32, uint64:
        return false
    }

    return math.IsNaN(value.float64())
}

// IsString will return true if value is a string (primitive).
func (value Value) IsString() bool {
    return value.kind == valueString
}

// IsObject will return true if value is an object.
func (value Value) IsObject() bool {
    return value.kind == valueObject
}

// IsFunction will return true if value is a function.
func (value Value) IsFunction() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "Function"
}

// Class will return the class string of the value or the empty string if value is not an object.
//
// The return value will (generally) be one of:
//
//      Object
//      Function
//      Array
//      String
//      Number
//      Boolean
//      Date
//      RegExp
//
func (value Value) Class() string {
    if value.kind != valueObject {
        return ""
    }
    return value.value.(*_object).class
}

func (value Value) isArray() bool {
    if value.kind != valueObject {
        return false
    }
    return isArray(value.value.(*_object))
}

func (value Value) isStringObject() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "String"
}

func (value Value) isBooleanObject() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "Boolean"
}

func (value Value) isNumberObject() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "Number"
}

func (value Value) isDate() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "Date"
}

func (value Value) isRegExp() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "RegExp"
}

func (value Value) isError() bool {
    if value.kind != valueObject {
        return false
    }
    return value.value.(*_object).class == "Error"
}

// ---

func toValue_reflectValuePanic(value interface{}, kind reflect.Kind) {
    // FIXME?
    switch kind {
    case reflect.Struct:
        panic(newError(nil, "TypeError", 0, "invalid value (struct): missing runtime: %v (%T)", value, value))
    case reflect.Map:
        panic(newError(nil, "TypeError", 0, "invalid value (map): missing runtime: %v (%T)", value, value))
    case reflect.Slice:
        panic(newError(nil, "TypeError", 0, "invalid value (slice): missing runtime: %v (%T)", value, value))
    }
}

func toValue(value interface{}) Value {
    switch value := value.(type) {
    case Value:
        return value
    case bool:
        return Value{valueBoolean, value}
    case int:
        return Value{valueNumber, value}
    case int8:
        return Value{valueNumber, value}
    case int16:
        return Value{valueNumber, value}
    case int32:
        return Value{valueNumber, value}
    case int64:
        return Value{valueNumber, value}
    case uint:
        return Value{valueNumber, value}
    case uint8:
        return Value{valueNumber, value}
    case uint16:
        return Value{valueNumber, value}
    case uint32:
        return Value{valueNumber, value}
    case uint64:
        return Value{valueNumber, value}
    case float32:
        return Value{valueNumber, float64(value)}
    case float64:
        return Value{valueNumber, value}
    case []uint16:
        return Value{valueString, value}
    case string:
        return Value{valueString, value}
    // A rune is actually an int32, which is handled above
    case *_object:
        return Value{valueObject, value}
    case *Object:
        return Value{valueObject, value.object}
    case Object:
        return Value{valueObject, value.object}
    case _reference: // reference is an interface (already a pointer)
        return Value{valueReference, value}
    case _result:
        return Value{valueResult, value}
    case nil:
        // TODO Ugh.
        return Value{}
    case reflect.Value:
        for value.Kind() == reflect.Ptr {
            // We were given a pointer, so we'll drill down until we get a non-pointer
            //
            // These semantics might change if we want to start supporting pointers to values transparently
            // (It would be best not to depend on this behavior)
            // FIXME: UNDEFINED
            if value.IsNil() {
                return Value{}
            }
            value = value.Elem()
        }
        switch value.Kind() {
        case reflect.Bool:
            return Value{valueBoolean, bool(value.Bool())}
        case reflect.Int:
            return Value{valueNumber, int(value.Int())}
        case reflect.Int8:
            return Value{valueNumber, int8(value.Int())}
        case reflect.Int16:
            return Value{valueNumber, int16(value.Int())}
        case reflect.Int32:
            return Value{valueNumber, int32(value.Int())}
        case reflect.Int64:
            return Value{valueNumber, int64(value.Int())}
        case reflect.Uint:
            return Value{valueNumber, uint(value.Uint())}
        case reflect.Uint8:
            return Value{valueNumber, uint8(value.Uint())}
        case reflect.Uint16:
            return Value{valueNumber, uint16(value.Uint())}
        case reflect.Uint32:
            return Value{valueNumber, uint32(value.Uint())}
        case reflect.Uint64:
            return Value{valueNumber, uint64(value.Uint())}
        case reflect.Float32:
            return Value{valueNumber, float32(value.Float())}
        case reflect.Float64:
            return Value{valueNumber, float64(value.Float())}
        case reflect.String:
            return Value{valueString, string(value.String())}
        default:
            toValue_reflectValuePanic(value.Interface(), value.Kind())
        }
    default:
        return toValue(reflect.ValueOf(value))
    }
    // FIXME?
    panic(newError(nil, "TypeError", 0, "invalid value: %v (%T)", value, value))
}

// String will return the value as a string.
//
// This method will make return the empty string if there is an error.
func (value Value) String() string {
    result := ""
    catchPanic(func() {
        result = value.string()
    })
    return result
}

// ToBoolean will convert the value to a boolean (bool).
//
//      ToValue(0).ToBoolean() => false
//      ToValue("").ToBoolean() => false
//      ToValue(true).ToBoolean() => true
//      ToValue(1).ToBoolean() => true
//      ToValue("Nothing happens").ToBoolean() => true
//
// If there is an error during the conversion process (like an uncaught exception), then the result will be false and an error.
func (value Value) ToBoolean() (bool, error) {
    result := false
    err := catchPanic(func() {
        result = value.bool()
    })
    return result, err
}

func (value Value) numberValue() Value {
    if value.kind == valueNumber {
        return value
    }
    return Value{valueNumber, value.float64()}
}

// ToFloat will convert the value to a number (float64).
//
//      ToValue(0).ToFloat() => 0.
//      ToValue(1.1).ToFloat() => 1.1
//      ToValue("11").ToFloat() => 11.
//
// If there is an error during the conversion process (like an uncaught exception), then the result will be 0 and an error.
func (value Value) ToFloat() (float64, error) {
    result := float64(0)
    err := catchPanic(func() {
        result = value.float64()
    })
    return result, err
}

// ToInteger will convert the value to a number (int64).
//
//      ToValue(0).ToInteger() => 0
//      ToValue(1.1).ToInteger() => 1
//      ToValue("11").ToInteger() => 11
//
// If there is an error during the conversion process (like an uncaught exception), then the result will be 0 and an error.
func (value Value) ToInteger() (int64, error) {
    result := int64(0)
    err := catchPanic(func() {
        result = value.number().int64
    })
    return result, err
}

// ToString will convert the value to a string (string).
//
//      ToValue(0).ToString() => "0"
//      ToValue(false).ToString() => "false"
//      ToValue(1.1).ToString() => "1.1"
//      ToValue("11").ToString() => "11"
//      ToValue('Nothing happens.').ToString() => "Nothing happens."
//
// If there is an error during the conversion process (like an uncaught exception), then the result will be the empty string ("") and an error.
func (value Value) ToString() (string, error) {
    result := ""
    err := catchPanic(func() {
        result = value.string()
    })
    return result, err
}

func (value Value) _object() *_object {
    switch value := value.value.(type) {
    case *_object:
        return value
    }
    return nil
}

// Object will return the object of the value, or nil if value is not an object.
//
// This method will not do any implicit conversion. For example, calling this method on a string primitive value will not return a String object.
func (value Value) Object() *Object {
    switch object := value.value.(type) {
    case *_object:
        return _newObject(object, value)
    }
    return nil
}

func (value Value) reference() _reference {
    switch value := value.value.(type) {
    case _reference:
        return value
    }
    return nil
}

func (value Value) resolve() Value {
    switch value := value.value.(type) {
    case _reference:
        return value.getValue()
    }
    return value
}

var (
    __NaN__              float64 = math.NaN()
    __PositiveInfinity__ float64 = math.Inf(+1)
    __NegativeInfinity__ float64 = math.Inf(-1)
    __PositiveZero__     float64 = 0
    __NegativeZero__     float64 = math.Float64frombits(0 | (1 << 63))
)

func positiveInfinity() float64 {
    return __PositiveInfinity__
}

func negativeInfinity() float64 {
    return __NegativeInfinity__
}

func positiveZero() float64 {
    return __PositiveZero__
}

func negativeZero() float64 {
    return __NegativeZero__
}

// NaNValue will return a value representing NaN.
//
// It is equivalent to:
//
//      ToValue(math.NaN())
//
func NaNValue() Value {
    return Value{valueNumber, __NaN__}
}

func positiveInfinityValue() Value {
    return Value{valueNumber, __PositiveInfinity__}
}

func negativeInfinityValue() Value {
    return Value{valueNumber, __NegativeInfinity__}
}

func positiveZeroValue() Value {
    return Value{valueNumber, __PositiveZero__}
}

func negativeZeroValue() Value {
    return Value{valueNumber, __NegativeZero__}
}

// TrueValue will return a value representing true.
//
// It is equivalent to:
//
//      ToValue(true)
//
func TrueValue() Value {
    return Value{valueBoolean, true}
}

// FalseValue will return a value representing false.
//
// It is equivalent to:
//
//      ToValue(false)
//
func FalseValue() Value {
    return Value{valueBoolean, false}
}

func sameValue(x Value, y Value) bool {
    if x.kind != y.kind {
        return false
    }
    result := false
    switch x.kind {
    case valueUndefined, valueNull:
        result = true
    case valueNumber:
        x := x.float64()
        y := y.float64()
        if math.IsNaN(x) && math.IsNaN(y) {
            result = true
        } else {
            result = x == y
            if result && x == 0 {
                // Since +0 != -0
                result = math.Signbit(x) == math.Signbit(y)
            }
        }
    case valueString:
        result = x.string() == y.string()
    case valueBoolean:
        result = x.bool() == y.bool()
    case valueObject:
        result = x._object() == y._object()
    default:
        panic(hereBeDragons())
    }

    return result
}

func strictEqualityComparison(x Value, y Value) bool {
    if x.kind != y.kind {
        return false
    }
    result := false
    switch x.kind {
    case valueUndefined, valueNull:
        result = true
    case valueNumber:
        x := x.float64()
        y := y.float64()
        if math.IsNaN(x) && math.IsNaN(y) {
            result = false
        } else {
            result = x == y
        }
    case valueString:
        result = x.string() == y.string()
    case valueBoolean:
        result = x.bool() == y.bool()
    case valueObject:
        result = x._object() == y._object()
    default:
        panic(hereBeDragons())
    }

    return result
}

// Export will attempt to convert the value to a Go representation
// and return it via an interface{} kind.
//
// Export returns an error, but it will always be nil. It is present
// for backwards compatibility.
//
// If a reasonable conversion is not possible, then the original
// value is returned.
//
//      undefined   -> nil (FIXME?: Should be Value{})
//      null        -> nil
//      boolean     -> bool
//      number      -> A number type (int, float32, uint64, ...)
//      string      -> string
//      Array       -> []interface{}
//      Object      -> map[string]interface{}
//
func (self Value) Export() (interface{}, error) {
    return self.export(), nil
}

func (self Value) export() interface{} {

    switch self.kind {
    case valueUndefined:
        return nil
    case valueNull:
        return nil
    case valueNumber, valueBoolean:
        return self.value
    case valueString:
        switch value := self.value.(type) {
        case string:
            return value
        case []uint16:
            return string(utf16.Decode(value))
        }
    case valueObject:
        object := self._object()
        switch value := object.value.(type) {
        case *_goStructObject:
            return value.value.Interface()
        case *_goMapObject:
            return value.value.Interface()
        case *_goArrayObject:
            return value.value.Interface()
        case *_goSliceObject:
            return value.value.Interface()
        }
        if object.class == "Array" {
            result := make([]interface{}, 0)
            lengthValue := object.get("length")
            length := lengthValue.value.(uint32)
            kind := reflect.Invalid
            state := 0
            var t reflect.Type
            for index := uint32(0); index < length; index += 1 {
                name := strconv.FormatInt(int64(index), 10)
                if !object.hasProperty(name) {
                    continue
                }
                value := object.get(name).export()

                t = reflect.TypeOf(value)

                var k reflect.Kind
                if t != nil {
                    k = t.Kind()
                }

                if state == 0 {
                    kind = k
                    state = 1
                } else if state == 1 && kind != k {
                    state = 2
                }

                result = append(result, value)
            }

            if state != 1 || kind == reflect.Interface || t == nil {
                // No common type
                return result
            }

            // Convert to the common type
            val := reflect.MakeSlice(reflect.SliceOf(t), len(result), len(result))
            for i, v := range result {
                val.Index(i).Set(reflect.ValueOf(v))
            }
            return val.Interface()
        } else {
            result := make(map[string]interface{})
            // TODO Should we export everything? Or just what is enumerable?
            object.enumerate(false, func(name string) bool {
                value := object.get(name)
                if value.IsDefined() {
                    result[name] = value.export()
                }
                return true
            })
            return result
        }
    }

    if self.safe() {
        return self
    }

    return Value{}
}

func (self Value) evaluateBreakContinue(labels []string) _resultKind {
    result := self.value.(_result)
    if result.kind == resultBreak || result.kind == resultContinue {
        for _, label := range labels {
            if label == result.target {
                return result.kind
            }
        }
    }
    return resultReturn
}

func (self Value) evaluateBreak(labels []string) _resultKind {
    result := self.value.(_result)
    if result.kind == resultBreak {
        for _, label := range labels {
            if label == result.target {
                return result.kind
            }
        }
    }
    return resultReturn
}

func (self Value) exportNative() interface{} {

    switch self.kind {
    case valueUndefined:
        return self
    case valueNull:
        return nil
    case valueNumber, valueBoolean:
        return self.value
    case valueString:
        switch value := self.value.(type) {
        case string:
            return value
        case []uint16:
            return string(utf16.Decode(value))
        }
    case valueObject:
        object := self._object()
        switch value := object.value.(type) {
        case *_goStructObject:
            return value.value.Interface()
        case *_goMapObject:
            return value.value.Interface()
        case *_goArrayObject:
            return value.value.Interface()
        case *_goSliceObject:
            return value.value.Interface()
        }
    }

    return self
}

// Make a best effort to return a reflect.Value corresponding to reflect.Kind, but
// fallback to just returning the Go value we have handy.
func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) {
    if kind != reflect.Float32 && kind != reflect.Float64 && kind != reflect.Interface {
        switch value := value.value.(type) {
        case float32:
            _, frac := math.Modf(float64(value))
            if frac > 0 {
                return reflect.Value{}, fmt.Errorf("RangeError: %v to reflect.Kind: %v", value, kind)
            }
        case float64:
            _, frac := math.Modf(value)
            if frac > 0 {
                return reflect.Value{}, fmt.Errorf("RangeError: %v to reflect.Kind: %v", value, kind)
            }
        }
    }

    switch kind {
    case reflect.Bool: // Bool
        return reflect.ValueOf(value.bool()), nil
    case reflect.Int: // Int
        // We convert to float64 here because converting to int64 will not tell us
        // if a value is outside the range of int64
        tmp := toIntegerFloat(value)
        if tmp < float_minInt || tmp > float_maxInt {
            return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to int", tmp, value)
        } else {
            return reflect.ValueOf(int(tmp)), nil
        }
    case reflect.Int8: // Int8
        tmp := value.number().int64
        if tmp < int64_minInt8 || tmp > int64_maxInt8 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int8", tmp, value)
        } else {
            return reflect.ValueOf(int8(tmp)), nil
        }
    case reflect.Int16: // Int16
        tmp := value.number().int64
        if tmp < int64_minInt16 || tmp > int64_maxInt16 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int16", tmp, value)
        } else {
            return reflect.ValueOf(int16(tmp)), nil
        }
    case reflect.Int32: // Int32
        tmp := value.number().int64
        if tmp < int64_minInt32 || tmp > int64_maxInt32 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int32", tmp, value)
        } else {
            return reflect.ValueOf(int32(tmp)), nil
        }
    case reflect.Int64: // Int64
        // We convert to float64 here because converting to int64 will not tell us
        // if a value is outside the range of int64
        tmp := toIntegerFloat(value)
        if tmp < float_minInt64 || tmp > float_maxInt64 {
            return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to int", tmp, value)
        } else {
            return reflect.ValueOf(int64(tmp)), nil
        }
    case reflect.Uint: // Uint
        // We convert to float64 here because converting to int64 will not tell us
        // if a value is outside the range of uint
        tmp := toIntegerFloat(value)
        if tmp < 0 || tmp > float_maxUint {
            return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to uint", tmp, value)
        } else {
            return reflect.ValueOf(uint(tmp)), nil
        }
    case reflect.Uint8: // Uint8
        tmp := value.number().int64
        if tmp < 0 || tmp > int64_maxUint8 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint8", tmp, value)
        } else {
            return reflect.ValueOf(uint8(tmp)), nil
        }
    case reflect.Uint16: // Uint16
        tmp := value.number().int64
        if tmp < 0 || tmp > int64_maxUint16 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint16", tmp, value)
        } else {
            return reflect.ValueOf(uint16(tmp)), nil
        }
    case reflect.Uint32: // Uint32
        tmp := value.number().int64
        if tmp < 0 || tmp > int64_maxUint32 {
            return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint32", tmp, value)
        } else {
            return reflect.ValueOf(uint32(tmp)), nil
        }
    case reflect.Uint64: // Uint64
        // We convert to float64 here because converting to int64 will not tell us
        // if a value is outside the range of uint64
        tmp := toIntegerFloat(value)
        if tmp < 0 || tmp > float_maxUint64 {
            return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to uint64", tmp, value)
        } else {
            return reflect.ValueOf(uint64(tmp)), nil
        }
    case reflect.Float32: // Float32
        tmp := value.float64()
        tmp1 := tmp
        if 0 > tmp1 {
            tmp1 = -tmp1
        }
        if tmp1 > 0 && (tmp1 < math.SmallestNonzeroFloat32 || tmp1 > math.MaxFloat32) {
            return reflect.Value{}, fmt.Errorf("RangeError: %f (%v) to float32", tmp, value)
        } else {
            return reflect.ValueOf(float32(tmp)), nil
        }
    case reflect.Float64: // Float64
        value := value.float64()
        return reflect.ValueOf(float64(value)), nil
    case reflect.String: // String
        return reflect.ValueOf(value.string()), nil
    case reflect.Invalid: // Invalid
    case reflect.Complex64: // FIXME? Complex64
    case reflect.Complex128: // FIXME? Complex128
    case reflect.Chan: // FIXME? Chan
    case reflect.Func: // FIXME? Func
    case reflect.Ptr: // FIXME? Ptr
    case reflect.UnsafePointer: // FIXME? UnsafePointer
    default:
        switch value.kind {
        case valueObject:
            object := value._object()
            switch vl := object.value.(type) {
            case *_goStructObject: // Struct
                return reflect.ValueOf(vl.value.Interface()), nil
            case *_goMapObject: // Map
                return reflect.ValueOf(vl.value.Interface()), nil
            case *_goArrayObject: // Array
                return reflect.ValueOf(vl.value.Interface()), nil
            case *_goSliceObject: // Slice
                return reflect.ValueOf(vl.value.Interface()), nil
            }
            return reflect.ValueOf(value.exportNative()), nil
        case valueEmpty, valueResult, valueReference:
            // These are invalid, and should panic
        default:
            return reflect.ValueOf(value.value), nil
        }
    }

    // FIXME Should this end up as a TypeError?
    panic(fmt.Errorf("invalid conversion of %v (%v) to reflect.Kind: %v", value.kind, value, kind))
}

func stringToReflectValue(value string, kind reflect.Kind) (reflect.Value, error) {
    switch kind {
    case reflect.Bool:
        value, err := strconv.ParseBool(value)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(value), nil
    case reflect.Int:
        value, err := strconv.ParseInt(value, 0, 0)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(int(value)), nil
    case reflect.Int8:
        value, err := strconv.ParseInt(value, 0, 8)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(int8(value)), nil
    case reflect.Int16:
        value, err := strconv.ParseInt(value, 0, 16)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(int16(value)), nil
    case reflect.Int32:
        value, err := strconv.ParseInt(value, 0, 32)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(int32(value)), nil
    case reflect.Int64:
        value, err := strconv.ParseInt(value, 0, 64)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(int64(value)), nil
    case reflect.Uint:
        value, err := strconv.ParseUint(value, 0, 0)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(uint(value)), nil
    case reflect.Uint8:
        value, err := strconv.ParseUint(value, 0, 8)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(uint8(value)), nil
    case reflect.Uint16:
        value, err := strconv.ParseUint(value, 0, 16)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(uint16(value)), nil
    case reflect.Uint32:
        value, err := strconv.ParseUint(value, 0, 32)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(uint32(value)), nil
    case reflect.Uint64:
        value, err := strconv.ParseUint(value, 0, 64)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(uint64(value)), nil
    case reflect.Float32:
        value, err := strconv.ParseFloat(value, 32)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(float32(value)), nil
    case reflect.Float64:
        value, err := strconv.ParseFloat(value, 64)
        if err != nil {
            return reflect.Value{}, err
        }
        return reflect.ValueOf(float64(value)), nil
    case reflect.String:
        return reflect.ValueOf(value), nil
    }

    // FIXME This should end up as a TypeError?
    panic(fmt.Errorf("invalid conversion of %q to reflect.Kind: %v", value, kind))
}