diff --git a/bug_test.go b/bug_test.go index 0dd1b01..7c072c8 100644 --- a/bug_test.go +++ b/bug_test.go @@ -55,7 +55,7 @@ func Test_issue13(t *testing.T) { t.Error(err) t.FailNow() } - is(result.toString(), "Xyzzy,42,def,ghi") + is(result.string(), "Xyzzy,42,def,ghi") anything := struct { Abc interface{} diff --git a/builtin.go b/builtin.go index 7e911bd..9562e86 100644 --- a/builtin.go +++ b/builtin.go @@ -18,7 +18,7 @@ func builtinGlobal_eval(call FunctionCall) Value { return src } runtime := call.runtime - program := runtime.cmpl_parseOrThrow(toString(src)) + program := runtime.cmpl_parseOrThrow(src.string()) if !call.eval { // Not a direct call to eval, so we enter the global ExecutionContext runtime.enterGlobalScope() @@ -32,12 +32,12 @@ func builtinGlobal_eval(call FunctionCall) Value { } func builtinGlobal_isNaN(call FunctionCall) Value { - value := toFloat(call.Argument(0)) + value := call.Argument(0).float64() return toValue_bool(math.IsNaN(value)) } func builtinGlobal_isFinite(call FunctionCall) Value { - value := toFloat(call.Argument(0)) + value := call.Argument(0).float64() return toValue_bool(!math.IsNaN(value) && !math.IsInf(value, 0)) } @@ -70,7 +70,7 @@ func digitValue(chr rune) int { } func builtinGlobal_parseInt(call FunctionCall) Value { - input := strings.TrimSpace(toString(call.Argument(0))) + input := strings.TrimSpace(call.Argument(0).string()) if len(input) == 0 { return NaNValue() } @@ -153,7 +153,7 @@ var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`) func builtinGlobal_parseFloat(call FunctionCall) Value { // Caveat emptor: This implementation does NOT match the specification - input := strings.TrimSpace(toString(call.Argument(0))) + input := strings.TrimSpace(call.Argument(0).string()) if parseFloat_matchBadSpecial.MatchString(input) { return NaNValue() } @@ -185,7 +185,7 @@ func _builtinGlobal_encodeURI(call FunctionCall, escape *regexp.Regexp) Value { case []uint16: input = vl default: - input = utf16.Encode([]rune(toString(value))) + input = utf16.Encode([]rune(value.string())) } if len(input) == 0 { return toValue_string("") @@ -256,7 +256,7 @@ func _decodeURI(input string, reserve bool) (string, bool) { } func builtinGlobal_decodeURI(call FunctionCall) Value { - output, err := _decodeURI(toString(call.Argument(0)), true) + output, err := _decodeURI(call.Argument(0).string(), true) if err { panic(newURIError("URI malformed")) } @@ -264,7 +264,7 @@ func builtinGlobal_decodeURI(call FunctionCall) Value { } func builtinGlobal_decodeURIComponent(call FunctionCall) Value { - output, err := _decodeURI(toString(call.Argument(0)), false) + output, err := _decodeURI(call.Argument(0).string(), false) if err { panic(newURIError("URI malformed")) } @@ -345,9 +345,9 @@ func builtin_unescape(input string) string { } func builtinGlobal_escape(call FunctionCall) Value { - return toValue_string(builtin_escape(toString(call.Argument(0)))) + return toValue_string(builtin_escape(call.Argument(0).string())) } func builtinGlobal_unescape(call FunctionCall) Value { - return toValue_string(builtin_unescape(toString(call.Argument(0)))) + return toValue_string(builtin_unescape(call.Argument(0).string())) } diff --git a/builtin_array.go b/builtin_array.go index 26eb37c..87af242 100644 --- a/builtin_array.go +++ b/builtin_array.go @@ -54,7 +54,7 @@ func builtinArray_toLocaleString(call FunctionCall) Value { if !toLocaleString.isCallable() { panic(newTypeError()) } - stringValue = toLocaleString.call(toValue_object(object)).toString() + stringValue = toLocaleString.call(toValue_object(object)).string() } stringList = append(stringList, stringValue) } @@ -70,7 +70,7 @@ func builtinArray_concat(call FunctionCall) Value { case valueObject: object := item._object() if isArray(object) { - length := toInteger(object.get("length")).int64 + length := object.get("length").number().int64 for index := int64(0); index < length; index += 1 { name := strconv.FormatInt(index, 10) if object.hasProperty(name) { @@ -143,7 +143,7 @@ func builtinArray_join(call FunctionCall) Value { { argument := call.Argument(0) if argument.IsDefined() { - separator = toString(argument) + separator = argument.string() } } thisObject := call.thisObject() @@ -158,7 +158,7 @@ func builtinArray_join(call FunctionCall) Value { switch value.kind { case valueEmpty, valueUndefined, valueNull: default: - stringValue = toString(value) + stringValue = value.string() } stringList = append(stringList, stringValue) } @@ -370,8 +370,8 @@ func sortCompare(thisObject *_object, index0, index1 uint, compare *_object) int } if compare == nil { - j.value = toString(x) - k.value = toString(y) + j.value = x.string() + k.value = y.string() if j.value == k.value { return 0 @@ -464,7 +464,7 @@ func builtinArray_indexOf(call FunctionCall) Value { if length := int64(toUint32(thisObject.get("length"))); length > 0 { index := int64(0) if len(call.ArgumentList) > 1 { - index = toInteger(call.Argument(1)).int64 + index = call.Argument(1).number().int64 } if index < 0 { if index += length; index < 0 { @@ -492,7 +492,7 @@ func builtinArray_lastIndexOf(call FunctionCall) Value { length := int64(toUint32(thisObject.get("length"))) index := length - 1 if len(call.ArgumentList) > 1 { - index = toInteger(call.Argument(1)).int64 + index = call.Argument(1).number().int64 } if 0 > index { index += length @@ -523,7 +523,7 @@ func builtinArray_every(call FunctionCall) Value { callThis := call.Argument(1) for index := int64(0); index < length; index++ { if key := arrayIndexToString(index); thisObject.hasProperty(key) { - if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() { + if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).bool() { continue } return falseValue @@ -542,7 +542,7 @@ func builtinArray_some(call FunctionCall) Value { callThis := call.Argument(1) for index := int64(0); index < length; index++ { if key := arrayIndexToString(index); thisObject.hasProperty(key) { - if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).isTrue() { + if value := thisObject.get(key); iterator.call(callThis, value, toValue_int64(index), this).bool() { return trueValue } } @@ -597,7 +597,7 @@ func builtinArray_filter(call FunctionCall) Value { for index := int64(0); index < length; index++ { if key := arrayIndexToString(index); thisObject.hasProperty(key) { value := thisObject.get(key) - if iterator.call(callThis, value, index, this).isTrue() { + if iterator.call(callThis, value, index, this).bool() { values = append(values, value) } } diff --git a/builtin_boolean.go b/builtin_boolean.go index bedfe26..59b8e78 100644 --- a/builtin_boolean.go +++ b/builtin_boolean.go @@ -3,7 +3,7 @@ package otto // Boolean func builtinBoolean(call FunctionCall) Value { - return toValue_bool(toBoolean(call.Argument(0))) + return toValue_bool(call.Argument(0).bool()) } func builtinNewBoolean(self *_object, argumentList []Value) Value { @@ -16,7 +16,7 @@ func builtinBoolean_toString(call FunctionCall) Value { // Will throw a TypeError if ThisObject is not a Boolean value = call.thisClassObject("Boolean").primitiveValue() } - return toValue_string(toString(value)) + return toValue_string(value.string()) } func builtinBoolean_valueOf(call FunctionCall) Value { diff --git a/builtin_date.go b/builtin_date.go index 444bb76..a31c3e0 100644 --- a/builtin_date.go +++ b/builtin_date.go @@ -69,7 +69,7 @@ func builtinDate_toJSON(call FunctionCall) Value { object := call.thisObject() value := object.DefaultValue(defaultValueHintNumber) // FIXME object.primitiveNumberValue { // FIXME value.isFinite - value := toFloat(value) + value := value.float64() if math.IsNaN(value) || math.IsInf(value, 0) { return nullValue } @@ -102,7 +102,7 @@ func builtinDate_getTime(call FunctionCall) Value { func builtinDate_setTime(call FunctionCall) Value { object := call.thisObject() date := dateObjectOf(object) - date.Set(toFloat(call.Argument(0))) + date.Set(call.Argument(0).float64()) object.value = date return date.Value() } @@ -126,16 +126,14 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool valueList := make([]int, argumentLimit) for index := 0; index < argumentLimit; index++ { value := call.ArgumentList[index] - if value.IsNaN() { + nm := value.number() + switch nm.kind { + case numberInteger, numberFloat: + default: object.value = invalidDateObject return nil, nil, nil, nil } - integer := toInteger(value) - if !integer.valid() { - object.value = invalidDateObject - return nil, nil, nil, nil - } - valueList[index] = int(integer.int64) + valueList[index] = int(nm.int64) } baseTime := date.Time() if timeLocal { @@ -146,7 +144,7 @@ func _builtinDate_beforeSet(call FunctionCall, argumentLimit int, timeLocal bool } func builtinDate_parse(call FunctionCall) Value { - date := toString(call.Argument(0)) + date := call.Argument(0).string() return toValue_float64(dateParse(date)) } diff --git a/builtin_error.go b/builtin_error.go index f0daa69..447c5fe 100644 --- a/builtin_error.go +++ b/builtin_error.go @@ -21,13 +21,13 @@ func builtinError_toString(call FunctionCall) Value { name := "Error" nameValue := thisObject.get("name") if nameValue.IsDefined() { - name = toString(nameValue) + name = nameValue.string() } message := "" messageValue := thisObject.get("message") if messageValue.IsDefined() { - message = toString(messageValue) + message = messageValue.string() } if len(name) == 0 { diff --git a/builtin_function.go b/builtin_function.go index e9be383..2b360df 100644 --- a/builtin_function.go +++ b/builtin_function.go @@ -22,7 +22,7 @@ func builtinNewFunction(self *_object, argumentList []Value) Value { func argumentList2parameterList(argumentList []Value) []string { parameterList := make([]string, 0, len(argumentList)) for _, value := range argumentList { - tmp := strings.FieldsFunc(toString(value), func(chr rune) bool { + tmp := strings.FieldsFunc(value.string(), func(chr rune) bool { return chr == ',' || unicode.IsSpace(chr) }) parameterList = append(parameterList, tmp...) @@ -38,10 +38,10 @@ func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object if count > 0 { tmp := make([]string, 0, count-1) for _, value := range argumentList[0 : count-1] { - tmp = append(tmp, toString(value)) + tmp = append(tmp, value.string()) } parameterList = strings.Join(tmp, ",") - body = toString(argumentList[count-1]) + body = argumentList[count-1].string() } function, err := parser.ParseFunction(parameterList, body) diff --git a/builtin_json.go b/builtin_json.go index f7c9077..b11d812 100644 --- a/builtin_json.go +++ b/builtin_json.go @@ -23,7 +23,7 @@ func builtinJSON_parse(call FunctionCall) Value { } var root interface{} - err := json.Unmarshal([]byte(toString(call.Argument(0))), &root) + err := json.Unmarshal([]byte(call.Argument(0).string()), &root) if err != nil { panic(newSyntaxError(err.Error())) } @@ -133,7 +133,7 @@ func builtinJSON_stringify(call FunctionCall) Value { default: continue } - name := toString(value) + name := value.string() if seen[name] { continue } @@ -151,21 +151,21 @@ func builtinJSON_stringify(call FunctionCall) Value { if spaceValue.kind == valueObject { switch spaceValue.value.(*_object).class { case "String": - spaceValue = toValue_string(toString(spaceValue)) + spaceValue = toValue_string(spaceValue.string()) case "Number": - spaceValue = toNumber(spaceValue) + spaceValue = spaceValue.numberValue() } } switch spaceValue.kind { case valueString: - value := toString(spaceValue) + value := spaceValue.string() if len(value) > 10 { ctx.gap = value[0:10] } else { ctx.gap = value } case valueNumber: - value := toInteger(spaceValue).int64 + value := spaceValue.number().int64 if value > 10 { value = 10 } else if value < 0 { @@ -219,23 +219,23 @@ func builtinJSON_stringifyWalk(ctx _builtinJSON_stringifyContext, key string, ho case "Boolean": value = value._object().value.(Value) case "String": - value = toValue_string(toString(value)) + value = toValue_string(value.string()) case "Number": - value = toNumber(value) + value = value.numberValue() } } switch value.kind { case valueBoolean: - return toBoolean(value), true + return value.bool(), true case valueString: - return toString(value), true + return value.string(), true case valueNumber: - integer := toInteger(value) + integer := value.number() switch integer.kind { - case integerValid: + case numberInteger: return integer.int64, true - case integerFloat: + case numberFloat: return integer.float64, true default: return nil, true diff --git a/builtin_math.go b/builtin_math.go index 37f7d8c..a9f4a55 100644 --- a/builtin_math.go +++ b/builtin_math.go @@ -8,31 +8,31 @@ import ( // Math func builtinMath_abs(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Abs(number)) } func builtinMath_acos(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Acos(number)) } func builtinMath_asin(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Asin(number)) } func builtinMath_atan(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Atan(number)) } func builtinMath_atan2(call FunctionCall) Value { - y := toFloat(call.Argument(0)) + y := call.Argument(0).float64() if math.IsNaN(y) { return NaNValue() } - x := toFloat(call.Argument(1)) + x := call.Argument(1).float64() if math.IsNaN(x) { return NaNValue() } @@ -40,27 +40,27 @@ func builtinMath_atan2(call FunctionCall) Value { } func builtinMath_cos(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Cos(number)) } func builtinMath_ceil(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Ceil(number)) } func builtinMath_exp(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Exp(number)) } func builtinMath_floor(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Floor(number)) } func builtinMath_log(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Log(number)) } @@ -69,14 +69,14 @@ func builtinMath_max(call FunctionCall) Value { case 0: return negativeInfinityValue() case 1: - return toValue_float64(toFloat(call.ArgumentList[0])) + return toValue_float64(call.ArgumentList[0].float64()) } - result := toFloat(call.ArgumentList[0]) + result := call.ArgumentList[0].float64() if math.IsNaN(result) { return NaNValue() } for _, value := range call.ArgumentList[1:] { - value := toFloat(value) + value := value.float64() if math.IsNaN(value) { return NaNValue() } @@ -90,14 +90,14 @@ func builtinMath_min(call FunctionCall) Value { case 0: return positiveInfinityValue() case 1: - return toValue_float64(toFloat(call.ArgumentList[0])) + return toValue_float64(call.ArgumentList[0].float64()) } - result := toFloat(call.ArgumentList[0]) + result := call.ArgumentList[0].float64() if math.IsNaN(result) { return NaNValue() } for _, value := range call.ArgumentList[1:] { - value := toFloat(value) + value := value.float64() if math.IsNaN(value) { return NaNValue() } @@ -108,8 +108,8 @@ func builtinMath_min(call FunctionCall) Value { func builtinMath_pow(call FunctionCall) Value { // TODO Make sure this works according to the specification (15.8.2.13) - x := toFloat(call.Argument(0)) - y := toFloat(call.Argument(1)) + x := call.Argument(0).float64() + y := call.Argument(1).float64() if math.Abs(x) == 1 && math.IsInf(y, 0) { return NaNValue() } @@ -121,7 +121,7 @@ func builtinMath_random(call FunctionCall) Value { } func builtinMath_round(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() value := math.Floor(number + 0.5) if value == 0 { value = math.Copysign(0, number) @@ -130,16 +130,16 @@ func builtinMath_round(call FunctionCall) Value { } func builtinMath_sin(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Sin(number)) } func builtinMath_sqrt(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Sqrt(number)) } func builtinMath_tan(call FunctionCall) Value { - number := toFloat(call.Argument(0)) + number := call.Argument(0).float64() return toValue_float64(math.Tan(number)) } diff --git a/builtin_number.go b/builtin_number.go index b020dbe..3091846 100644 --- a/builtin_number.go +++ b/builtin_number.go @@ -9,7 +9,7 @@ import ( func numberValueFromNumberArgumentList(argumentList []Value) Value { if len(argumentList) > 0 { - return toNumber(argumentList[0]) + return argumentList[0].numberValue() } return toValue_int(0) } @@ -35,7 +35,7 @@ func builtinNumber_toString(call FunctionCall) Value { radix = int(integer) } if radix == 10 { - return toValue_string(toString(value)) + return toValue_string(value.string()) } return toValue_string(numberToStringRadix(value, radix)) } @@ -52,11 +52,11 @@ func builtinNumber_toFixed(call FunctionCall) Value { if call.This.IsNaN() { return toValue_string("NaN") } - value := toFloat(call.This) + value := call.This.float64() if math.Abs(value) >= 1e21 { return toValue_string(floatToString(value, 64)) } - return toValue_string(strconv.FormatFloat(toFloat(call.This), 'f', int(precision), 64)) + return toValue_string(strconv.FormatFloat(call.This.float64(), 'f', int(precision), 64)) } func builtinNumber_toExponential(call FunctionCall) Value { @@ -70,7 +70,7 @@ func builtinNumber_toExponential(call FunctionCall) Value { panic(newRangeError("RangeError: toExponential() precision must be greater than 0")) } } - return toValue_string(strconv.FormatFloat(toFloat(call.This), 'e', int(precision), 64)) + return toValue_string(strconv.FormatFloat(call.This.float64(), 'e', int(precision), 64)) } func builtinNumber_toPrecision(call FunctionCall) Value { @@ -79,13 +79,13 @@ func builtinNumber_toPrecision(call FunctionCall) Value { } value := call.Argument(0) if value.IsUndefined() { - return toValue_string(toString(call.This)) + return toValue_string(call.This.string()) } precision := toIntegerFloat(value) if 1 > precision { panic(newRangeError("RangeError: toPrecision() precision must be greater than 1")) } - return toValue_string(strconv.FormatFloat(toFloat(call.This), 'g', int(precision), 64)) + return toValue_string(strconv.FormatFloat(call.This.float64(), 'g', int(precision), 64)) } func builtinNumber_toLocaleString(call FunctionCall) Value { diff --git a/builtin_object.go b/builtin_object.go index d13ba19..ee1ceb4 100644 --- a/builtin_object.go +++ b/builtin_object.go @@ -34,7 +34,7 @@ func builtinObject_valueOf(call FunctionCall) Value { } func builtinObject_hasOwnProperty(call FunctionCall) Value { - propertyName := toString(call.Argument(0)) + propertyName := call.Argument(0).string() thisObject := call.thisObject() return toValue_bool(thisObject.hasOwnProperty(propertyName)) } @@ -56,7 +56,7 @@ func builtinObject_isPrototypeOf(call FunctionCall) Value { } func builtinObject_propertyIsEnumerable(call FunctionCall) Value { - propertyName := toString(call.Argument(0)) + propertyName := call.Argument(0).string() thisObject := call.thisObject() property := thisObject.getOwnProperty(propertyName) if property != nil && property.enumerable() { @@ -106,7 +106,7 @@ func builtinObject_getOwnPropertyDescriptor(call FunctionCall) Value { panic(newTypeError()) } - name := toString(call.Argument(1)) + name := call.Argument(1).string() descriptor := object.getOwnProperty(name) if descriptor == nil { return Value{} @@ -120,7 +120,7 @@ func builtinObject_defineProperty(call FunctionCall) Value { if object == nil { panic(newTypeError()) } - name := toString(call.Argument(1)) + name := call.Argument(1).string() descriptor := toPropertyDescriptor(call.Argument(2)) object.defineOwnProperty(name, descriptor, true) return objectValue diff --git a/builtin_regexp.go b/builtin_regexp.go index fe6e5fb..9942251 100644 --- a/builtin_regexp.go +++ b/builtin_regexp.go @@ -26,15 +26,15 @@ func builtinNewRegExp(self *_object, argumentList []Value) Value { func builtinRegExp_toString(call FunctionCall) Value { thisObject := call.thisObject() - source := toString(thisObject.get("source")) + source := thisObject.get("source").string() flags := []byte{} - if toBoolean(thisObject.get("global")) { + if thisObject.get("global").bool() { flags = append(flags, 'g') } - if toBoolean(thisObject.get("ignoreCase")) { + if thisObject.get("ignoreCase").bool() { flags = append(flags, 'i') } - if toBoolean(thisObject.get("multiline")) { + if thisObject.get("multiline").bool() { flags = append(flags, 'm') } return toValue_string(fmt.Sprintf("/%s/%s", source, flags)) @@ -42,7 +42,7 @@ func builtinRegExp_toString(call FunctionCall) Value { func builtinRegExp_exec(call FunctionCall) Value { thisObject := call.thisObject() - target := toString(call.Argument(0)) + target := call.Argument(0).string() match, result := execRegExp(thisObject, target) if !match { return nullValue @@ -52,7 +52,7 @@ func builtinRegExp_exec(call FunctionCall) Value { func builtinRegExp_test(call FunctionCall) Value { thisObject := call.thisObject() - target := toString(call.Argument(0)) + target := call.Argument(0).string() match, _ := execRegExp(thisObject, target) return toValue_bool(match) } diff --git a/builtin_string.go b/builtin_string.go index 58881e0..067dde5 100644 --- a/builtin_string.go +++ b/builtin_string.go @@ -12,7 +12,7 @@ import ( func stringValueFromStringArgumentList(argumentList []Value) Value { if len(argumentList) > 0 { - return toValue_string(toString(argumentList[0])) + return toValue_string(argumentList[0].string()) } return toValue_string("") } @@ -42,7 +42,7 @@ func builtinString_fromCharCode(call FunctionCall) Value { func builtinString_charAt(call FunctionCall) Value { checkObjectCoercible(call.This) - idx := int(toInteger(call.Argument(0)).int64) + idx := int(call.Argument(0).number().int64) chr := stringAt(call.This._object().stringValue(), idx) if chr == utf8.RuneError { return toValue_string("") @@ -52,7 +52,7 @@ func builtinString_charAt(call FunctionCall) Value { func builtinString_charCodeAt(call FunctionCall) Value { checkObjectCoercible(call.This) - idx := int(toInteger(call.Argument(0)).int64) + idx := int(call.Argument(0).number().int64) chr := stringAt(call.This._object().stringValue(), idx) if chr == utf8.RuneError { return NaNValue() @@ -63,17 +63,17 @@ func builtinString_charCodeAt(call FunctionCall) Value { func builtinString_concat(call FunctionCall) Value { checkObjectCoercible(call.This) var value bytes.Buffer - value.WriteString(toString(call.This)) + value.WriteString(call.This.string()) for _, item := range call.ArgumentList { - value.WriteString(toString(item)) + value.WriteString(item.string()) } return toValue_string(value.String()) } func builtinString_indexOf(call FunctionCall) Value { checkObjectCoercible(call.This) - value := toString(call.This) - target := toString(call.Argument(0)) + value := call.This.string() + target := call.Argument(0).string() if 2 > len(call.ArgumentList) { return toValue_int(strings.Index(value, target)) } @@ -95,8 +95,8 @@ func builtinString_indexOf(call FunctionCall) Value { func builtinString_lastIndexOf(call FunctionCall) Value { checkObjectCoercible(call.This) - value := toString(call.This) - target := toString(call.Argument(0)) + value := call.This.string() + target := call.Argument(0).string() if 2 > len(call.ArgumentList) || call.ArgumentList[1].IsUndefined() { return toValue_int(strings.LastIndex(value, target)) } @@ -104,8 +104,8 @@ func builtinString_lastIndexOf(call FunctionCall) Value { if length == 0 { return toValue_int(strings.LastIndex(value, target)) } - start := toInteger(call.ArgumentList[1]) - if !start.valid() { + start := call.ArgumentList[1].number() + if start.kind == numberInfinity { // FIXME // startNumber is infinity, so start is the end of string (start = length) return toValue_int(strings.LastIndex(value, target)) } @@ -121,13 +121,13 @@ func builtinString_lastIndexOf(call FunctionCall) Value { func builtinString_match(call FunctionCall) Value { checkObjectCoercible(call.This) - target := toString(call.This) + target := call.This.string() matcherValue := call.Argument(0) matcher := matcherValue._object() if !matcherValue.IsObject() || matcher.class != "RegExp" { matcher = call.runtime.newRegExp(matcherValue, Value{}) } - global := toBoolean(matcher.get("global")) + global := matcher.get("global").bool() if !global { match, result := execRegExp(matcher, target) if !match { @@ -190,7 +190,7 @@ func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int func builtinString_replace(call FunctionCall) Value { checkObjectCoercible(call.This) - target := []byte(toString(call.This)) + target := []byte(call.This.string()) searchValue := call.Argument(0) searchObject := searchValue._object() @@ -205,7 +205,7 @@ func builtinString_replace(call FunctionCall) Value { find = -1 } } else { - search = regexp.MustCompile(regexp.QuoteMeta(toString(searchValue))) + search = regexp.MustCompile(regexp.QuoteMeta(searchValue.string())) } found := search.FindAllSubmatchIndex(target, find) @@ -237,13 +237,13 @@ func builtinString_replace(call FunctionCall) Value { } argumentList[matchCount+0] = toValue_int(match[0]) argumentList[matchCount+1] = toValue_string(target) - replacement := toString(replace.call(Value{}, argumentList, false)) + replacement := replace.call(Value{}, argumentList, false).string() result = append(result, []byte(replacement)...) lastIndex = match[1] } } else { - replace := []byte(toString(replaceValue)) + replace := []byte(replaceValue.string()) for _, match := range found { result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace) lastIndex = match[1] @@ -264,7 +264,7 @@ func builtinString_replace(call FunctionCall) Value { func builtinString_search(call FunctionCall) Value { checkObjectCoercible(call.This) - target := toString(call.This) + target := call.This.string() searchValue := call.Argument(0) search := searchValue._object() if !searchValue.IsObject() || search.class != "RegExp" { @@ -290,7 +290,7 @@ func stringSplitMatch(target string, targetLength int64, index uint, search stri func builtinString_split(call FunctionCall) Value { checkObjectCoercible(call.This) - target := toString(call.This) + target := call.This.string() separatorValue := call.Argument(0) limitValue := call.Argument(1) @@ -365,7 +365,7 @@ func builtinString_split(call FunctionCall) Value { return toValue_object(call.runtime.newArrayOf(valueArray)) } else { - separator := toString(separatorValue) + separator := separatorValue.string() splitLimit := limit excess := false @@ -391,7 +391,7 @@ func builtinString_split(call FunctionCall) Value { func builtinString_slice(call FunctionCall) Value { checkObjectCoercible(call.This) - target := toString(call.This) + target := call.This.string() length := int64(len(target)) start, end := rangeStartEnd(call.ArgumentList, length, false) @@ -403,7 +403,7 @@ func builtinString_slice(call FunctionCall) Value { func builtinString_substring(call FunctionCall) Value { checkObjectCoercible(call.This) - target := toString(call.This) + target := call.This.string() length := int64(len(target)) start, end := rangeStartEnd(call.ArgumentList, length, true) @@ -414,7 +414,7 @@ func builtinString_substring(call FunctionCall) Value { } func builtinString_substr(call FunctionCall) Value { - target := toString(call.This) + target := call.This.string() size := int64(len(target)) start, length := rangeStartLength(call.ArgumentList, size) @@ -440,12 +440,12 @@ func builtinString_substr(call FunctionCall) Value { func builtinString_toLowerCase(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue_string(strings.ToLower(toString(call.This))) + return toValue_string(strings.ToLower(call.This.string())) } func builtinString_toUpperCase(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue_string(strings.ToUpper(toString(call.This))) + return toValue_string(strings.ToUpper(call.This.string())) } // 7.2 Table 2 — Whitespace Characters & 7.3 Table 3 - Line Terminator Characters @@ -453,28 +453,28 @@ const builtinString_trim_whitespace = "\u0009\u000A\u000B\u000C\u000D\u0020\u00A func builtinString_trim(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue(strings.Trim(toString(call.This), + return toValue(strings.Trim(call.This.string(), builtinString_trim_whitespace)) } // Mozilla extension, not ECMAScript 5 func builtinString_trimLeft(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue(strings.TrimLeft(toString(call.This), + return toValue(strings.TrimLeft(call.This.string(), builtinString_trim_whitespace)) } // Mozilla extension, not ECMAScript 5 func builtinString_trimRight(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue(strings.TrimRight(toString(call.This), + return toValue(strings.TrimRight(call.This.string(), builtinString_trim_whitespace)) } func builtinString_localeCompare(call FunctionCall) Value { checkObjectCoercible(call.This) - this := toString(call.This) - that := toString(call.Argument(0)) + this := call.This.string() + that := call.Argument(0).string() if this < that { return toValue_int(-1) } else if this == that { @@ -487,7 +487,7 @@ func builtinString_localeCompare(call FunctionCall) Value { An alternate version of String.trim func builtinString_trim(call FunctionCall) Value { checkObjectCoercible(call.This) - return toValue_string(strings.TrimFunc(toString(call.This), isWhiteSpaceOrLineTerminator)) + return toValue_string(strings.TrimFunc(call.string(.This), isWhiteSpaceOrLineTerminator)) } */ diff --git a/cmpl_evaluate.go b/cmpl_evaluate.go index 48223fd..c249a02 100644 --- a/cmpl_evaluate.go +++ b/cmpl_evaluate.go @@ -52,7 +52,7 @@ func (self *_runtime) cmpl_call_nodeFunction(function *_object, stash *_fnStash, self.cmpl_variableDeclaration(node.varList) result := self.cmpl_evaluate_nodeStatement(node.body) - if result.isResult() { + if result.kind == valueResult { return result } diff --git a/cmpl_evaluate_expression.go b/cmpl_evaluate_expression.go index ef4c686..ea82d44 100644 --- a/cmpl_evaluate_expression.go +++ b/cmpl_evaluate_expression.go @@ -142,13 +142,13 @@ func (self *_runtime) cmpl_evaluate_nodeBinaryExpression(node *_nodeBinaryExpres switch node.operator { // Logical case token.LOGICAL_AND: - if !toBoolean(leftValue) { + if !leftValue.bool() { return leftValue } right := self.cmpl_evaluate_nodeExpression(node.right) return right.resolve() case token.LOGICAL_OR: - if toBoolean(leftValue) { + if leftValue.bool() { return leftValue } right := self.cmpl_evaluate_nodeExpression(node.right) @@ -173,7 +173,7 @@ func (self *_runtime) cmpl_evaluate_nodeBracketExpression(node *_nodeBracketExpr memberValue := member.resolve() // TODO Pass in base value as-is, and defer toObject till later? - return toValue(newPropertyReference(self.toObject(targetValue), toString(memberValue), false)) + return toValue(newPropertyReference(self.toObject(targetValue), memberValue.string(), false)) } func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression, withArgumentList []interface{}) Value { @@ -212,7 +212,7 @@ func (self *_runtime) cmpl_evaluate_nodeCallExpression(node *_nodeCallExpression func (self *_runtime) cmpl_evaluate_nodeConditionalExpression(node *_nodeConditionalExpression) Value { test := self.cmpl_evaluate_nodeExpression(node.test) testValue := test.resolve() - if toBoolean(testValue) { + if testValue.bool() { return self.cmpl_evaluate_nodeExpression(node.consequent) } return self.cmpl_evaluate_nodeExpression(node.alternate) @@ -295,7 +295,7 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi switch node.operator { case token.NOT: targetValue := target.resolve() - if targetValue.toBoolean() { + if targetValue.bool() { return falseValue } return trueValue @@ -305,10 +305,10 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi return toValue_int32(^integerValue) case token.PLUS: targetValue := target.resolve() - return toValue_float64(targetValue.toFloat()) + return toValue_float64(targetValue.float64()) case token.MINUS: targetValue := target.resolve() - value := targetValue.toFloat() + value := targetValue.float64() // TODO Test this sign := float64(-1) if math.Signbit(value) { @@ -319,13 +319,13 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi targetValue := target.resolve() if node.postfix { // Postfix++ - oldValue := targetValue.toFloat() + oldValue := targetValue.float64() newValue := toValue_float64(+1 + oldValue) self.putValue(target.reference(), newValue) return toValue_float64(oldValue) } else { // ++Prefix - newValue := toValue_float64(+1 + targetValue.toFloat()) + newValue := toValue_float64(+1 + targetValue.float64()) self.putValue(target.reference(), newValue) return newValue } @@ -333,13 +333,13 @@ func (self *_runtime) cmpl_evaluate_nodeUnaryExpression(node *_nodeUnaryExpressi targetValue := target.resolve() if node.postfix { // Postfix-- - oldValue := targetValue.toFloat() + oldValue := targetValue.float64() newValue := toValue_float64(-1 + oldValue) self.putValue(target.reference(), newValue) return toValue_float64(oldValue) } else { // --Prefix - newValue := toValue_float64(-1 + targetValue.toFloat()) + newValue := toValue_float64(-1 + targetValue.float64()) self.putValue(target.reference(), newValue) return newValue } diff --git a/cmpl_evaluate_statement.go b/cmpl_evaluate_statement.go index c75f8c4..c68a64c 100644 --- a/cmpl_evaluate_statement.go +++ b/cmpl_evaluate_statement.go @@ -150,7 +150,7 @@ resultBreak: } } resultContinue: - if !self.cmpl_evaluate_nodeExpression(test).resolve().isTrue() { + if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { // Stahp: do ... while (false) break } @@ -184,7 +184,7 @@ func (self *_runtime) cmpl_evaluate_nodeForInStatement(node *_nodeForInStatement into := self.cmpl_evaluate_nodeExpression(into) // In the case of: for (var abc in def) ... if into.reference() == nil { - identifier := toString(into) + identifier := into.string() // TODO Should be true or false (strictness) depending on context into = toValue(getIdentifierReference(self.scope.lexical, identifier, false)) } @@ -242,7 +242,7 @@ resultBreak: if test != nil { testResult := self.cmpl_evaluate_nodeExpression(test) testResultValue := testResult.resolve() - if toBoolean(testResultValue) == false { + if testResultValue.bool() == false { break } } @@ -275,7 +275,7 @@ resultBreak: func (self *_runtime) cmpl_evaluate_nodeIfStatement(node *_nodeIfStatement) Value { test := self.cmpl_evaluate_nodeExpression(node.test) testValue := test.resolve() - if toBoolean(testValue) { + if testValue.bool() { return self.cmpl_evaluate_nodeStatement(node.consequent) } else if node.alternate != nil { return self.cmpl_evaluate_nodeStatement(node.alternate) @@ -351,7 +351,7 @@ func (self *_runtime) cmpl_evaluate_nodeTryStatement(node *_nodeTryStatement) Va if node.finally != nil { finallyValue := self.cmpl_evaluate_nodeStatement(node.finally) - if finallyValue.isResult() { + if finallyValue.kind == valueResult { return finallyValue } } @@ -373,7 +373,7 @@ func (self *_runtime) cmpl_evaluate_nodeWhileStatement(node *_nodeWhileStatement result := emptyValue resultBreakContinue: for { - if !self.cmpl_evaluate_nodeExpression(test).resolve().isTrue() { + if !self.cmpl_evaluate_nodeExpression(test).resolve().bool() { // Stahp: while (false) ... break } diff --git a/error.go b/error.go index 93a13fe..a953e5d 100644 --- a/error.go +++ b/error.go @@ -136,7 +136,7 @@ func catchPanic(function func()) (err error) { } return case Value: - err = errors.New(toString(caught)) + err = errors.New(caught.string()) return //case string: // if strings.HasPrefix(caught, "SyntaxError:") { diff --git a/evaluate.go b/evaluate.go index e58d1e7..4cff1d8 100644 --- a/evaluate.go +++ b/evaluate.go @@ -65,38 +65,38 @@ func (self *_runtime) calculateBinaryExpression(operator token.Token, left Value rightValue = toPrimitive(rightValue) if leftValue.IsString() || rightValue.IsString() { - return toValue_string(strings.Join([]string{leftValue.toString(), rightValue.toString()}, "")) + return toValue_string(strings.Join([]string{leftValue.string(), rightValue.string()}, "")) } else { - return toValue_float64(leftValue.toFloat() + rightValue.toFloat()) + return toValue_float64(leftValue.float64() + rightValue.float64()) } case token.MINUS: rightValue := right.resolve() - return toValue_float64(leftValue.toFloat() - rightValue.toFloat()) + return toValue_float64(leftValue.float64() - rightValue.float64()) // Multiplicative case token.MULTIPLY: rightValue := right.resolve() - return toValue_float64(leftValue.toFloat() * rightValue.toFloat()) + return toValue_float64(leftValue.float64() * rightValue.float64()) case token.SLASH: rightValue := right.resolve() - return self.evaluateDivide(leftValue.toFloat(), rightValue.toFloat()) + return self.evaluateDivide(leftValue.float64(), rightValue.float64()) case token.REMAINDER: rightValue := right.resolve() - return toValue_float64(math.Mod(leftValue.toFloat(), rightValue.toFloat())) + return toValue_float64(math.Mod(leftValue.float64(), rightValue.float64())) // Logical case token.LOGICAL_AND: - left := toBoolean(leftValue) + left := leftValue.bool() if !left { return falseValue } - return toValue_bool(toBoolean(right.resolve())) + return toValue_bool(right.resolve().bool()) case token.LOGICAL_OR: - left := toBoolean(leftValue) + left := leftValue.bool() if left { return trueValue } - return toValue_bool(toBoolean(right.resolve())) + return toValue_bool(right.resolve().bool()) // Bitwise case token.AND: @@ -134,7 +134,7 @@ func (self *_runtime) calculateBinaryExpression(operator token.Token, left Value if !rightValue.IsObject() { panic(newTypeError()) } - return toValue_bool(rightValue._object().hasProperty(toString(leftValue))) + return toValue_bool(rightValue._object().hasProperty(leftValue.string())) } panic(hereBeDragons(operator)) @@ -150,10 +150,10 @@ func makeEqualDispatch() map[int](func(Value, Value) bool) { key := valueKindDispatchKey return map[int](func(Value, Value) bool){ - key(valueNumber, valueObject): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, - key(valueString, valueObject): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, - key(valueObject, valueNumber): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, - key(valueObject, valueString): func(x Value, y Value) bool { return x.toFloat() == y.toFloat() }, + key(valueNumber, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueString, valueObject): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueObject, valueNumber): func(x Value, y Value) bool { return x.float64() == y.float64() }, + key(valueObject, valueString): func(x Value, y Value) bool { return x.float64() == y.float64() }, } } @@ -180,13 +180,13 @@ func calculateLessThan(left Value, right Value, leftFirst bool) _lessThanResult result := false if x.kind != valueString || y.kind != valueString { - x, y := x.toFloat(), y.toFloat() + x, y := x.float64(), y.float64() if math.IsNaN(x) || math.IsNaN(y) { return lessThanUndefined } result = x < y } else { - x, y := x.toString(), y.toString() + x, y := x.string(), y.string() result = x < y } @@ -268,11 +268,11 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri } else if x.kind <= valueNull || y.kind <= valueNull { result = false } else if x.kind <= valueString && y.kind <= valueString { - result = x.toFloat() == y.toFloat() + result = x.float64() == y.float64() } else if x.kind == valueBoolean { - result = self.calculateComparison(token.EQUAL, toValue_float64(x.toFloat()), y) + result = self.calculateComparison(token.EQUAL, toValue_float64(x.float64()), y) } else if y.kind == valueBoolean { - result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.toFloat())) + result = self.calculateComparison(token.EQUAL, x, toValue_float64(y.float64())) } else if x.kind == valueObject { result = self.calculateComparison(token.EQUAL, toPrimitive(x), y) } else if y.kind == valueObject { @@ -289,17 +289,17 @@ func (self *_runtime) calculateComparison(comparator token.Token, left Value, ri case valueUndefined, valueNull: result = true case valueNumber: - x := x.toFloat() - y := y.toFloat() + x := x.float64() + y := y.float64() if math.IsNaN(x) || math.IsNaN(y) { result = false } else { result = x == y } case valueString: - result = x.toString() == y.toString() + result = x.string() == y.string() case valueBoolean: - result = x.toBoolean() == y.toBoolean() + result = x.bool() == y.bool() case valueObject: result = x._object() == y._object() default: diff --git a/global.go b/global.go index efacc3a..99a7e52 100644 --- a/global.go +++ b/global.go @@ -145,10 +145,10 @@ func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_objec flags = regExp.flags } else { if patternValue.IsDefined() { - pattern = toString(patternValue) + pattern = patternValue.string() } if flagsValue.IsDefined() { - flags = toString(flagsValue) + flags = flagsValue.string() } } diff --git a/number_test.go b/number_test.go index f3790e0..8db01cf 100644 --- a/number_test.go +++ b/number_test.go @@ -144,15 +144,13 @@ func TestNumber_toLocaleString(t *testing.T) { }) } -func Test_toInteger(t *testing.T) { +func TestValue_number(t *testing.T) { tt(t, func() { - integer := toInteger(toValue(0.0)) - is(integer.valid(), true) - is(integer.exact(), true) + nm := toValue(0.0).number() + is(nm.kind, numberInteger) - integer = toInteger(toValue(3.14159)) - is(integer.valid(), true) - is(integer.exact(), false) + nm = toValue(3.14159).number() + is(nm.kind, numberFloat) }) } diff --git a/object.go b/object.go index f29a044..51d006a 100644 --- a/object.go +++ b/object.go @@ -98,7 +98,7 @@ func (self *_object) DefaultValue(hint _defaultValueHint) Value { } func (self *_object) String() string { - return toString(self.DefaultValue(defaultValueHintString)) + return self.DefaultValue(defaultValueHintString).string() } func (self *_object) defineProperty(name string, value Value, mode _propertyMode, throw bool) bool { diff --git a/otto_.go b/otto_.go index b257208..e053b54 100644 --- a/otto_.go +++ b/otto_.go @@ -73,7 +73,7 @@ func getValueOfArrayIndex(array []Value, index int) (Value, bool) { // A range index can be anything from 0 up to length. It is NOT safe to use as an index // to an array, but is useful for slicing and in some ECMA algorithms. func valueToRangeIndex(indexValue Value, length int64, negativeIsZero bool) int64 { - index := toInteger(indexValue).int64 + index := indexValue.number().int64 if negativeIsZero { if index < 0 { index = 0 @@ -129,7 +129,7 @@ func rangeStartLength(source []Value, size int64) (start, length int64) { lengthValue := valueOfArrayIndex(source, 1) if !lengthValue.IsUndefined() { // Which it is not, so get the value as an array index - length = toInteger(lengthValue).int64 + length = lengthValue.number().int64 } return } diff --git a/otto_test.go b/otto_test.go index c696887..68a811d 100644 --- a/otto_test.go +++ b/otto_test.go @@ -649,7 +649,7 @@ func Test_PrimitiveValueObjectValue(t *testing.T) { test, _ := test() Number11 := test(`new Number(11)`) - is(toFloat(Number11), 11) + is(Number11.float64(), 11) }) } @@ -866,8 +866,8 @@ func TestDotMember(t *testing.T) { func Test_stringToFloat(t *testing.T) { tt(t, func() { - is(stringToFloat("10e10000"), _Infinity) - is(stringToFloat("10e10_."), _NaN) + is(parseNumber("10e10000"), _Infinity) + is(parseNumber("10e10_."), _NaN) }) } diff --git a/property.go b/property.go index ed0fccb..c07a0e0 100644 --- a/property.go +++ b/property.go @@ -124,7 +124,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { { descriptor.mode = modeSetMask // Initially nothing is set if objectDescriptor.hasProperty("enumerable") { - if objectDescriptor.get("enumerable").toBoolean() { + if objectDescriptor.get("enumerable").bool() { descriptor.enumerateOn() } else { descriptor.enumerateOff() @@ -132,7 +132,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { } if objectDescriptor.hasProperty("configurable") { - if objectDescriptor.get("configurable").toBoolean() { + if objectDescriptor.get("configurable").bool() { descriptor.configureOn() } else { descriptor.configureOff() @@ -140,7 +140,7 @@ func toPropertyDescriptor(value Value) (descriptor _property) { } if objectDescriptor.hasProperty("writable") { - if objectDescriptor.get("writable").toBoolean() { + if objectDescriptor.get("writable").bool() { descriptor.writeOn() } else { descriptor.writeOff() diff --git a/runtime_test.go b/runtime_test.go index 8706d59..2510a0b 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -359,7 +359,7 @@ func TestComparison(t *testing.T) { test("1 == 'Hello, World.'", false) - is(stringToFloat("-1"), -1) + is(parseNumber("-1"), -1) test("0+Object", "0function Object() { [native code] }") }) diff --git a/type_array.go b/type_array.go index 2443f40..598b6a4 100644 --- a/type_array.go +++ b/type_array.go @@ -32,11 +32,11 @@ func objectLength(object *_object) uint32 { } func arrayUint32(value Value) uint32 { - tmp := toInteger(value) - if !tmp.exact() || !isUint32(tmp.int64) { + nm := value.number() + if nm.kind != numberInteger || !isUint32(nm.int64) { panic(newRangeError()) } - return uint32(tmp.int64) + return uint32(nm.int64) } func arrayDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool { diff --git a/type_boolean.go b/type_boolean.go index c24409d..afc45c6 100644 --- a/type_boolean.go +++ b/type_boolean.go @@ -5,7 +5,7 @@ import ( ) func (runtime *_runtime) newBooleanObject(value Value) *_object { - return runtime.newPrimitiveObject("Boolean", toValue_bool(toBoolean(value))) + return runtime.newPrimitiveObject("Boolean", toValue_bool(value.bool())) } func booleanToString(value bool) string { diff --git a/type_date.go b/type_date.go index 65e822f..262e55e 100644 --- a/type_date.go +++ b/type_date.go @@ -180,7 +180,7 @@ func newDateTime(argumentList []Value, location *Time.Location) (epoch float64) if index >= len(argumentList) { return default_, false } - value := toFloat(argumentList[index]) + value := argumentList[index].float64() if math.IsNaN(value) || math.IsInf(value, 0) { return 0, true } @@ -226,10 +226,10 @@ func newDateTime(argumentList []Value, location *Time.Location) (epoch float64) value := valueOfArrayIndex(argumentList, 0) value = toPrimitive(value) if value.IsString() { - return dateParse(toString(value)) + return dateParse(value.string()) } - return toFloat(value) + return value.float64() } INVALID: diff --git a/type_error.go b/type_error.go index 683fcf9..41bdaf6 100644 --- a/type_error.go +++ b/type_error.go @@ -3,7 +3,7 @@ package otto func (runtime *_runtime) newErrorObject(message Value) *_object { self := runtime.newClassObject("Error") if message.IsDefined() { - self.defineProperty("message", toValue_string(toString(message)), 0111, false) + self.defineProperty("message", toValue_string(message.string()), 0111, false) } return self } diff --git a/type_number.go b/type_number.go index ee7adc9..28de444 100644 --- a/type_number.go +++ b/type_number.go @@ -1,5 +1,5 @@ package otto func (runtime *_runtime) newNumberObject(value Value) *_object { - return runtime.newPrimitiveObject("Number", toNumber(value)) + return runtime.newPrimitiveObject("Number", value.numberValue()) } diff --git a/type_regexp.go b/type_regexp.go index 5ad9138..e305d91 100644 --- a/type_regexp.go +++ b/type_regexp.go @@ -88,9 +88,9 @@ func execRegExp(this *_object, target string) (match bool, result []int) { if this.class != "RegExp" { panic(newTypeError("Calling RegExp.exec on a non-RegExp object")) } - lastIndex := toInteger(this.get("lastIndex")).int64 + lastIndex := this.get("lastIndex").number().int64 index := lastIndex - global := toBoolean(this.get("global")) + global := this.get("global").bool() if !global { index = 0 } diff --git a/type_string.go b/type_string.go index fd93316..ef3afa4 100644 --- a/type_string.go +++ b/type_string.go @@ -70,7 +70,7 @@ func stringAt(str _stringObject, index int) rune { } func (runtime *_runtime) newStringObject(value Value) *_object { - str := _newStringObject(toString(value)) + str := _newStringObject(value.string()) self := runtime.newClassObject("String") self.defineProperty("length", toValue_int(str.Length()), 0, false) diff --git a/underscore_test.go b/underscore_test.go index 2c58b1e..d8bf2da 100644 --- a/underscore_test.go +++ b/underscore_test.go @@ -36,10 +36,10 @@ func (self *_tester) underscore() { } vm.Set("assert", func(call FunctionCall) Value { - if !toBoolean(call.Argument(0)) { + if !call.Argument(0).bool() { message := "Assertion failed" if len(call.ArgumentList) > 1 { - message = toString(call.ArgumentList[1]) + message = call.ArgumentList[1].string() } t := terst.Caller().T() is(message, nil) diff --git a/value.go b/value.go index 7470ce2..a3a8153 100644 --- a/value.go +++ b/value.go @@ -94,14 +94,6 @@ func (value Value) isCallable() bool { return false } -func (value Value) isResult() bool { - return value.kind == valueResult -} - -func (value Value) isReference() bool { - return value.kind == valueReference -} - // 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: // @@ -176,7 +168,7 @@ func (value Value) IsNaN() bool { return false } - return math.IsNaN(toFloat(value)) + return math.IsNaN(value.float64()) } // IsString will return true if value is a string (primitive). @@ -383,19 +375,11 @@ func toValue(value interface{}) Value { func (value Value) String() string { result := "" catchPanic(func() { - result = value.toString() + result = value.string() }) return result } -func (value Value) toBoolean() bool { - return toBoolean(value) -} - -func (value Value) isTrue() bool { - return toBoolean(value) -} - // ToBoolean will convert the value to a boolean (bool). // // ToValue(0).ToBoolean() => false @@ -408,17 +392,16 @@ func (value Value) isTrue() bool { func (value Value) ToBoolean() (bool, error) { result := false err := catchPanic(func() { - result = toBoolean(value) + result = value.bool() }) return result, err } -func (value Value) toNumber() Value { - return toNumber(value) -} - -func (value Value) toFloat() float64 { - return toFloat(value) +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). @@ -431,7 +414,7 @@ func (value Value) toFloat() float64 { func (value Value) ToFloat() (float64, error) { result := float64(0) err := catchPanic(func() { - result = toFloat(value) + result = value.float64() }) return result, err } @@ -446,15 +429,11 @@ func (value Value) ToFloat() (float64, error) { func (value Value) ToInteger() (int64, error) { result := int64(0) err := catchPanic(func() { - result = toInteger(value).int64 + result = value.number().int64 }) return result, err } -func (value Value) toString() string { - return toString(value) -} - // ToString will convert the value to a string (string). // // ToValue(0).ToString() => "0" @@ -467,7 +446,7 @@ func (value Value) toString() string { func (value Value) ToString() (string, error) { result := "" err := catchPanic(func() { - result = toString(value) + result = value.string() }) return result, err } @@ -586,8 +565,8 @@ func sameValue(x Value, y Value) bool { case valueUndefined, valueNull: result = true case valueNumber: - x := x.toFloat() - y := y.toFloat() + x := x.float64() + y := y.float64() if math.IsNaN(x) && math.IsNaN(y) { result = true } else { @@ -598,9 +577,9 @@ func sameValue(x Value, y Value) bool { } } case valueString: - result = x.toString() == y.toString() + result = x.string() == y.string() case valueBoolean: - result = x.toBoolean() == y.toBoolean() + result = x.bool() == y.bool() case valueObject: result = x._object() == y._object() default: @@ -619,17 +598,17 @@ func strictEqualityComparison(x Value, y Value) bool { case valueUndefined, valueNull: result = true case valueNumber: - x := x.toFloat() - y := y.toFloat() + x := x.float64() + y := y.float64() if math.IsNaN(x) && math.IsNaN(y) { result = false } else { result = x == y } case valueString: - result = x.toString() == y.toString() + result = x.string() == y.string() case valueBoolean: - result = x.toBoolean() == y.toBoolean() + result = x.bool() == y.bool() case valueObject: result = x._object() == y._object() default: @@ -784,7 +763,7 @@ func (self Value) exportNative() interface{} { func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) { switch kind { case reflect.Bool: // Bool - return reflect.ValueOf(value.toBoolean()), nil + 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 @@ -795,21 +774,21 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) { return reflect.ValueOf(int(tmp)), nil } case reflect.Int8: // Int8 - tmp := toInteger(value).int64 + 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 := toInteger(value).int64 + 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 := toInteger(value).int64 + tmp := value.number().int64 if tmp < int64_minInt32 || tmp > int64_maxInt32 { return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to int32", tmp, value) } else { @@ -834,21 +813,21 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) { return reflect.ValueOf(uint(tmp)), nil } case reflect.Uint8: // Uint8 - tmp := toInteger(value).int64 + 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 := toInteger(value).int64 + 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 := toInteger(value).int64 + tmp := value.number().int64 if tmp < 0 || tmp > int64_maxUint32 { return reflect.Value{}, fmt.Errorf("RangeError: %d (%v) to uint32", tmp, value) } else { @@ -864,7 +843,7 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) { return reflect.ValueOf(uint64(tmp)), nil } case reflect.Float32: // Float32 - tmp := toFloat(value) + tmp := value.float64() tmp1 := tmp if 0 > tmp1 { tmp1 = -tmp1 @@ -875,10 +854,10 @@ func (value Value) toReflectValue(kind reflect.Kind) (reflect.Value, error) { return reflect.ValueOf(float32(tmp)), nil } case reflect.Float64: // Float64 - value := toFloat(value) + value := value.float64() return reflect.ValueOf(float64(value)), nil case reflect.String: // String - return reflect.ValueOf(value.toString()), nil + return reflect.ValueOf(value.string()), nil case reflect.Invalid: // Invalid case reflect.Complex64: // FIXME? Complex64 case reflect.Complex128: // FIXME? Complex128 diff --git a/value_boolean.go b/value_boolean.go index 038828e..3040f41 100644 --- a/value_boolean.go +++ b/value_boolean.go @@ -6,7 +6,7 @@ import ( "reflect" ) -func toBoolean(value Value) bool { +func (value Value) bool() bool { if value.kind == valueBoolean { return value.value.(bool) } @@ -38,12 +38,3 @@ func toBoolean(value Value) bool { } panic(fmt.Errorf("toBoolean(%T)", value.value)) } - -func stringToBoolean(value string) bool { - if value == "true" { - return true - } else if value == "false" { - return false - } - panic(fmt.Errorf("stringToBoolean(%s)", value)) -} diff --git a/value_number.go b/value_number.go index e41c3e3..54996c7 100644 --- a/value_number.go +++ b/value_number.go @@ -10,7 +10,7 @@ import ( var stringToNumberParseInteger = regexp.MustCompile(`^(?:0[xX])`) -func stringToFloat(value string) float64 { +func parseNumber(value string) float64 { value = strings.TrimSpace(value) if value == "" { @@ -41,14 +41,7 @@ func stringToFloat(value string) float64 { return float64(number) } -func toNumber(value Value) Value { - if value.kind == valueNumber { - return value - } - return Value{valueNumber, toFloat(value)} -} - -func toFloat(value Value) float64 { +func (value Value) float64() float64 { switch value.kind { case valueUndefined: return math.NaN() @@ -84,9 +77,9 @@ func toFloat(value Value) float64 { case float64: return value case string: - return stringToFloat(value) + return parseNumber(value) case *_object: - return toFloat(value.DefaultValue(defaultValueHintNumber)) + return value.DefaultValue(defaultValueHintNumber).float64() } panic(fmt.Errorf("toFloat(%T)", value.value)) } @@ -145,7 +138,7 @@ const ( ) func toIntegerFloat(value Value) float64 { - float := value.toFloat() + float := value.float64() if math.IsInf(float, 0) { } else if math.IsNaN(float) { float = 0 @@ -157,99 +150,88 @@ func toIntegerFloat(value Value) float64 { return float } -type _integerKind int +type _numberKind int const ( - integerValid _integerKind = iota // 3.0 => 3.0 - integerFloat // 3.14159 => 3.0, 1+2**63 > 2**63-1 - integerInfinite // Infinity => 2**63-1 - integerInvalid // NaN => 0 + numberInteger _numberKind = iota // 3.0 => 3.0 + numberFloat // 3.14159 => 3.0, 1+2**63 > 2**63-1 + numberInfinity // Infinity => 2**63-1 + numberNaN // NaN => 0 ) -type _integer struct { - kind _integerKind +type _number struct { + kind _numberKind int64 int64 float64 float64 } -func (self _integer) valid() bool { - return self.kind == integerValid || self.kind == integerFloat -} - -func (self _integer) exact() bool { - return self.kind == integerValid -} - -func (self _integer) infinite() bool { - return self.kind == integerInfinite -} - -// Could this use some improvement? +// FIXME // http://www.goinggo.net/2013/08/gustavos-ieee-754-brain-teaser.html // http://bazaar.launchpad.net/~niemeyer/strepr/trunk/view/6/strepr.go#L160 -func toInteger(value Value) (integer _integer) { - switch value := value.value.(type) { +func (vl Value) number() (number _number) { + switch vl := vl.value.(type) { case int8: - integer.int64 = int64(value) + number.int64 = int64(vl) return case int16: - integer.int64 = int64(value) + number.int64 = int64(vl) return case uint8: - integer.int64 = int64(value) + number.int64 = int64(vl) return case uint16: - integer.int64 = int64(value) + number.int64 = int64(vl) return case uint32: - integer.int64 = int64(value) + number.int64 = int64(vl) return case int: - integer.int64 = int64(value) + number.int64 = int64(vl) return case int64: - integer.int64 = value + number.int64 = vl return } - { - value := toFloat(value) - integer.float64 = value - if value == 0 { - return - } - if math.IsNaN(value) { - integer.kind = integerInvalid - return - } - if math.IsInf(value, 0) { - integer.kind = integerInfinite - } - if value >= float_maxInt64 { - integer.int64 = math.MaxInt64 - integer.kind = integerFloat - return - } - if value <= float_minInt64 { - integer.int64 = math.MinInt64 - integer.kind = integerFloat - return - } - { - value0 := value - value1 := float64(0) - if value0 > 0 { - value1 = math.Floor(value0) - } else { - value1 = math.Ceil(value0) - } - if value0 != value1 { - integer.kind = integerFloat - } - integer.int64 = int64(value1) - return - } + float := vl.float64() + if float == 0 { + return } + + number.kind = numberFloat + number.float64 = float + + if math.IsNaN(float) { + number.kind = numberNaN + return + } + + if math.IsInf(float, 0) { + number.kind = numberInfinity + } + + if float >= float_maxInt64 { + number.int64 = math.MaxInt64 + return + } + + if float <= float_minInt64 { + number.int64 = math.MinInt64 + return + } + + integer := float64(0) + if float > 0 { + integer = math.Floor(float) + } else { + integer = math.Ceil(float) + } + + if float == integer { + number.kind = numberInteger + } + number.int64 = int64(float) + return } // ECMA 262: 9.5 @@ -264,7 +246,7 @@ func toInt32(value Value) int32 { return value } } - floatValue := value.toFloat() + floatValue := value.float64() if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { return 0 } @@ -298,7 +280,7 @@ func toUint32(value Value) uint32 { return value } } - floatValue := value.toFloat() + floatValue := value.float64() if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { return 0 } @@ -325,7 +307,7 @@ func toUint16(value Value) uint16 { return value } } - floatValue := value.toFloat() + floatValue := value.float64() if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) { return 0 } diff --git a/value_string.go b/value_string.go index 71e209f..0fbfd6b 100644 --- a/value_string.go +++ b/value_string.go @@ -10,6 +10,8 @@ import ( var matchLeading0Exponent = regexp.MustCompile(`([eE][\+\-])0+([1-9])`) // 1e-07 => 1e-7 +// FIXME +// https://code.google.com/p/v8/source/browse/branches/bleeding_edge/src/conversions.cc?spec=svn18082&r=18082 func floatToString(value float64, bitsize int) string { // TODO Fit to ECMA-262 9.8.1 specification if math.IsNaN(value) { @@ -28,7 +30,7 @@ func floatToString(value float64, bitsize int) string { } func numberToStringRadix(value Value, radix int) string { - float := toFloat(value) + float := value.float64() if math.IsNaN(float) { return "NaN" } else if math.IsInf(float, 1) { @@ -42,7 +44,7 @@ func numberToStringRadix(value Value, radix int) string { return strconv.FormatInt(int64(float), radix) } -func toString(value Value) string { +func (value Value) string() string { if value.kind == valueString { switch value := value.value.(type) { case string: @@ -95,7 +97,7 @@ func toString(value Value) string { case string: return value case *_object: - return toString(value.DefaultValue(defaultValueHintString)) + return value.DefaultValue(defaultValueHintString).string() } - panic(fmt.Errorf("toString(%v %T)", value.value, value.value)) + panic(fmt.Errorf("%v.string( %T)", value.value, value.value)) } diff --git a/value_test.go b/value_test.go index 1d038bc..4a9bd54 100644 --- a/value_test.go +++ b/value_test.go @@ -15,7 +15,7 @@ func TestValue(t *testing.T) { is(toValue(false), false) is(toValue(1), 1) - is(toValue(1).toFloat(), float64(1)) + is(toValue(1).float64(), float64(1)) }) } @@ -87,7 +87,7 @@ func TestToValue(t *testing.T) { func TestToBoolean(t *testing.T) { tt(t, func() { is := func(left interface{}, right bool) { - is(toValue(left).toBoolean(), right) + is(toValue(left).bool(), right) } is("", false) @@ -104,7 +104,7 @@ func TestToFloat(t *testing.T) { tt(t, func() { { is := func(left interface{}, right float64) { - is(toValue(left).toFloat(), right) + is(toValue(left).float64(), right) } is("", 0) is("xyzzy", math.NaN()) @@ -114,16 +114,16 @@ func TestToFloat(t *testing.T) { is(NullValue(), 0) //is(newObjectValue(), math.NaN()) } - is(math.IsNaN(UndefinedValue().toFloat()), true) + is(math.IsNaN(UndefinedValue().float64()), true) }) } func TestToString(t *testing.T) { tt(t, func() { - is("undefined", UndefinedValue().toString()) - is("null", NullValue().toString()) - is("true", toValue(true).toString()) - is("false", toValue(false).toString()) + is("undefined", UndefinedValue().string()) + is("null", NullValue().string()) + is("true", toValue(true).string()) + is("false", toValue(false).string()) is(UndefinedValue(), "undefined") is(NullValue(), "null")