Bug 894026 - Implement ES6 binary and octal literals. r=till
authorJeff Walden <jwalden@mit.edu>
Tue, 23 Jul 2013 14:12:36 -0700
changeset 140141 77df61af1a84b8e5d554920e1f48781de6d63600
parent 140140 e978bb426e87a0cdca79f827904c954ffdc47439
child 140142 35f1055fd2179c264946c5007496a89fe4045eb2
push id25016
push userryanvm@gmail.com
push dateSat, 27 Jul 2013 02:25:56 +0000
treeherdermozilla-central@fb48c7d58b8b [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