Value.string(), .float64(), .bool(), etc.

This commit is contained in:
Robert Krimen
2014-06-06 21:29:40 -07:00
parent b813fe3676
commit 709a0aa7ff
38 changed files with 302 additions and 352 deletions

View File

@@ -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{}

View File

@@ -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()))
}

View File

@@ -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)
}
}

View File

@@ -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 {

View File

@@ -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))
}

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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))
}
*/

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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:") {

View File

@@ -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:

View File

@@ -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()
}
}

View File

@@ -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)
})
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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)
})
}

View File

@@ -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()

View File

@@ -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] }")
})

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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:

View File

@@ -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
}

View File

@@ -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())
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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))
}

View File

@@ -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
}

View File

@@ -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))
}

View File

@@ -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")