diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/robertkrimen/otto/value.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/robertkrimen/otto/value.go | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go b/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go new file mode 100644 index 000000000..05d61dd62 --- /dev/null +++ b/Godeps/_workspace/src/github.com/robertkrimen/otto/value.go @@ -0,0 +1,989 @@ +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 (vl Value) safe() bool { + return vl.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", "invalid value (struct): missing runtime: %v (%T)", value, value)) + case reflect.Map: + panic(newError(nil, "TypeError", "invalid value (map): missing runtime: %v (%T)", value, value)) + case reflect.Slice: + panic(newError(nil, "TypeError", "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", "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) + for index := uint32(0); index < length; index += 1 { + name := strconv.FormatInt(int64(index), 10) + if !object.hasProperty(name) { + continue + } + value := object.get(name) + result = append(result, value.export()) + } + return result + } 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) { + 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 < 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)) +} |