Bug 894026 - Implement ES6 binary and octal literals. r=till
☠☠ backed out by bbf37166d07c ☠ ☠
authorJeff Walden <jwalden@mit.edu>
Tue, 23 Jul 2013 14:12:36 -0700
changeset 152362 5e1dd28ede5d12a37dee6a9d0ac75f66c015d32a
parent 152361 c10c0a6270ecbf817fe472b8dc04d195b6900d28
child 152363 631b3d5d54f46823f660ff5ad5ae298356309b10
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs894026
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 894026 - Implement ES6 binary and octal literals. r=till
js/src/frontend/TokenStream.cpp
js/src/js.msg
js/src/tests/ecma_6/Expressions/binary-literals.js
js/src/tests/ecma_6/Expressions/browser.js
js/src/tests/ecma_6/Expressions/octal-literals.js
js/src/tests/ecma_6/Expressions/shell.js
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -998,17 +998,17 @@ enum FirstCharKind {
     OneChar,
     Ident,
     Dot,
     Equals,
     String,
     Dec,
     Colon,
     Plus,
-    HexOct,
+    BasePrefix,
 
     /* These two must be last, so that |c >= Space| matches both. */
     Space,
     EOL
 };
 
 #define _______ Other
 
@@ -1017,27 +1017,27 @@ enum FirstCharKind {
  *          '(', ')', ',', ';', '?', '[', ']', '{', '}', '~'
  * Ident:   36, 65..90, 95, 97..122: '$', 'A'..'Z', '_', 'a'..'z'
  * Dot:     46: '.'
  * Equals:  61: '='
  * String:  34, 39: '"', '\''
  * Dec:     49..57: '1'..'9'
  * Colon:   58: ':'
  * Plus:    43: '+'
- * HexOct:  48: '0'
+ * BasePrefix:  48: '0'
  * Space:   9, 11, 12: '\t', '\v', '\f'
  * EOL:     10, 13: '\n', '\r'
  */
 static const uint8_t firstCharKinds[] = {
 /*         0        1        2        3        4        5        6        7        8        9    */
 /*   0+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______,   Space,
 /*  10+ */     EOL,   Space,   Space,     EOL, _______, _______, _______, _______, _______, _______,
 /*  20+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
 /*  30+ */ _______, _______,   Space, _______,  String, _______,   Ident, _______, _______,  String,
-/*  40+ */ OneChar, OneChar, _______,    Plus, OneChar, _______,     Dot, _______,  HexOct,     Dec,
+/*  40+ */ OneChar, OneChar, _______,    Plus, OneChar, _______,     Dot, _______, BasePrefix,  Dec,
 /*  50+ */     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,     Dec,   Colon, OneChar,
 /*  60+ */ _______,  Equals, _______, OneChar, _______,   Ident,   Ident,   Ident,   Ident,   Ident,
 /*  70+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /*  80+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /*  90+ */   Ident, OneChar, _______, OneChar, _______,   Ident, _______,   Ident,   Ident,   Ident,
 /* 100+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /* 110+ */   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,   Ident,
 /* 120+ */   Ident,   Ident,   Ident, OneChar, _______, OneChar, OneChar, _______
@@ -1392,33 +1392,53 @@ TokenStream::getTokenInternal()
     if (c1kind == Plus) {
         if (matchChar('+'))
             tt = TOK_INC;
         else
             tt = matchChar('=') ? TOK_ADDASSIGN : TOK_PLUS;
         goto out;
     }
 
-    /*
-     * Look for a hexadecimal or octal number.
-     */
-    if (c1kind == HexOct) {
+    // Look for a hexadecimal, octal, or binary number.
+    if (c1kind == BasePrefix) {
         int radix;
         c = getCharIgnoreEOL();
         if (c == 'x' || c == 'X') {
             radix = 16;
             c = getCharIgnoreEOL();
             if (!JS7_ISHEX(c)) {
                 ungetCharIgnoreEOL(c);
                 reportError(JSMSG_MISSING_HEXDIGITS);
                 goto error;
             }
             numStart = userbuf.addressOfNextRawChar() - 1;  /* one past the '0x' */
             while (JS7_ISHEX(c))
                 c = getCharIgnoreEOL();
+        } else if (c == 'b' || c == 'B') {
+            radix = 2;
+            c = getCharIgnoreEOL();
+            if (c != '0' && c != '1') {
+                ungetCharIgnoreEOL(c);
+                reportError(JSMSG_MISSING_BINARY_DIGITS);
+                goto error;
+            }
+            numStart = userbuf.addressOfNextRawChar() - 1;  /* one past the '0b' */
+            while (c == '0' || c == '1')
+                c = getCharIgnoreEOL();
+        } else if (c == 'o' || c == 'O') {
+            radix = 8;
+            c = getCharIgnoreEOL();
+            if (c < '0' || c > '7') {
+                ungetCharIgnoreEOL(c);
+                reportError(JSMSG_MISSING_OCTAL_DIGITS);
+                goto error;
+            }
+            numStart = userbuf.addressOfNextRawChar() - 1;  /* one past the '0o' */
+            while ('0' <= c && c <= '7')
+                c = getCharIgnoreEOL();
         } else if (JS7_ISDEC(c)) {
             radix = 8;
             numStart = userbuf.addressOfNextRawChar() - 1;  /* one past the '0' */
             while (JS7_ISDEC(c)) {
                 /* Octal integer literals are not permitted in strict mode code. */
                 if (!reportStrictModeError(JSMSG_DEPRECATED_OCTAL))
                     goto error;
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -179,26 +179,26 @@ MSG_DEF(JSMSG_BAD_LABEL,              12
 MSG_DEF(JSMSG_DUPLICATE_LABEL,        126, 0, JSEXN_SYNTAXERR, "duplicate label")
 MSG_DEF(JSMSG_VAR_HIDES_ARG,          127, 1, JSEXN_TYPEERR, "variable {0} redeclares argument")
 MSG_DEF(JSMSG_BAD_VAR_INIT,           128, 0, JSEXN_SYNTAXERR, "invalid variable initialization")
 MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS,    129, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side")
 MSG_DEF(JSMSG_BAD_OPERAND,            130, 1, JSEXN_SYNTAXERR, "invalid {0} operand")
 MSG_DEF(JSMSG_BAD_PROP_ID,            131, 0, JSEXN_SYNTAXERR, "invalid property id")
 MSG_DEF(JSMSG_RESERVED_ID,            132, 1, JSEXN_SYNTAXERR, "{0} is a reserved identifier")
 MSG_DEF(JSMSG_SYNTAX_ERROR,           133, 0, JSEXN_SYNTAXERR, "syntax error")
-MSG_DEF(JSMSG_UNUSED134,              134, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_MISSING_BINARY_DIGITS,  134, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
 MSG_DEF(JSMSG_BAD_PROTOTYPE,          135, 1, JSEXN_TYPEERR,   "'prototype' property of {0} is not an object")
 MSG_DEF(JSMSG_MISSING_EXPONENT,       136, 0, JSEXN_SYNTAXERR, "missing exponent")
 MSG_DEF(JSMSG_OUT_OF_MEMORY,          137, 0, JSEXN_ERR, "out of memory")
 MSG_DEF(JSMSG_UNTERMINATED_STRING,    138, 0, JSEXN_SYNTAXERR, "unterminated string literal")
 MSG_DEF(JSMSG_TOO_MANY_PARENS,        139, 0, JSEXN_INTERNALERR, "too many parentheses in regular expression")
 MSG_DEF(JSMSG_UNTERMINATED_COMMENT,   140, 0, JSEXN_SYNTAXERR, "unterminated comment")
 MSG_DEF(JSMSG_UNTERMINATED_REGEXP,    141, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
 MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 142, 0, JSEXN_TYPEERR, "bad cloned function scope chain")
-MSG_DEF(JSMSG_UNUSED143,              143, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS,   143, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'")
 MSG_DEF(JSMSG_ILLEGAL_CHARACTER,      144, 0, JSEXN_SYNTAXERR, "illegal character")
 MSG_DEF(JSMSG_BAD_OCTAL,              145, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant")
 MSG_DEF(JSMSG_REPEAT_RANGE,           146, 0, JSEXN_RANGEERR, "repeat count must be positive and less than inifinity")
 MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION,     147, 1, JSEXN_INTERNALERR, "uncaught exception: {0}")
 MSG_DEF(JSMSG_INVALID_BACKREF,        148, 0, JSEXN_SYNTAXERR, "non-octal digit in an escape sequence that doesn't match a back-reference")
 MSG_DEF(JSMSG_BAD_BACKREF,            149, 0, JSEXN_SYNTAXERR, "back-reference exceeds number of capturing parentheses")
 MSG_DEF(JSMSG_PRECISION_RANGE,        150, 1, JSEXN_RANGEERR, "precision {0} out of range")
 MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER,   151, 1, JSEXN_TYPEERR, "invalid {0} usage")
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Expressions/binary-literals.js
@@ -0,0 +1,115 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 894026;
+var summary = "Implement ES6 binary literals";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var chars = ['b', 'B'];
+
+for (var i = 0; i < 2; i++)
+{
+  if (i === 2)
+  {
+    chars.forEach(function(v)
+    {
+      try
+      {
+        eval('0' + v + i);
+        throw "didn't throw";
+      }
+      catch (e)
+      {
+        assertEq(e instanceof SyntaxError, true,
+                 "no syntax error evaluating 0" + v + i + ", " +
+                 "got " + e);
+      }
+    });
+    continue;
+  }
+
+  for (var j = 0; j < 2; j++)
+  {
+    if (j === 2)
+    {
+      chars.forEach(function(v)
+      {
+        try
+        {
+          eval('0' + v + i + j);
+          throw "didn't throw";
+        }
+        catch (e)
+        {
+          assertEq(e instanceof SyntaxError, true,
+                   "no syntax error evaluating 0" + v + i + j + ", " +
+                   "got " + e);
+        }
+      });
+      continue;
+    }
+
+    for (var k = 0; k < 2; k++)
+    {
+      if (k === 2)
+      {
+        chars.forEach(function(v)
+        {
+          try
+          {
+            eval('0' + v + i + j + k);
+            throw "didn't throw";
+          }
+          catch (e)
+          {
+            assertEq(e instanceof SyntaxError, true,
+                     "no syntax error evaluating 0" + v + i + j + k + ", " +
+                     "got " + e);
+          }
+        });
+        continue;
+      }
+
+      chars.forEach(function(v)
+      {
+        assertEq(eval('0' + v + i + j + k), i * 4 + j * 2 + k);
+      });
+    }
+  }
+}
+
+chars.forEach(function(v)
+{
+  try
+  {
+  }
+  catch (e)
+  {
+    assertEq(e instanceof SyntaxError, true,
+             "no syntax error evaluating 0" + v + ", got " + e);
+  }
+});
+
+// Off-by-one check: '/' immediately precedes '0'.
+assertEq(0b110/1, 6);
+assertEq(0B10110/1, 22);
+
+function strict()
+{
+  "use strict";
+  return 0b11010101;
+}
+assertEq(strict(), 128 + 64 + 16 + 4 + 1);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Expressions/octal-literals.js
@@ -0,0 +1,103 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 894026;
+var summary = "Implement ES6 octal literals";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var chars = ['o', 'O'];
+
+for (var i = 0; i < 8; i++)
+{
+  if (i === 8)
+  {
+    chars.forEach(function(v)
+    {
+      try
+      {
+        eval('0' + v + i);
+        throw "didn't throw";
+      }
+      catch (e)
+      {
+        assertEq(e instanceof SyntaxError, true,
+                 "no syntax error evaluating 0" + v + i + ", " +
+                 "got " + e);
+      }
+    });
+    continue;
+  }
+
+  for (var j = 0; j < 8; j++)
+  {
+    if (j === 8)
+    {
+      chars.forEach(function(v)
+      {
+        try
+        {
+          eval('0' + v + i + j);
+          throw "didn't throw";
+        }
+        catch (e)
+        {
+          assertEq(e instanceof SyntaxError, true,
+                   "no syntax error evaluating 0" + v + i + j + ", " +
+                   "got " + e);
+        }
+      });
+      continue;
+    }
+
+    for (var k = 0; k < 8; k++)
+    {
+      if (k === 8)
+      {
+        chars.forEach(function(v)
+        {
+          try
+          {
+            eval('0' + v + i + j + k);
+            throw "didn't throw";
+          }
+          catch (e)
+          {
+            assertEq(e instanceof SyntaxError, true,
+                     "no syntax error evaluating 0" + v + i + j + k + ", " +
+                     "got " + e);
+          }
+        });
+        continue;
+      }
+
+      chars.forEach(function(v)
+      {
+        assertEq(eval('0' + v + i + j + k), i * 64 + j * 8 + k);
+      });
+    }
+  }
+}
+
+// Off-by-one check: '/' immediately precedes '0'.
+assertEq(0o110/2, 36);
+assertEq(0O644/2, 210);
+
+function strict()
+{
+  "use strict";
+  return 0o755;
+}
+assertEq(strict(), 7 * 64 + 5 * 8 + 5);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("Tests complete");
new file mode 100644