From 16030f4b6fb5c3708849fb0f824317db4c9bcc1d Mon Sep 17 00:00:00 2001 From: Robert Krimen Date: Mon, 29 Apr 2013 17:29:08 +0200 Subject: [PATCH] Make parseInt behavior correspond to the 15.1.2.3 algorithm --- builtin.go | 24 +++++++++++++++++++++--- global.go | 2 +- global_test.go | 24 +++++++++++++++++------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/builtin.go b/builtin.go index 9fdbf73..775ad52 100644 --- a/builtin.go +++ b/builtin.go @@ -123,13 +123,31 @@ func builtinGlobal_parseInt(call FunctionCall) Value { return toValue(value) } +var parseFloat_matchBadSpecial = regexp.MustCompile(`[\+\-]?(?:[Ii]nf$|infinity)`) +var parseFloat_matchValid = regexp.MustCompile(`[0-9eE\+\-\.]|Infinity`) + func builtinGlobal_parseFloat(call FunctionCall) Value { // Caveat emptor: This implementation does NOT match the specification - string_ := strings.TrimSpace(toString(call.Argument(0))) - value, err := strconv.ParseFloat(string_, 64) - if err != nil { + input := strings.TrimSpace(toString(call.Argument(0))) + if parseFloat_matchBadSpecial.MatchString(input) { return NaNValue() } + value, err := strconv.ParseFloat(input, 64) + if err != nil { + for end := len(input); end > 0; end -= 1 { + input := input[0:end] + if !parseFloat_matchValid.MatchString(input) { + return NaNValue() + } + value, err = strconv.ParseFloat(input, 64) + if err == nil { + break + } + } + if err != nil { + return NaNValue() + } + } return toValue(value) } diff --git a/global.go b/global.go index 1212337..995ec35 100644 --- a/global.go +++ b/global.go @@ -703,7 +703,7 @@ func newContext() *_runtime { "Infinity", positiveInfinityValue(), "eval", -1, builtinGlobal_eval, "parseInt", -2, builtinGlobal_parseInt, - "parseFloat", builtinGlobal_parseFloat, + "parseFloat", -1, builtinGlobal_parseFloat, "isNaN", builtinGlobal_isNaN, "isFinite", builtinGlobal_isFinite, "decodeURI", builtinGlobal_decodeURI_decodeURIComponent, diff --git a/global_test.go b/global_test.go index 6cee9eb..b01c251 100644 --- a/global_test.go +++ b/global_test.go @@ -118,7 +118,9 @@ func Test_parseInt(t *testing.T) { test(`parseInt(" 11 ")`, "11") test(`parseInt(" 11\n")`, "11") test(`parseInt(" 11\n", 16)`, "17") + test(`parseInt("Xyzzy")`, "NaN") + test(`parseInt(" 0x11\n", 16)`, "17") test(`parseInt("0x0aXyzzy", 16)`, "10") test(`parseInt("0x1", 0)`, "1") @@ -126,6 +128,7 @@ func Test_parseInt(t *testing.T) { // TODO test(`parseInt("0x10000000000000000000", 16)`, "75557863725914323419136") } + test(`parseInt.length === 2`, "true") test(`parseInt.prototype === undefined`, "true") } @@ -141,14 +144,21 @@ func Test_parseFloat(t *testing.T) { test(`parseFloat(" 11 ")`, "11") test(`parseFloat(" 11\n")`, "11") test(`parseFloat(" 11\n", 16)`, "11") - test(`parseFloat("Xyzzy")`, "NaN") - test(`parseFloat("0x0a")`, "NaN") test(`parseFloat("11.1")`, "11.1") - if false { - test(`parseFloat(" 0x11\n", 16)`, "17") - // TODO parseFloat should return 10 in this scenario - test(`parseFloat("0x0aXyzzy")`, "10") - } + + test(`parseFloat("Xyzzy")`, "NaN") + + test(`parseFloat(" 0x11\n", 16)`, "0") + test(`parseFloat("0x0a")`, "0") + test(`parseFloat("0x0aXyzzy")`, "0") + test(`parseFloat("Infinity")`, "Infinity") + test(`parseFloat("infinity")`, "NaN") + test(`parseFloat("0x")`, "0") + test(`parseFloat("11x")`, "11") + test(`parseFloat("Infinity1")`, "Infinity") + + test(`parseFloat.length === 1`, "true") + test(`parseFloat.prototype === undefined`, "true") } func Test_encodeURI(t *testing.T) {