From: rossberg@chromium.org Date: Fri, 19 Jul 2013 09:57:35 +0000 (+0000) Subject: Add support for explicit octal and binary integer literals X-Git-Tag: upstream/4.7.83~13293 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=83d9e6e7ee591f68c97690b369cdef756500137e;p=platform%2Fupstream%2Fv8.git Add support for explicit octal and binary integer literals http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.3 ES6 extends the numeric literals to support explicit support for binary and octal literals using the following syntax: 0b10101 0o777 This is currently behind the flag, --harmony-numeric-literals BUG=2783 R=rossberg@chromium.org Review URL: https://codereview.chromium.org/19300002 Patch from Erik Arvidsson . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15772 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/char-predicates-inl.h b/src/char-predicates-inl.h index 1a89ef3..dee9ccd 100644 --- a/src/char-predicates-inl.h +++ b/src/char-predicates-inl.h @@ -71,6 +71,18 @@ inline bool IsHexDigit(uc32 c) { } +inline bool IsOctalDigit(uc32 c) { + // ECMA-262, 6th, 7.8.3 + return IsInRange(c, '0', '7'); +} + + +inline bool IsBinaryDigit(uc32 c) { + // ECMA-262, 6th, 7.8.3 + return c == '0' || c == '1'; +} + + inline bool IsRegExpWord(uc16 c) { return IsInRange(AsciiAlphaToLower(c), 'a', 'z') || IsDecimalDigit(c) diff --git a/src/char-predicates.h b/src/char-predicates.h index b97191f..767ad65 100644 --- a/src/char-predicates.h +++ b/src/char-predicates.h @@ -40,6 +40,8 @@ inline bool IsCarriageReturn(uc32 c); inline bool IsLineFeed(uc32 c); inline bool IsDecimalDigit(uc32 c); inline bool IsHexDigit(uc32 c); +inline bool IsOctalDigit(uc32 c); +inline bool IsBinaryDigit(uc32 c); inline bool IsRegExpWord(uc32 c); inline bool IsRegExpNewline(uc32 c); diff --git a/src/conversions-inl.h b/src/conversions-inl.h index 595ae9e..2f0a399 100644 --- a/src/conversions-inl.h +++ b/src/conversions-inl.h @@ -515,6 +515,32 @@ double InternalStringToDouble(UnicodeCache* unicode_cache, end, false, allow_trailing_junk); + + // It could be an explicit octal value. + } else if ((flags & ALLOW_OCTAL) && (*current == 'o' || *current == 'O')) { + ++current; + if (current == end || !isDigit(*current, 8) || sign != NONE) { + return JunkStringValue(); // "0o". + } + + return InternalStringToIntDouble<3>(unicode_cache, + current, + end, + false, + allow_trailing_junk); + + // It could be a binary value. + } else if ((flags & ALLOW_BINARY) && (*current == 'b' || *current == 'B')) { + ++current; + if (current == end || !isBinaryDigit(*current) || sign != NONE) { + return JunkStringValue(); // "0b". + } + + return InternalStringToIntDouble<1>(unicode_cache, + current, + end, + false, + allow_trailing_junk); } // Ignore leading zeros in the integer part. @@ -524,7 +550,7 @@ double InternalStringToDouble(UnicodeCache* unicode_cache, } } - bool octal = leading_zero && (flags & ALLOW_OCTALS) != 0; + bool octal = leading_zero && (flags & ALLOW_IMPLICIT_OCTAL) != 0; // Copy significant digits of the integer part (if any) to the buffer. while (*current >= '0' && *current <= '9') { diff --git a/src/conversions.h b/src/conversions.h index 1fbb5f1..7aa2d3f 100644 --- a/src/conversions.h +++ b/src/conversions.h @@ -52,6 +52,11 @@ inline bool isDigit(int x, int radix) { } +inline bool isBinaryDigit(int x) { + return x == '0' || x == '1'; +} + + // The fast double-to-(unsigned-)int conversion routine does not guarantee // rounding towards zero. // For NaN and values outside the int range, return INT_MIN or INT_MAX. @@ -108,8 +113,10 @@ inline uint32_t DoubleToUint32(double x) { enum ConversionFlags { NO_FLAGS = 0, ALLOW_HEX = 1, - ALLOW_OCTALS = 2, - ALLOW_TRAILING_JUNK = 4 + ALLOW_OCTAL = 2, + ALLOW_IMPLICIT_OCTAL = 4, + ALLOW_BINARY = 8, + ALLOW_TRAILING_JUNK = 16 }; diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 6ba2d08..63cf663 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -171,6 +171,8 @@ DEFINE_bool(harmony_array_buffer, false, DEFINE_implication(harmony_typed_arrays, harmony_array_buffer) DEFINE_bool(harmony_generators, false, "enable harmony generators") DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)") +DEFINE_bool(harmony_numeric_literals, false, + "enable harmony numeric literals (0o77, 0b11)") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) @@ -180,6 +182,7 @@ DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony, harmony_observation) DEFINE_implication(harmony, harmony_generators) DEFINE_implication(harmony, harmony_iteration) +DEFINE_implication(harmony, harmony_numeric_literals) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_observation, harmony_collections) // TODO[dslomov] add harmony => harmony_typed_arrays diff --git a/src/parser.cc b/src/parser.cc index b062673..df568ef 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -563,6 +563,7 @@ Parser::Parser(CompilationInfo* info) set_allow_lazy(false); // Must be explicitly enabled. set_allow_generators(FLAG_harmony_generators); set_allow_for_of(FLAG_harmony_iteration); + set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); } @@ -3573,7 +3574,8 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { ASSERT(scanner().is_literal_ascii()); double value = StringToDouble(isolate()->unicode_cache(), scanner().literal_ascii_string(), - ALLOW_HEX | ALLOW_OCTALS); + ALLOW_HEX | ALLOW_OCTAL | + ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY); result = factory()->NewNumberLiteral(value); break; } @@ -4026,7 +4028,8 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { ASSERT(scanner().is_literal_ascii()); double value = StringToDouble(isolate()->unicode_cache(), scanner().literal_ascii_string(), - ALLOW_HEX | ALLOW_OCTALS); + ALLOW_HEX | ALLOW_OCTAL | + ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY); key = factory()->NewNumberLiteral(value); break; } @@ -4581,6 +4584,8 @@ preparser::PreParser::PreParseResult Parser::LazyParseFunctionLiteral( reusable_preparser_->set_allow_lazy(true); reusable_preparser_->set_allow_generators(allow_generators()); reusable_preparser_->set_allow_for_of(allow_for_of()); + reusable_preparser_->set_allow_harmony_numeric_literals( + allow_harmony_numeric_literals()); } preparser::PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(top_scope_->language_mode(), @@ -5850,6 +5855,7 @@ ScriptDataImpl* PreParserApi::PreParse(Utf16CharacterStream* source) { preparser.set_allow_generators(FLAG_harmony_generators); preparser.set_allow_for_of(FLAG_harmony_iteration); preparser.set_allow_harmony_scoping(FLAG_harmony_scoping); + preparser.set_allow_harmony_numeric_literals(FLAG_harmony_numeric_literals); scanner.Initialize(source); preparser::PreParser::PreParseResult result = preparser.PreParseProgram(); if (result == preparser::PreParser::kPreParseStackOverflow) { diff --git a/src/parser.h b/src/parser.h index c3a7edf..68a74b7 100644 --- a/src/parser.h +++ b/src/parser.h @@ -438,6 +438,9 @@ class Parser BASE_EMBEDDED { bool allow_harmony_scoping() { return scanner().HarmonyScoping(); } bool allow_generators() const { return allow_generators_; } bool allow_for_of() const { return allow_for_of_; } + bool allow_harmony_numeric_literals() { + return scanner().HarmonyNumericLiterals(); + } void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; } void set_allow_lazy(bool allow) { allow_lazy_ = allow; } @@ -447,6 +450,9 @@ class Parser BASE_EMBEDDED { } void set_allow_generators(bool allow) { allow_generators_ = allow; } void set_allow_for_of(bool allow) { allow_for_of_ = allow; } + void set_allow_harmony_numeric_literals(bool allow) { + scanner().SetHarmonyNumericLiterals(allow); + } // Parses the source code represented by the compilation info and sets its // function literal. Returns false (and deallocates any allocated AST diff --git a/src/preparser.cc b/src/preparser.cc index fe37cfa..36a94a3 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -1724,7 +1724,8 @@ int DuplicateFinder::AddNumber(i::Vector key, int value) { return AddAsciiSymbol(key, value); } - int flags = i::ALLOW_HEX | i::ALLOW_OCTALS; + int flags = i::ALLOW_HEX | i::ALLOW_OCTAL | i::ALLOW_IMPLICIT_OCTAL | + i::ALLOW_BINARY; double double_value = StringToDouble(unicode_constants_, key, flags, 0.0); int length; const char* string; diff --git a/src/preparser.h b/src/preparser.h index 41907d1..faddecc 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -141,6 +141,9 @@ class PreParser { bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); } bool allow_generators() const { return allow_generators_; } bool allow_for_of() const { return allow_for_of_; } + bool allow_harmony_numeric_literals() const { + return scanner_->HarmonyNumericLiterals(); + } void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; } void set_allow_lazy(bool allow) { allow_lazy_ = allow; } @@ -150,6 +153,9 @@ class PreParser { } void set_allow_generators(bool allow) { allow_generators_ = allow; } void set_allow_for_of(bool allow) { allow_for_of_ = allow; } + void set_allow_harmony_numeric_literals(bool allow) { + scanner_->SetHarmonyNumericLiterals(allow); + } // Pre-parse the program from the character stream; returns true on // success (even if parsing failed, the pre-parse data successfully diff --git a/src/runtime.cc b/src/runtime.cc index a14f501..4c8e6a4 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -5959,8 +5959,14 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) { } // Slower case. + int flags = ALLOW_HEX; + if (FLAG_harmony_numeric_literals) { + // The current spec draft has not updated "ToNumber Applied to the String + // Type", https://bugs.ecmascript.org/show_bug.cgi?id=1584 + flags |= ALLOW_OCTAL | ALLOW_BINARY; + } return isolate->heap()->NumberFromDouble( - StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX)); + StringToDouble(isolate->unicode_cache(), subject, flags)); } diff --git a/src/scanner.cc b/src/scanner.cc index ef2dc2c..8b7cb56 100644 --- a/src/scanner.cc +++ b/src/scanner.cc @@ -42,7 +42,8 @@ Scanner::Scanner(UnicodeCache* unicode_cache) : unicode_cache_(unicode_cache), octal_pos_(Location::invalid()), harmony_scoping_(false), - harmony_modules_(false) { } + harmony_modules_(false), + harmony_numeric_literals_(false) { } void Scanner::Initialize(Utf16CharacterStream* source) { @@ -719,7 +720,7 @@ void Scanner::ScanDecimalDigits() { Token::Value Scanner::ScanNumber(bool seen_period) { ASSERT(IsDecimalDigit(c0_)); // the first digit of the number or the fraction - enum { DECIMAL, HEX, OCTAL } kind = DECIMAL; + enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; LiteralScope literal(this); if (seen_period) { @@ -733,7 +734,8 @@ Token::Value Scanner::ScanNumber(bool seen_period) { int start_pos = source_pos(); // For reporting octal positions. AddLiteralCharAdvance(); - // either 0, 0exxx, 0Exxx, 0.xxx, an octal number, or a hex number + // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or + // an octal number. if (c0_ == 'x' || c0_ == 'X') { // hex number kind = HEX; @@ -745,9 +747,29 @@ Token::Value Scanner::ScanNumber(bool seen_period) { while (IsHexDigit(c0_)) { AddLiteralCharAdvance(); } + } else if (harmony_numeric_literals_ && (c0_ == 'o' || c0_ == 'O')) { + kind = OCTAL; + AddLiteralCharAdvance(); + if (!IsOctalDigit(c0_)) { + // we must have at least one octal digit after 'o'/'O' + return Token::ILLEGAL; + } + while (IsOctalDigit(c0_)) { + AddLiteralCharAdvance(); + } + } else if (harmony_numeric_literals_ && (c0_ == 'b' || c0_ == 'B')) { + kind = BINARY; + AddLiteralCharAdvance(); + if (!IsBinaryDigit(c0_)) { + // we must have at least one binary digit after 'b'/'B' + return Token::ILLEGAL; + } + while (IsBinaryDigit(c0_)) { + AddLiteralCharAdvance(); + } } else if ('0' <= c0_ && c0_ <= '7') { // (possible) octal number - kind = OCTAL; + kind = IMPLICIT_OCTAL; while (true) { if (c0_ == '8' || c0_ == '9') { kind = DECIMAL; @@ -776,7 +798,7 @@ Token::Value Scanner::ScanNumber(bool seen_period) { // scan exponent, if any if (c0_ == 'e' || c0_ == 'E') { ASSERT(kind != HEX); // 'e'/'E' must be scanned as part of the hex number - if (kind == OCTAL) return Token::ILLEGAL; // no exponent for octals allowed + if (kind != DECIMAL) return Token::ILLEGAL; // scan exponent AddLiteralCharAdvance(); if (c0_ == '+' || c0_ == '-') diff --git a/src/scanner.h b/src/scanner.h index eb6764e..d732808 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -408,7 +408,12 @@ class Scanner { void SetHarmonyModules(bool modules) { harmony_modules_ = modules; } - + bool HarmonyNumericLiterals() const { + return harmony_numeric_literals_; + } + void SetHarmonyNumericLiterals(bool numeric_literals) { + harmony_numeric_literals_ = numeric_literals; + } // Returns true if there was a line terminator before the peek'ed token, // possibly inside a multi-line comment. @@ -557,6 +562,8 @@ class Scanner { bool harmony_scoping_; // Whether we scan 'module', 'import', 'export' as keywords. bool harmony_modules_; + // Whether we scan 0o777 and 0b111 as numbers. + bool harmony_numeric_literals_; }; } } // namespace v8::internal diff --git a/test/cctest/test-conversions.cc b/test/cctest/test-conversions.cc index 3253d83..9e194ea 100644 --- a/test/cctest/test-conversions.cc +++ b/test/cctest/test-conversions.cc @@ -37,12 +37,14 @@ using namespace v8::internal; TEST(Hex) { UnicodeCache uc; - CHECK_EQ(0.0, StringToDouble(&uc, "0x0", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0X0", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(1.0, StringToDouble(&uc, "0x1", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(16.0, StringToDouble(&uc, "0x10", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(255.0, StringToDouble(&uc, "0xff", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(175.0, StringToDouble(&uc, "0xAF", ALLOW_HEX | ALLOW_OCTALS)); + CHECK_EQ(0.0, StringToDouble(&uc, "0x0", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0X0", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(1.0, StringToDouble(&uc, "0x1", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(16.0, StringToDouble(&uc, "0x10", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(255.0, StringToDouble(&uc, "0xff", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(175.0, StringToDouble(&uc, "0xAF", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); CHECK_EQ(0.0, StringToDouble(&uc, "0x0", ALLOW_HEX)); CHECK_EQ(0.0, StringToDouble(&uc, "0X0", ALLOW_HEX)); @@ -55,12 +57,32 @@ TEST(Hex) { TEST(Octal) { UnicodeCache uc; - CHECK_EQ(0.0, StringToDouble(&uc, "0", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "00", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(1.0, StringToDouble(&uc, "01", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(7.0, StringToDouble(&uc, "07", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(8.0, StringToDouble(&uc, "010", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(63.0, StringToDouble(&uc, "077", ALLOW_HEX | ALLOW_OCTALS)); + CHECK_EQ(0.0, StringToDouble(&uc, "0o0", ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0O0", ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(1.0, StringToDouble(&uc, "0o1", ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(7.0, StringToDouble(&uc, "0o7", ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(8.0, StringToDouble(&uc, "0o10", + ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(63.0, StringToDouble(&uc, "0o77", + ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL)); + + CHECK_EQ(0.0, StringToDouble(&uc, "0o0", ALLOW_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0O0", ALLOW_OCTAL)); + CHECK_EQ(1.0, StringToDouble(&uc, "0o1", ALLOW_OCTAL)); + CHECK_EQ(7.0, StringToDouble(&uc, "0o7", ALLOW_OCTAL)); + CHECK_EQ(8.0, StringToDouble(&uc, "0o10", ALLOW_OCTAL)); + CHECK_EQ(63.0, StringToDouble(&uc, "0o77", ALLOW_OCTAL)); +} + + +TEST(ImplicitOctal) { + UnicodeCache uc; + CHECK_EQ(0.0, StringToDouble(&uc, "0", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "00", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(1.0, StringToDouble(&uc, "01", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(7.0, StringToDouble(&uc, "07", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(8.0, StringToDouble(&uc, "010", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(63.0, StringToDouble(&uc, "077", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); CHECK_EQ(0.0, StringToDouble(&uc, "0", ALLOW_HEX)); CHECK_EQ(0.0, StringToDouble(&uc, "00", ALLOW_HEX)); @@ -71,26 +93,53 @@ TEST(Octal) { const double x = 010000000000; // Power of 2, no rounding errors. CHECK_EQ(x * x * x * x * x, StringToDouble(&uc, "01" "0000000000" "0000000000" - "0000000000" "0000000000" "0000000000", ALLOW_OCTALS)); + "0000000000" "0000000000" "0000000000", ALLOW_IMPLICIT_OCTAL)); } -TEST(MalformedOctal) { +TEST(Binary) { UnicodeCache uc; - CHECK_EQ(8.0, StringToDouble(&uc, "08", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(81.0, StringToDouble(&uc, "081", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(78.0, StringToDouble(&uc, "078", ALLOW_HEX | ALLOW_OCTALS)); - - CHECK(std::isnan(StringToDouble(&uc, "07.7", ALLOW_HEX | ALLOW_OCTALS))); - CHECK(std::isnan(StringToDouble(&uc, "07.8", ALLOW_HEX | ALLOW_OCTALS))); - CHECK(std::isnan(StringToDouble(&uc, "07e8", ALLOW_HEX | ALLOW_OCTALS))); - CHECK(std::isnan(StringToDouble(&uc, "07e7", ALLOW_HEX | ALLOW_OCTALS))); + CHECK_EQ(0.0, StringToDouble(&uc, "0b0", + ALLOW_BINARY | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0B0", + ALLOW_BINARY | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(1.0, StringToDouble(&uc, "0b1", + ALLOW_BINARY | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(2.0, StringToDouble(&uc, "0b10", + ALLOW_BINARY | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(3.0, StringToDouble(&uc, "0b11", + ALLOW_BINARY | ALLOW_IMPLICIT_OCTAL)); + + CHECK_EQ(0.0, StringToDouble(&uc, "0b0", ALLOW_BINARY)); + CHECK_EQ(0.0, StringToDouble(&uc, "0B0", ALLOW_BINARY)); + CHECK_EQ(1.0, StringToDouble(&uc, "0b1", ALLOW_BINARY)); + CHECK_EQ(2.0, StringToDouble(&uc, "0b10", ALLOW_BINARY)); + CHECK_EQ(3.0, StringToDouble(&uc, "0b11", ALLOW_BINARY)); +} - CHECK_EQ(8.7, StringToDouble(&uc, "08.7", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(8e7, StringToDouble(&uc, "08e7", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.001, StringToDouble(&uc, "0.001", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.713, StringToDouble(&uc, "0.713", ALLOW_HEX | ALLOW_OCTALS)); +TEST(MalformedOctal) { + UnicodeCache uc; + CHECK_EQ(8.0, StringToDouble(&uc, "08", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(81.0, StringToDouble(&uc, "081", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(78.0, StringToDouble(&uc, "078", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + + CHECK(std::isnan(StringToDouble(&uc, "07.7", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL))); + CHECK(std::isnan(StringToDouble(&uc, "07.8", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL))); + CHECK(std::isnan(StringToDouble(&uc, "07e8", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL))); + CHECK(std::isnan(StringToDouble(&uc, "07e7", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL))); + + CHECK_EQ(8.7, StringToDouble(&uc, "08.7", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(8e7, StringToDouble(&uc, "08e7", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + + CHECK_EQ(0.001, StringToDouble(&uc, "0.001", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.713, StringToDouble(&uc, "0.713", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); CHECK_EQ(8.0, StringToDouble(&uc, "08", ALLOW_HEX)); CHECK_EQ(81.0, StringToDouble(&uc, "081", ALLOW_HEX)); @@ -112,12 +161,12 @@ TEST(MalformedOctal) { TEST(TrailingJunk) { UnicodeCache uc; CHECK_EQ(8.0, StringToDouble(&uc, "8q", ALLOW_TRAILING_JUNK)); - CHECK_EQ(63.0, - StringToDouble(&uc, "077qqq", ALLOW_OCTALS | ALLOW_TRAILING_JUNK)); - CHECK_EQ(10.0, - StringToDouble(&uc, "10e", ALLOW_OCTALS | ALLOW_TRAILING_JUNK)); - CHECK_EQ(10.0, - StringToDouble(&uc, "10e-", ALLOW_OCTALS | ALLOW_TRAILING_JUNK)); + CHECK_EQ(63.0, StringToDouble(&uc, "077qqq", + ALLOW_IMPLICIT_OCTAL | ALLOW_TRAILING_JUNK)); + CHECK_EQ(10.0, StringToDouble(&uc, "10e", + ALLOW_IMPLICIT_OCTAL | ALLOW_TRAILING_JUNK)); + CHECK_EQ(10.0, StringToDouble(&uc, "10e-", + ALLOW_IMPLICIT_OCTAL | ALLOW_TRAILING_JUNK)); } @@ -144,12 +193,14 @@ TEST(IntegerStrLiteral) { CHECK(std::isnan(StringToDouble(&uc, " - 1 ", NO_FLAGS))); CHECK(std::isnan(StringToDouble(&uc, " + 1 ", NO_FLAGS))); - CHECK_EQ(0.0, StringToDouble(&uc, "0e0", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0e1", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0e-1", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0e-100000", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0e+100000", ALLOW_HEX | ALLOW_OCTALS)); - CHECK_EQ(0.0, StringToDouble(&uc, "0.", ALLOW_HEX | ALLOW_OCTALS)); + CHECK_EQ(0.0, StringToDouble(&uc, "0e0", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0e1", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0e-1", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0e-100000", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0e+100000", + ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); + CHECK_EQ(0.0, StringToDouble(&uc, "0.", ALLOW_HEX | ALLOW_IMPLICIT_OCTAL)); } diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index ee628c3..999fe4c 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1086,6 +1086,7 @@ enum ParserFlag { kAllowModules, kAllowGenerators, kAllowForOf, + kAllowHarmonyNumericLiterals, kParserFlagCount }; @@ -1103,7 +1104,9 @@ static bool checkParserFlag(unsigned flags, ParserFlag flag) { kAllowHarmonyScoping)); \ parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \ parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators)); \ - parser.set_allow_for_of(checkParserFlag(flags, kAllowForOf)); + parser.set_allow_for_of(checkParserFlag(flags, kAllowForOf)); \ + parser.set_allow_harmony_numeric_literals( \ + checkParserFlag(flags, kAllowHarmonyNumericLiterals)); void TestParserSyncWithFlags(i::Handle source, unsigned flags) { i::Isolate* isolate = i::Isolate::Current(); diff --git a/test/mjsunit/harmony/numeric-literals-off.js b/test/mjsunit/harmony/numeric-literals-off.js new file mode 100644 index 0000000..37204ed --- /dev/null +++ b/test/mjsunit/harmony/numeric-literals-off.js @@ -0,0 +1,41 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This is to ensure that we do not support 0b and 0o in Number when +// the --harmony-numeric-literals flag is not set. + + +function TestOctalLiteralUsingNumberFunction() { + assertEquals(NaN, Number('0o0')); +} +TestOctalLiteralUsingNumberFunction(); + + +function TestBinaryLiteralUsingNumberFunction() { + assertEquals(NaN, Number('0b0')); +} +TestBinaryLiteralUsingNumberFunction(); diff --git a/test/mjsunit/harmony/numeric-literals.js b/test/mjsunit/harmony/numeric-literals.js new file mode 100644 index 0000000..7300f3e --- /dev/null +++ b/test/mjsunit/harmony/numeric-literals.js @@ -0,0 +1,87 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-numeric-literals + +function TestOctalLiteral() { + assertEquals(0, 0o0); + assertEquals(0, 0O0); + assertEquals(1, 0o1); + assertEquals(7, 0o7); + assertEquals(8, 0o10); + assertEquals(63, 0o77); +} +TestOctalLiteral(); + + +function TestOctalLiteralUsingNumberFunction() { + assertEquals(0, Number('0o0')); + assertEquals(0, Number('0O0')); + assertEquals(1, Number('0o1')); + assertEquals(7, Number('0o7')); + assertEquals(8, Number('0o10')); + assertEquals(63, Number('0o77')); +} +TestOctalLiteralUsingNumberFunction(); + + +function TestBinaryLiteral() { + assertEquals(0, 0b0); + assertEquals(0, 0B0); + assertEquals(1, 0b1); + assertEquals(2, 0b10); + assertEquals(3, 0b11); +} +TestBinaryLiteral(); + + +function TestBinaryLiteralUsingNumberFunction() { + assertEquals(0, Number('0b0')); + assertEquals(0, Number('0B0')); + assertEquals(1, Number('0b1')); + assertEquals(2, Number('0b10')); + assertEquals(3, Number('0b11')); +} +TestBinaryLiteralUsingNumberFunction(); + + +// parseInt should (probably) not support 0b and 0o. +// https://bugs.ecmascript.org/show_bug.cgi?id=1585 +function TestParseIntDoesNotSupportOctalNorBinary() { + assertEquals(0, parseInt('0o77')); + assertEquals(0, parseInt('0o77', 8)); + assertEquals(0, parseInt('0b11')); + assertEquals(0, parseInt('0b11', 2)); +} +TestParseIntDoesNotSupportOctalNorBinary(); + + +function TestParseFloatDoesNotSupportOctalNorBinary() { + assertEquals(0, parseFloat('0o77')); + assertEquals(0, parseFloat('0b11')); +} +TestParseFloatDoesNotSupportOctalNorBinary();