src/jdk/nashorn/internal/parser/Parser.java

Print this page
rev 739 : 8030809: Anonymous functions should not be shown with internal names in script stack trace
Reviewed-by: lagergren, hannesw, jlaskey
rev 743 : 8031317: SyntaxError when property setter has no parameter
Reviewed-by: lagergren, hannesw
rev 750 : 8032068: implement @sourceURL and #sourceURL directives
Reviewed-by: hannesw, lagergren
rev 758 : 8021350: Share script classes between threads/globals within context
Reviewed-by: lagergren, sundar


   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.parser;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.FUNCTION_PREFIX;
  30 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
  31 import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
  32 import static jdk.nashorn.internal.parser.TokenType.CASE;
  33 import static jdk.nashorn.internal.parser.TokenType.CATCH;
  34 import static jdk.nashorn.internal.parser.TokenType.COLON;
  35 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
  36 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
  37 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
  38 import static jdk.nashorn.internal.parser.TokenType.ELSE;
  39 import static jdk.nashorn.internal.parser.TokenType.EOF;
  40 import static jdk.nashorn.internal.parser.TokenType.EOL;
  41 import static jdk.nashorn.internal.parser.TokenType.FINALLY;
  42 import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
  43 import static jdk.nashorn.internal.parser.TokenType.IDENT;
  44 import static jdk.nashorn.internal.parser.TokenType.IF;
  45 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
  46 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
  47 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
  48 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
  49 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;


 372      */
 373     private Block newBlock() {
 374         return lc.push(new Block(token, Token.descPosition(token)));
 375     }
 376 
 377     /**
 378      * Set up a new function block.
 379      *
 380      * @param ident Name of function.
 381      * @return New block.
 382      */
 383     private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
 384         // Build function name.
 385         final StringBuilder sb = new StringBuilder();
 386 
 387         final FunctionNode parentFunction = lc.getCurrentFunction();
 388         if (parentFunction != null && !parentFunction.isProgram()) {
 389             sb.append(parentFunction.getName()).append('$');
 390         }
 391 
 392         sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName());


 393         final String name = namespace.uniqueName(sb.toString());
 394         assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName())  : "name = " + name;// must not rename runScript().
 395 
 396         int flags = 0;
 397         if (parentFunction == null) {
 398             flags |= FunctionNode.IS_PROGRAM;
 399         }
 400         if (isStrictMode) {
 401             flags |= FunctionNode.IS_STRICT;
 402         }
 403         if (env._specialize_calls != null) {
 404             if (env._specialize_calls.contains(name)) {
 405                 flags |= FunctionNode.CAN_SPECIALIZE;
 406             }
 407         }
 408 
 409         // Start new block.
 410         FunctionNode functionNode =
 411             new FunctionNode(
 412                 source,
 413                 line, //TODO?
 414                 token,
 415                 Token.descPosition(token),
 416                 startToken,
 417                 namespace,
 418                 ident,
 419                 name,
 420                 parameters,
 421                 kind,
 422                 flags);

 423 
 424         lc.push(functionNode);
 425         // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
 426         // FunctionNode.
 427         newBlock();
 428 
 429         return functionNode;
 430     }
 431 
 432     /**
 433      * Restore the current block.
 434      */
 435     private Block restoreBlock(final Block block) {
 436         return lc.pop(block);
 437     }
 438 
 439 
 440     private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
 441         final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
 442 


 621         final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
 622         // Set up the script to append elements.
 623 
 624         FunctionNode script = newFunctionNode(
 625             functionToken,
 626             new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
 627             new ArrayList<IdentNode>(),
 628             FunctionNode.Kind.SCRIPT);
 629 
 630         functionDeclarations = new ArrayList<>();
 631         sourceElements();
 632         addFunctionDeclarations(script);
 633         functionDeclarations = null;
 634 
 635         expect(EOF);
 636 
 637         script.setFinish(source.getLength() - 1);
 638 
 639         script = restoreFunctionNode(script, token); //commit code
 640         script = script.setBody(lc, script.getBody().setNeedsScope(lc));




 641 
 642         return script;
 643     }
 644 
 645     /**
 646      * Directive value or null if statement is not a directive.
 647      *
 648      * @param stmt Statement to be checked
 649      * @return Directive value if the given statement is a directive
 650      */
 651     private String getDirective(final Node stmt) {
 652         if (stmt instanceof ExpressionStatement) {
 653             final Node expr = ((ExpressionStatement)stmt).getExpression();
 654             if (expr instanceof LiteralNode) {
 655                 final LiteralNode<?> lit = (LiteralNode<?>)expr;
 656                 final long litToken = lit.getToken();
 657                 final TokenType tt = Token.descType(litToken);
 658                 // A directive is either a string or an escape string
 659                 if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) {
 660                     // Make sure that we don't unescape anything. Return as seen in source!


1775      *      Literal
1776      *      ArrayLiteral
1777      *      ObjectLiteral
1778      *      ( Expression )
1779      *
1780      *  See 11.1
1781      *
1782      * Parse primary expression.
1783      * @return Expression node.
1784      */
1785     @SuppressWarnings("fallthrough")
1786     private Expression primaryExpression() {
1787         // Capture first token.
1788         final int  primaryLine  = line;
1789         final long primaryToken = token;
1790 
1791         switch (type) {
1792         case THIS:
1793             final String name = type.getName();
1794             next();

1795             return new IdentNode(primaryToken, finish, name);
1796         case IDENT:
1797             final IdentNode ident = getIdent();
1798             if (ident == null) {
1799                 break;
1800             }
1801             detectSpecialProperty(ident);
1802             return ident;
1803         case OCTAL:
1804             if (isStrictMode) {
1805                throw error(AbstractParser.message("strict.no.octal"), token);
1806             }
1807         case STRING:
1808         case ESCSTRING:
1809         case DECIMAL:
1810         case HEXADECIMAL:
1811         case FLOATING:
1812         case REGEX:
1813         case XML:
1814             return getLiteral();


2115             final String ident = (String)expectValue(IDENT);
2116 
2117             if (type != COLON) {
2118                 final long getSetToken = propertyToken;
2119 
2120                 switch (ident) {
2121                 case "get":
2122                     final PropertyKey getIdent = propertyName();
2123                     final String getterName = getIdent.getPropertyName();
2124                     final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
2125                     expect(LPAREN);
2126                     expect(RPAREN);
2127                     functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
2128                     return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null);
2129 
2130                 case "set":
2131                     final PropertyKey setIdent = propertyName();
2132                     final String setterName = setIdent.getPropertyName();
2133                     final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
2134                     expect(LPAREN);
2135                     final IdentNode argIdent = getIdent();




2136                     verifyStrictIdent(argIdent, "setter argument");



2137                     expect(RPAREN);
2138                     List<IdentNode> parameters = new ArrayList<>();

2139                     parameters.add(argIdent);

2140                     functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
2141                     return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode);
2142 
2143                 default:
2144                     break;
2145                 }
2146             }
2147 
2148             propertyName =  new IdentNode(propertyToken, finish, ident).setIsPropertyName();
2149         } else {
2150             propertyName = propertyName();
2151         }
2152 
2153         expect(COLON);
2154 
2155         return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
2156     }
2157 
2158     /**
2159      * LeftHandSideExpression :


2431         final long functionToken = token;
2432         final int  functionLine  = line;
2433         // FUNCTION is tested in caller.
2434         next();
2435 
2436         IdentNode name = null;
2437 
2438         if (type == IDENT || isNonStrictModeIdent()) {
2439             name = getIdent();
2440             verifyStrictIdent(name, "function name");
2441         } else if (isStatement) {
2442             // Nashorn extension: anonymous function statements
2443             if (env._no_syntax_extensions) {
2444                 expect(IDENT);
2445             }
2446         }
2447 
2448         // name is null, generate anonymous name
2449         boolean isAnonymous = false;
2450         if (name == null) {
2451             final String tmpName = "_L" + functionLine;
2452             name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
2453             isAnonymous = true;
2454         }
2455 
2456         expect(LPAREN);
2457         final List<IdentNode> parameters = formalParameterList();
2458         expect(RPAREN);
2459 
2460         FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
2461 
2462         if (isStatement) {
2463             if (topLevel) {
2464                 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
2465             } else if (isStrictMode) {
2466                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
2467             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
2468                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
2469             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
2470                 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
2471             }




   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.parser;
  27 
  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX;
  30 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
  31 import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
  32 import static jdk.nashorn.internal.parser.TokenType.CASE;
  33 import static jdk.nashorn.internal.parser.TokenType.CATCH;
  34 import static jdk.nashorn.internal.parser.TokenType.COLON;
  35 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
  36 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
  37 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
  38 import static jdk.nashorn.internal.parser.TokenType.ELSE;
  39 import static jdk.nashorn.internal.parser.TokenType.EOF;
  40 import static jdk.nashorn.internal.parser.TokenType.EOL;
  41 import static jdk.nashorn.internal.parser.TokenType.FINALLY;
  42 import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
  43 import static jdk.nashorn.internal.parser.TokenType.IDENT;
  44 import static jdk.nashorn.internal.parser.TokenType.IF;
  45 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
  46 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
  47 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
  48 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
  49 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;


 372      */
 373     private Block newBlock() {
 374         return lc.push(new Block(token, Token.descPosition(token)));
 375     }
 376 
 377     /**
 378      * Set up a new function block.
 379      *
 380      * @param ident Name of function.
 381      * @return New block.
 382      */
 383     private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
 384         // Build function name.
 385         final StringBuilder sb = new StringBuilder();
 386 
 387         final FunctionNode parentFunction = lc.getCurrentFunction();
 388         if (parentFunction != null && !parentFunction.isProgram()) {
 389             sb.append(parentFunction.getName()).append('$');
 390         }
 391 
 392         assert ident.getName() != null;
 393         sb.append(ident.getName());
 394 
 395         final String name = namespace.uniqueName(sb.toString());
 396         assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName())  : "name = " + name;// must not rename runScript().
 397 
 398         int flags = 0;
 399         if (parentFunction == null) {
 400             flags |= FunctionNode.IS_PROGRAM;
 401         }
 402         if (isStrictMode) {
 403             flags |= FunctionNode.IS_STRICT;
 404         }
 405         if (env._specialize_calls != null) {
 406             if (env._specialize_calls.contains(name)) {
 407                 flags |= FunctionNode.CAN_SPECIALIZE;
 408             }
 409         }
 410 
 411         // Start new block.
 412         FunctionNode functionNode =
 413             new FunctionNode(
 414                 source,
 415                 line, //TODO?
 416                 token,
 417                 Token.descPosition(token),
 418                 startToken,
 419                 namespace,
 420                 ident,
 421                 name,
 422                 parameters,
 423                 kind,
 424                 flags,
 425                 sourceURL);
 426 
 427         lc.push(functionNode);
 428         // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
 429         // FunctionNode.
 430         newBlock();
 431 
 432         return functionNode;
 433     }
 434 
 435     /**
 436      * Restore the current block.
 437      */
 438     private Block restoreBlock(final Block block) {
 439         return lc.pop(block);
 440     }
 441 
 442 
 443     private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
 444         final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
 445 


 624         final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
 625         // Set up the script to append elements.
 626 
 627         FunctionNode script = newFunctionNode(
 628             functionToken,
 629             new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
 630             new ArrayList<IdentNode>(),
 631             FunctionNode.Kind.SCRIPT);
 632 
 633         functionDeclarations = new ArrayList<>();
 634         sourceElements();
 635         addFunctionDeclarations(script);
 636         functionDeclarations = null;
 637 
 638         expect(EOF);
 639 
 640         script.setFinish(source.getLength() - 1);
 641 
 642         script = restoreFunctionNode(script, token); //commit code
 643         script = script.setBody(lc, script.getBody().setNeedsScope(lc));
 644         // user may have directive comment to set sourceURL
 645         if (sourceURL != null) {
 646             script = script.setSourceURL(lc, sourceURL);
 647         }
 648 
 649         return script;
 650     }
 651 
 652     /**
 653      * Directive value or null if statement is not a directive.
 654      *
 655      * @param stmt Statement to be checked
 656      * @return Directive value if the given statement is a directive
 657      */
 658     private String getDirective(final Node stmt) {
 659         if (stmt instanceof ExpressionStatement) {
 660             final Node expr = ((ExpressionStatement)stmt).getExpression();
 661             if (expr instanceof LiteralNode) {
 662                 final LiteralNode<?> lit = (LiteralNode<?>)expr;
 663                 final long litToken = lit.getToken();
 664                 final TokenType tt = Token.descType(litToken);
 665                 // A directive is either a string or an escape string
 666                 if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) {
 667                     // Make sure that we don't unescape anything. Return as seen in source!


1782      *      Literal
1783      *      ArrayLiteral
1784      *      ObjectLiteral
1785      *      ( Expression )
1786      *
1787      *  See 11.1
1788      *
1789      * Parse primary expression.
1790      * @return Expression node.
1791      */
1792     @SuppressWarnings("fallthrough")
1793     private Expression primaryExpression() {
1794         // Capture first token.
1795         final int  primaryLine  = line;
1796         final long primaryToken = token;
1797 
1798         switch (type) {
1799         case THIS:
1800             final String name = type.getName();
1801             next();
1802             lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
1803             return new IdentNode(primaryToken, finish, name);
1804         case IDENT:
1805             final IdentNode ident = getIdent();
1806             if (ident == null) {
1807                 break;
1808             }
1809             detectSpecialProperty(ident);
1810             return ident;
1811         case OCTAL:
1812             if (isStrictMode) {
1813                throw error(AbstractParser.message("strict.no.octal"), token);
1814             }
1815         case STRING:
1816         case ESCSTRING:
1817         case DECIMAL:
1818         case HEXADECIMAL:
1819         case FLOATING:
1820         case REGEX:
1821         case XML:
1822             return getLiteral();


2123             final String ident = (String)expectValue(IDENT);
2124 
2125             if (type != COLON) {
2126                 final long getSetToken = propertyToken;
2127 
2128                 switch (ident) {
2129                 case "get":
2130                     final PropertyKey getIdent = propertyName();
2131                     final String getterName = getIdent.getPropertyName();
2132                     final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
2133                     expect(LPAREN);
2134                     expect(RPAREN);
2135                     functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
2136                     return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null);
2137 
2138                 case "set":
2139                     final PropertyKey setIdent = propertyName();
2140                     final String setterName = setIdent.getPropertyName();
2141                     final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
2142                     expect(LPAREN);
2143                     // be sloppy and allow missing setter parameter even though
2144                     // spec does not permit it!
2145                     final IdentNode argIdent;
2146                     if (type == IDENT || isNonStrictModeIdent()) {
2147                         argIdent = getIdent();
2148                         verifyStrictIdent(argIdent, "setter argument");
2149                     } else {
2150                         argIdent = null;
2151                     }
2152                     expect(RPAREN);
2153                     List<IdentNode> parameters = new ArrayList<>();
2154                     if (argIdent != null) {
2155                         parameters.add(argIdent);
2156                     }
2157                     functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
2158                     return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode);
2159 
2160                 default:
2161                     break;
2162                 }
2163             }
2164 
2165             propertyName =  new IdentNode(propertyToken, finish, ident).setIsPropertyName();
2166         } else {
2167             propertyName = propertyName();
2168         }
2169 
2170         expect(COLON);
2171 
2172         return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
2173     }
2174 
2175     /**
2176      * LeftHandSideExpression :


2448         final long functionToken = token;
2449         final int  functionLine  = line;
2450         // FUNCTION is tested in caller.
2451         next();
2452 
2453         IdentNode name = null;
2454 
2455         if (type == IDENT || isNonStrictModeIdent()) {
2456             name = getIdent();
2457             verifyStrictIdent(name, "function name");
2458         } else if (isStatement) {
2459             // Nashorn extension: anonymous function statements
2460             if (env._no_syntax_extensions) {
2461                 expect(IDENT);
2462             }
2463         }
2464 
2465         // name is null, generate anonymous name
2466         boolean isAnonymous = false;
2467         if (name == null) {
2468             final String tmpName = ANON_FUNCTION_PREFIX.symbolName() + functionLine;
2469             name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
2470             isAnonymous = true;
2471         }
2472 
2473         expect(LPAREN);
2474         final List<IdentNode> parameters = formalParameterList();
2475         expect(RPAREN);
2476 
2477         FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
2478 
2479         if (isStatement) {
2480             if (topLevel) {
2481                 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
2482             } else if (isStrictMode) {
2483                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
2484             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
2485                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
2486             } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
2487                 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
2488             }