Add support for explicit octal and binary integer literals
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 19 Jul 2013 09:57:35 +0000 (09:57 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 19 Jul 2013 09:57:35 +0000 (09:57 +0000)
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 <arv@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15772 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

16 files changed:
src/char-predicates-inl.h
src/char-predicates.h
src/conversions-inl.h
src/conversions.h
src/flag-definitions.h
src/parser.cc
src/parser.h
src/preparser.cc
src/preparser.h
src/runtime.cc
src/scanner.cc
src/scanner.h
test/cctest/test-conversions.cc
test/cctest/test-parsing.cc
test/mjsunit/harmony/numeric-literals-off.js [new file with mode: 0644]
test/mjsunit/harmony/numeric-literals.js [new file with mode: 0644]

index 1a89ef3..dee9ccd 100644 (file)
@@ -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)
index b97191f..767ad65 100644 (file)
@@ -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);
 
index 595ae9e..2f0a399 100644 (file)
@@ -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') {
index 1fbb5f1..7aa2d3f 100644 (file)
@@ -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
 };
 
 
index 6ba2d08..63cf663 100644 (file)
@@ -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
index b062673..df568ef 100644 (file)
@@ -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) {
index c3a7edf..68a74b7 100644 (file)
@@ -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
index fe37cfa..36a94a3 100644 (file)
@@ -1724,7 +1724,8 @@ int DuplicateFinder::AddNumber(i::Vector<const char> 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;
index 41907d1..faddecc 100644 (file)
@@ -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
index a14f501..4c8e6a4 100644 (file)
@@ -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));
 }
 
 
index ef2dc2c..8b7cb56 100644 (file)
@@ -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_ == '-')
index eb6764e..d732808 100644 (file)
@@ -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
index 3253d83..9e194ea 100644 (file)
@@ -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));
 }
 
 
index ee628c3..999fe4c 100644 (file)
@@ -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<i::String> 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 (file)
index 0000000..37204ed
--- /dev/null
@@ -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 (file)
index 0000000..7300f3e
--- /dev/null
@@ -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();