8134873: Implement support for ES6 numeric literals
authoraw
Tue, 01 Sep 2015 16:11:09 +0200
changeset 32444 4c7a40aab132
parent 32442 a29dbbbe10ef
child 32445 9d05e7490a07
8134873: Implement support for ES6 numeric literals Reviewed-by: attila, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java
nashorn/test/script/basic/es6/numeric-literals.js
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Wed Sep 02 22:28:31 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java	Tue Sep 01 16:11:09 2015 +0200
@@ -26,6 +26,7 @@
 package jdk.nashorn.internal.parser;
 
 import static jdk.nashorn.internal.parser.TokenType.ADD;
+import static jdk.nashorn.internal.parser.TokenType.BINARY_NUMBER;
 import static jdk.nashorn.internal.parser.TokenType.COMMENT;
 import static jdk.nashorn.internal.parser.TokenType.DECIMAL;
 import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
@@ -40,6 +41,7 @@
 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
 import static jdk.nashorn.internal.parser.TokenType.OCTAL;
+import static jdk.nashorn.internal.parser.TokenType.OCTAL_LEGACY;
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.REGEX;
 import static jdk.nashorn.internal.parser.TokenType.RPAREN;
@@ -47,6 +49,7 @@
 import static jdk.nashorn.internal.parser.TokenType.XML;
 
 import java.io.Serializable;
+
 import jdk.nashorn.internal.runtime.ECMAErrors;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -75,6 +78,9 @@
     /** True if here and edit strings are supported. */
     private final boolean scripting;
 
+    /** True if parsing in ECMAScript 6 mode. */
+    private final boolean es6;
+
     /** True if a nested scan. (scan to completion, no EOF.) */
     private final boolean nested;
 
@@ -173,7 +179,7 @@
      * @param stream    the token stream to lex
      */
     public Lexer(final Source source, final TokenStream stream) {
-        this(source, stream, false);
+        this(source, stream, false, false);
     }
 
     /**
@@ -182,9 +188,10 @@
      * @param source    the source
      * @param stream    the token stream to lex
      * @param scripting are we in scripting mode
+     * @param es6       are we in ECMAScript 6 mode
      */
-    public Lexer(final Source source, final TokenStream stream, final boolean scripting) {
-        this(source, 0, source.getLength(), stream, scripting, false);
+    public Lexer(final Source source, final TokenStream stream, final boolean scripting, final boolean es6) {
+        this(source, 0, source.getLength(), stream, scripting, es6, false);
     }
 
     /**
@@ -195,16 +202,18 @@
      * @param len       length of source segment to lex
      * @param stream    token stream to lex
      * @param scripting are we in scripting mode
+     * @param es6       are we in ECMAScript 6 mode
      * @param pauseOnFunctionBody if true, lexer will return from {@link #lexify()} when it encounters a
      * function body. This is used with the feature where the parser is skipping nested function bodies to
      * avoid reading ahead unnecessarily when we skip the function bodies.
      */
 
-    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean pauseOnFunctionBody) {
+    public Lexer(final Source source, final int start, final int len, final TokenStream stream, final boolean scripting, final boolean es6, final boolean pauseOnFunctionBody) {
         super(source.getContent(), 1, start, len);
         this.source      = source;
         this.stream      = stream;
         this.scripting   = scripting;
+        this.es6         = es6;
         this.nested      = false;
         this.pendingLine = 1;
         this.last        = EOL;
@@ -218,6 +227,7 @@
         source = lexer.source;
         stream = lexer.stream;
         scripting = lexer.scripting;
+        es6 = lexer.es6;
         nested = true;
 
         pendingLine = state.pendingLine;
@@ -1088,6 +1098,24 @@
             }
 
             type = HEXADECIMAL;
+        } else if (digit == 0 && es6 && (ch1 == 'o' || ch1 == 'O') && convertDigit(ch2, 8) != -1) {
+            // Skip over 0oN.
+            skip(3);
+            // Skip over remaining digits.
+            while (convertDigit(ch0, 8) != -1) {
+                skip(1);
+            }
+
+            type = OCTAL;
+        } else if (digit == 0 && es6 && (ch1 == 'b' || ch1 == 'B') && convertDigit(ch2, 2) != -1) {
+            // Skip over 0bN.
+            skip(3);
+            // Skip over remaining digits.
+            while (convertDigit(ch0, 2) != -1) {
+                skip(1);
+            }
+
+            type = BINARY_NUMBER;
         } else {
             // Check for possible octal constant.
             boolean octal = digit == 0;
@@ -1105,7 +1133,7 @@
             }
 
             if (octal && position - start > 1) {
-                type = OCTAL;
+                type = OCTAL_LEGACY;
             } else if (ch0 == '.' || ch0 == 'E' || ch0 == 'e') {
                 // Must be a double.
                 if (ch0 == '.') {
@@ -1637,10 +1665,14 @@
         switch (Token.descType(token)) {
         case DECIMAL:
             return Lexer.valueOf(source.getString(start, len), 10); // number
-        case OCTAL:
-            return Lexer.valueOf(source.getString(start, len), 8); // number
         case HEXADECIMAL:
             return Lexer.valueOf(source.getString(start + 2, len - 2), 16); // number
+        case OCTAL_LEGACY:
+            return Lexer.valueOf(source.getString(start, len), 8); // number
+        case OCTAL:
+            return Lexer.valueOf(source.getString(start + 2, len - 2), 8); // number
+        case BINARY_NUMBER:
+            return Lexer.valueOf(source.getString(start + 2, len - 2), 2); // number
         case FLOATING:
             final String str   = source.getString(start, len);
             final double value = Double.valueOf(str);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Sep 02 22:28:31 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue Sep 01 16:11:09 2015 +0200
@@ -273,7 +273,7 @@
 
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null);
+            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
             lexer.line = lexer.pendingLine = lineOffset + 1;
             line = lineOffset;
 
@@ -309,7 +309,7 @@
     public List<IdentNode> parseFormalParameterList() {
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
 
             // Set up first token (skips opening EOL.)
             k = -1;
@@ -333,7 +333,7 @@
     public FunctionNode parseFunctionBody() {
         try {
             stream = new TokenStream();
-            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
+            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
             final int functionLine = line;
 
             // Set up first token (skips opening EOL.)
@@ -1955,7 +1955,7 @@
             }
             detectSpecialProperty(ident);
             return ident;
-        case OCTAL:
+        case OCTAL_LEGACY:
             if (isStrictMode) {
                throw error(AbstractParser.message("strict.no.octal"), token);
             }
@@ -1963,6 +1963,8 @@
         case ESCSTRING:
         case DECIMAL:
         case HEXADECIMAL:
+        case OCTAL:
+        case BINARY_NUMBER:
         case FLOATING:
         case REGEX:
         case XML:
@@ -2224,7 +2226,7 @@
         switch (type) {
         case IDENT:
             return getIdent().setIsPropertyName();
-        case OCTAL:
+        case OCTAL_LEGACY:
             if (isStrictMode) {
                 throw error(AbstractParser.message("strict.no.octal"), token);
             }
@@ -2232,6 +2234,8 @@
         case ESCSTRING:
         case DECIMAL:
         case HEXADECIMAL:
+        case OCTAL:
+        case BINARY_NUMBER:
         case FLOATING:
             return getLiteral();
         default:
@@ -3035,7 +3039,7 @@
         assert parserState != null;
 
         stream.reset();
-        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions);
+        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6);
         line = parserState.line;
         linePosition = parserState.linePosition;
         // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
@@ -3064,8 +3068,8 @@
             this.linePosition = linePosition;
         }
 
-        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) {
-            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true);
+        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) {
+            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true);
             newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
             return newLexer;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Wed Sep 02 22:28:31 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Tue Sep 01 16:11:09 2015 +0200
@@ -170,8 +170,10 @@
     YIELD          (FUTURESTRICT,  "yield"),
 
     DECIMAL        (LITERAL,  null),
+    HEXADECIMAL    (LITERAL,  null),
+    OCTAL_LEGACY   (LITERAL,  null),
     OCTAL          (LITERAL,  null),
-    HEXADECIMAL    (LITERAL,  null),
+    BINARY_NUMBER  (LITERAL,  null),
     FLOATING       (LITERAL,  null),
     STRING         (LITERAL,  null),
     ESCSTRING      (LITERAL,  null),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/numeric-literals.js	Tue Sep 01 16:11:09 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8134873: ECMAScript 6 Numeric Literals
+ *
+ * @test
+ * @option --language=es6
+ */
+
+function assertEquals(expected, actual) {
+  if (expected !== actual) {
+    throw new Error("expected: " + expected + ", actual: " + actual);
+  }
+}
+
+assertEquals(0b0, 0);
+assertEquals(0B0, 0);
+assertEquals(0b01, 1);
+assertEquals(0B10, 2);
+assertEquals(0b11111111, 255);
+assertEquals(0b11111111111111111111111111111111, 4294967295);
+
+assertEquals(0o0, 0);
+assertEquals(0O0, 0);
+assertEquals(0o01, 1);
+assertEquals(0O10, 8);
+assertEquals(0o777, 511);
+