Parser.java revision 1115:a723569d0559
126234Swpaul/* 226234Swpaul * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 326234Swpaul * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 426234Swpaul * 526234Swpaul * This code is free software; you can redistribute it and/or modify it 626234Swpaul * under the terms of the GNU General Public License version 2 only, as 726234Swpaul * published by the Free Software Foundation. Oracle designates this 826234Swpaul * particular file as subject to the "Classpath" exception as provided 926234Swpaul * by Oracle in the LICENSE file that accompanied this code. 1026234Swpaul * 1126234Swpaul * This code is distributed in the hope that it will be useful, but WITHOUT 1226234Swpaul * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1326234Swpaul * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1426234Swpaul * version 2 for more details (a copy is included in the LICENSE file that 1526234Swpaul * accompanied this code). 1626234Swpaul * 1726234Swpaul * You should have received a copy of the GNU General Public License version 1826234Swpaul * 2 along with this work; if not, write to the Free Software Foundation, 1926234Swpaul * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2026234Swpaul * 2126234Swpaul * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2226234Swpaul * or visit www.oracle.com if you need additional information or have any 2326234Swpaul * questions. 2426234Swpaul */ 2526234Swpaul 2626234Swpaulpackage jdk.nashorn.internal.parser; 2726234Swpaul 2826234Swpaulimport static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX; 2926234Swpaulimport static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; 3029735Scharnierimport static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM; 3129735Scharnierimport static jdk.nashorn.internal.parser.TokenType.ASSIGN; 3229735Scharnierimport static jdk.nashorn.internal.parser.TokenType.CASE; 3329735Scharnierimport static jdk.nashorn.internal.parser.TokenType.CATCH; 3429735Scharnierimport static jdk.nashorn.internal.parser.TokenType.COLON; 3550479Speterimport static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; 3629735Scharnierimport static jdk.nashorn.internal.parser.TokenType.CONST; 3726234Swpaulimport static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; 3826234Swpaulimport static jdk.nashorn.internal.parser.TokenType.DECPREFIX; 3926234Swpaulimport static jdk.nashorn.internal.parser.TokenType.ELSE; 4026234Swpaulimport static jdk.nashorn.internal.parser.TokenType.EOF; 4126234Swpaulimport static jdk.nashorn.internal.parser.TokenType.EOL; 4226234Swpaulimport static jdk.nashorn.internal.parser.TokenType.FINALLY; 4326234Swpaulimport static jdk.nashorn.internal.parser.TokenType.FUNCTION; 4426234Swpaulimport static jdk.nashorn.internal.parser.TokenType.IDENT; 4526234Swpaulimport static jdk.nashorn.internal.parser.TokenType.IF; 4626234Swpaulimport static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; 4726234Swpaulimport static jdk.nashorn.internal.parser.TokenType.LBRACE; 4826234Swpaulimport static jdk.nashorn.internal.parser.TokenType.LET; 4926234Swpaulimport static jdk.nashorn.internal.parser.TokenType.LPAREN; 5029735Scharnierimport static jdk.nashorn.internal.parser.TokenType.RBRACE; 5129735Scharnierimport static jdk.nashorn.internal.parser.TokenType.RBRACKET; 5226234Swpaulimport static jdk.nashorn.internal.parser.TokenType.RPAREN; 5326234Swpaulimport static jdk.nashorn.internal.parser.TokenType.SEMICOLON; 5429735Scharnierimport static jdk.nashorn.internal.parser.TokenType.TERNARY; 5526234Swpaulimport static jdk.nashorn.internal.parser.TokenType.WHILE; 5626234Swpaulimport java.io.Serializable; 5726234Swpaulimport java.util.ArrayDeque; 5826234Swpaulimport java.util.ArrayList; 5926234Swpaulimport java.util.Collections; 6026234Swpaulimport java.util.Deque; 6126234Swpaulimport java.util.HashMap; 6226234Swpaulimport java.util.HashSet; 6326234Swpaulimport java.util.Iterator; 6426234Swpaulimport java.util.List; 6526234Swpaulimport java.util.Map; 6626234Swpaulimport jdk.internal.dynalink.support.NameCodec; 6726234Swpaulimport jdk.nashorn.internal.codegen.CompilerConstants; 6826234Swpaulimport jdk.nashorn.internal.codegen.Namespace; 6926234Swpaulimport jdk.nashorn.internal.ir.AccessNode; 7026234Swpaulimport jdk.nashorn.internal.ir.BaseNode; 7126234Swpaulimport jdk.nashorn.internal.ir.BinaryNode; 7226234Swpaulimport jdk.nashorn.internal.ir.Block; 7326234Swpaulimport jdk.nashorn.internal.ir.BlockStatement; 7426234Swpaulimport jdk.nashorn.internal.ir.BreakNode; 75173412Skevloimport jdk.nashorn.internal.ir.CallNode; 76173412Skevloimport jdk.nashorn.internal.ir.CaseNode; 77173412Skevloimport jdk.nashorn.internal.ir.CatchNode; 78173412Skevloimport jdk.nashorn.internal.ir.ContinueNode; 7926234Swpaulimport jdk.nashorn.internal.ir.EmptyNode; 8026234Swpaulimport jdk.nashorn.internal.ir.Expression; 8126234Swpaulimport jdk.nashorn.internal.ir.ExpressionStatement; 8226234Swpaulimport jdk.nashorn.internal.ir.ForNode; 8326234Swpaulimport jdk.nashorn.internal.ir.FunctionNode; 8426234Swpaulimport jdk.nashorn.internal.ir.FunctionNode.CompilationState; 8526234Swpaulimport jdk.nashorn.internal.ir.IdentNode; 8626234Swpaulimport jdk.nashorn.internal.ir.IfNode; 8726234Swpaulimport jdk.nashorn.internal.ir.IndexNode; 8826234Swpaulimport jdk.nashorn.internal.ir.JoinPredecessorExpression; 8926234Swpaulimport jdk.nashorn.internal.ir.LabelNode; 9026234Swpaulimport jdk.nashorn.internal.ir.LiteralNode; 9126234Swpaulimport jdk.nashorn.internal.ir.Node; 9226234Swpaulimport jdk.nashorn.internal.ir.ObjectNode; 9326234Swpaulimport jdk.nashorn.internal.ir.PropertyKey; 9426234Swpaulimport jdk.nashorn.internal.ir.PropertyNode; 9526234Swpaulimport jdk.nashorn.internal.ir.ReturnNode; 9626234Swpaulimport jdk.nashorn.internal.ir.RuntimeNode; 9726234Swpaulimport jdk.nashorn.internal.ir.Statement; 9826234Swpaulimport jdk.nashorn.internal.ir.SwitchNode; 9926234Swpaulimport jdk.nashorn.internal.ir.TernaryNode; 10026234Swpaulimport jdk.nashorn.internal.ir.ThrowNode; 10126234Swpaulimport jdk.nashorn.internal.ir.TryNode; 10226234Swpaulimport jdk.nashorn.internal.ir.UnaryNode; 10326234Swpaulimport jdk.nashorn.internal.ir.VarNode; 10426234Swpaulimport jdk.nashorn.internal.ir.WhileNode; 105173412Skevloimport jdk.nashorn.internal.ir.WithNode; 106173412Skevloimport jdk.nashorn.internal.ir.debug.ASTWriter; 107173412Skevloimport jdk.nashorn.internal.ir.debug.PrintVisitor; 10826234Swpaulimport jdk.nashorn.internal.runtime.Context; 10926234Swpaulimport jdk.nashorn.internal.runtime.ErrorManager; 11026234Swpaulimport jdk.nashorn.internal.runtime.JSErrorType; 11126234Swpaulimport jdk.nashorn.internal.runtime.ParserException; 11226234Swpaulimport jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 11326234Swpaulimport jdk.nashorn.internal.runtime.ScriptEnvironment; 11426234Swpaulimport jdk.nashorn.internal.runtime.ScriptingFunctions; 11526234Swpaulimport jdk.nashorn.internal.runtime.Source; 11626234Swpaulimport jdk.nashorn.internal.runtime.Timing; 11726234Swpaulimport jdk.nashorn.internal.runtime.logging.DebugLogger; 11890317Salfredimport jdk.nashorn.internal.runtime.logging.Loggable; 11990317Salfredimport jdk.nashorn.internal.runtime.logging.Logger; 12090317Salfred 12126234Swpaul/** 12226234Swpaul * Builds the IR. 12326234Swpaul */ 12426234Swpaul@Logger(name="parser") 12526234Swpaulpublic class Parser extends AbstractParser implements Loggable { 12626234Swpaul private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName(); 12726234Swpaul 12826234Swpaul /** Current env. */ 12926234Swpaul private final ScriptEnvironment env; 13026234Swpaul 13126234Swpaul /** Is scripting mode. */ 13226234Swpaul private final boolean scripting; 13326234Swpaul 13426234Swpaul private List<Statement> functionDeclarations; 13526234Swpaul 13626234Swpaul private final ParserContext lc; 13726234Swpaul private final Deque<Object> defaultNames; 13826234Swpaul 13926234Swpaul /** Namespace for function names where not explicitly given */ 14026234Swpaul private final Namespace namespace; 14126234Swpaul 14226234Swpaul private final DebugLogger log; 14326234Swpaul 14426234Swpaul /** to receive line information from Lexer when scanning multine literals. */ 14526234Swpaul protected final Lexer.LineInfoReceiver lineInfoReceiver; 14626234Swpaul 14726234Swpaul private RecompilableScriptFunctionData reparsedFunction; 14826234Swpaul 14929735Scharnier /** 15029735Scharnier * Constructor 15126234Swpaul * 15226234Swpaul * @param env script environment 15326234Swpaul * @param source source to parse 15426234Swpaul * @param errors error manager 15526234Swpaul */ 15626234Swpaul public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) { 15726234Swpaul this(env, source, errors, env._strict, null); 15826234Swpaul } 15990317Salfred 16029735Scharnier /** 16129735Scharnier * Constructor 16226234Swpaul * 16326234Swpaul * @param env script environment 16426234Swpaul * @param source source to parse 16590317Salfred * @param errors error manager 16690317Salfred * @param strict strict 16790317Salfred * @param log debug logger if one is needed 16874462Salfred */ 16974462Salfred public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) { 17074462Salfred this(env, source, errors, strict, 0, log); 17174462Salfred } 17274462Salfred 17374462Salfred /** 17474462Salfred * Construct a parser. 17574462Salfred * 17674462Salfred * @param env script environment 17774462Salfred * @param source source to parse 17874462Salfred * @param errors error manager 17974462Salfred * @param strict parser created with strict mode enabled. 18074462Salfred * @param lineOffset line offset to start counting lines from 18126234Swpaul * @param log debug logger if one is needed 18290317Salfred */ 18390317Salfred public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { 18490317Salfred super(source, errors, strict, lineOffset); 18590317Salfred this.lc = new ParserContext(); 18690317Salfred this.defaultNames = new ArrayDeque<>(); 18790317Salfred this.env = env; 18890317Salfred this.namespace = new Namespace(env.getNamespace()); 18990317Salfred this.scripting = env._scripting; 19090317Salfred if (this.scripting) { 19190317Salfred this.lineInfoReceiver = new Lexer.LineInfoReceiver() { 19290317Salfred @Override 19390317Salfred public void lineInfo(final int receiverLine, final int receiverLinePosition) { 19490317Salfred // update the parser maintained line information 19590317Salfred Parser.this.line = receiverLine; 19690317Salfred Parser.this.linePosition = receiverLinePosition; 19790317Salfred } 19890317Salfred }; 19990317Salfred } else { 20090317Salfred // non-scripting mode script can't have multi-line literals 20190317Salfred this.lineInfoReceiver = null; 20290317Salfred } 20390317Salfred 20490317Salfred this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; 20590317Salfred } 20690317Salfred 20790317Salfred @Override 20826234Swpaul public DebugLogger getLogger() { 20926234Swpaul return log; 21026234Swpaul } 21126234Swpaul 21290317Salfred @Override 21390317Salfred public DebugLogger initLogger(final Context context) { 21426234Swpaul return context.getLogger(this.getClass()); 21526234Swpaul } 21626234Swpaul 21726234Swpaul /** 21826234Swpaul * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can 21926234Swpaul * preserve their already assigned name, as that name doesn't appear in their source text. 22026234Swpaul * @param name the name for the first parsed function. 22126234Swpaul */ 22226234Swpaul public void setFunctionName(final String name) { 22326234Swpaul defaultNames.push(createIdentNode(0, 0, name)); 22426234Swpaul } 22526234Swpaul 22626234Swpaul /** 227110665Sache * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this 22826234Swpaul * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation). 22926234Swpaul * This will trigger various special behaviors, such as skipping nested function bodies. 23026234Swpaul * @param reparsedFunction the function being reparsed. 23126234Swpaul */ 23226234Swpaul public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) { 23326234Swpaul this.reparsedFunction = reparsedFunction; 23426234Swpaul } 235239991Sed 23626234Swpaul /** 23726234Swpaul * Execute parse and return the resulting function node. 23826234Swpaul * Errors will be thrown and the error manager will contain information 239110665Sache * if parsing should fail 24026234Swpaul * 241110665Sache * This is the default parse call, which will name the function node 242111062Skris * {code :program} {@link CompilerConstants#PROGRAM} 243111062Skris * 244110665Sache * @return function node resulting from successful parse 24526234Swpaul */ 24626234Swpaul public FunctionNode parse() { 24726234Swpaul return parse(PROGRAM.symbolName(), 0, source.getLength(), false); 248111062Skris } 24926234Swpaul 25026234Swpaul /** 251110665Sache * Execute parse and return the resulting function node. 252110665Sache * Errors will be thrown and the error manager will contain information 253110665Sache * if parsing should fail 25426234Swpaul * 255110665Sache * This should be used to create one and only one function node 25626234Swpaul * 25726234Swpaul * @param scriptName name for the script, given to the parsed FunctionNode 25826234Swpaul * @param startPos start position in source 25926234Swpaul * @param len length of parse 26026234Swpaul * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by 26126234Swpaul * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a 26226234Swpaul * property getter or setter in an object literal. 26326234Swpaul * 26426234Swpaul * @return function node resulting from successful parse 26526234Swpaul */ 26626234Swpaul public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) { 26726234Swpaul final boolean isTimingEnabled = env.isTimingEnabled(); 26826234Swpaul final long t0 = isTimingEnabled ? System.nanoTime() : 0L; 26926234Swpaul log.info(this, " begin for '", scriptName, "'"); 27026234Swpaul 27126234Swpaul try { 27226234Swpaul stream = new TokenStream(); 27326234Swpaul lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, reparsedFunction != null); 27426234Swpaul lexer.line = lexer.pendingLine = lineOffset + 1; 27526234Swpaul line = lineOffset; 27626234Swpaul 27726234Swpaul // Set up first token (skips opening EOL.) 27826234Swpaul k = -1; 27926234Swpaul next(); 28026234Swpaul // Begin parse. 28126234Swpaul return program(scriptName, allowPropertyFunction); 28226234Swpaul } catch (final Exception e) { 28326234Swpaul handleParseException(e); 28426234Swpaul 28526234Swpaul return null; 28626234Swpaul } finally { 28729735Scharnier final String end = this + " end '" + scriptName + "'"; 28826234Swpaul if (isTimingEnabled) { 28926234Swpaul env._timing.accumulateTime(toString(), System.nanoTime() - t0); 29026234Swpaul log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms"); 29126234Swpaul } else { 29226234Swpaul log.info(end); 29329735Scharnier } 29429735Scharnier } 29526234Swpaul } 29626234Swpaul 29726234Swpaul /** 29826234Swpaul * Parse and return the list of function parameter list. A comma 29926234Swpaul * separated list of function parameter identifiers is expected to be parsed. 30026234Swpaul * Errors will be thrown and the error manager will contain information 30129735Scharnier * if parsing should fail. This method is used to check if parameter Strings 30226234Swpaul * passed to "Function" constructor is a valid or not. 30326234Swpaul * 30426234Swpaul * @return the list of IdentNodes representing the formal parameter list 30526234Swpaul */ 30626234Swpaul public List<IdentNode> parseFormalParameterList() { 30726234Swpaul try { 30826234Swpaul stream = new TokenStream(); 30926234Swpaul lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions); 31026234Swpaul 31126234Swpaul // Set up first token (skips opening EOL.) 31226234Swpaul k = -1; 31329735Scharnier next(); 31426234Swpaul 31526234Swpaul return formalParameterList(TokenType.EOF); 31626234Swpaul } catch (final Exception e) { 31729735Scharnier handleParseException(e); 31826234Swpaul return null; 31926234Swpaul } 32026234Swpaul } 32126234Swpaul 32226234Swpaul /** 32326234Swpaul * Execute parse and return the resulting function node. 32426234Swpaul * Errors will be thrown and the error manager will contain information 32526234Swpaul * if parsing should fail. This method is used to check if code String 32626234Swpaul * passed to "Function" constructor is a valid function body or not. 32726234Swpaul * 32826234Swpaul * @return function node resulting from successful parse 32926234Swpaul */ 33026234Swpaul public FunctionNode parseFunctionBody() { 33126234Swpaul try { 33226234Swpaul stream = new TokenStream(); 33326234Swpaul lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions); 33426234Swpaul final int functionLine = line; 33526234Swpaul 33626234Swpaul // Set up first token (skips opening EOL.) 33726234Swpaul k = -1; 33826234Swpaul next(); 33926234Swpaul 34026234Swpaul // Make a fake token for the function. 34126234Swpaul final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 34226234Swpaul // Set up the function to append elements. 34326234Swpaul 34426234Swpaul final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()); 34526234Swpaul final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList()); 34626234Swpaul lc.push(function); 34726234Swpaul 34826234Swpaul final ParserContextBlockNode body = newBlock(); 34926234Swpaul 35026234Swpaul functionDeclarations = new ArrayList<>(); 35126234Swpaul sourceElements(false); 35226234Swpaul addFunctionDeclarations(function); 35326234Swpaul functionDeclarations = null; 35426234Swpaul 35526234Swpaul restoreBlock(body); 35626234Swpaul body.setFlag(Block.NEEDS_SCOPE); 35726234Swpaul 35826234Swpaul final Block functionBody = new Block(functionToken, source.getLength() - 1, body.getFlags(), body.getStatements()); 35926234Swpaul lc.pop(function); 36026234Swpaul 36126234Swpaul expect(EOF); 36226234Swpaul 36326234Swpaul final FunctionNode functionNode = createFunctionNode( 364228662Sdim function, 36526234Swpaul functionToken, 36626234Swpaul ident, 36726234Swpaul Collections.<IdentNode>emptyList(), 36826234Swpaul FunctionNode.Kind.NORMAL, 36926234Swpaul functionLine, 37026234Swpaul functionBody); 37126234Swpaul printAST(functionNode); 37226234Swpaul return functionNode; 37326234Swpaul } catch (final Exception e) { 37426234Swpaul handleParseException(e); 37526234Swpaul return null; 37626234Swpaul } 37726234Swpaul } 37826234Swpaul 37926234Swpaul private void handleParseException(final Exception e) { 38026234Swpaul // Extract message from exception. The message will be in error 38126234Swpaul // message format. 38226234Swpaul String message = e.getMessage(); 383228662Sdim 38426234Swpaul // If empty message. 38526234Swpaul if (message == null) { 38626234Swpaul message = e.toString(); 38726234Swpaul } 38826234Swpaul 38926234Swpaul // Issue message. 39026234Swpaul if (e instanceof ParserException) { 39126234Swpaul errors.error((ParserException)e); 39226234Swpaul } else { 39326234Swpaul errors.error(message); 39426234Swpaul } 39526234Swpaul 39626234Swpaul if (env._dump_on_error) { 39726234Swpaul e.printStackTrace(env.getErr()); 39826234Swpaul } 39926234Swpaul } 40026234Swpaul 40126234Swpaul /** 40226234Swpaul * Skip to a good parsing recovery point. 40326234Swpaul */ 40426234Swpaul private void recover(final Exception e) { 40526234Swpaul if (e != null) { 40626234Swpaul // Extract message from exception. The message will be in error 40726234Swpaul // message format. 40826234Swpaul String message = e.getMessage(); 40926234Swpaul 41026234Swpaul // If empty message. 411228662Sdim if (message == null) { 41226234Swpaul message = e.toString(); 41326234Swpaul } 41426234Swpaul 41526234Swpaul // Issue message. 41626234Swpaul if (e instanceof ParserException) { 41726234Swpaul errors.error((ParserException)e); 41826234Swpaul } else { 41926234Swpaul errors.error(message); 42026234Swpaul } 42126234Swpaul 42226234Swpaul if (env._dump_on_error) { 42326234Swpaul e.printStackTrace(env.getErr()); 42426234Swpaul } 42526234Swpaul } 42626234Swpaul 42726234Swpaul // Skip to a recovery point. 42826234Swpaulloop: 42926234Swpaul while (true) { 43026234Swpaul switch (type) { 43126234Swpaul case EOF: 43226234Swpaul // Can not go any further. 43326234Swpaul break loop; 43426234Swpaul case EOL: 43526234Swpaul case SEMICOLON: 43626234Swpaul case RBRACE: 43726234Swpaul // Good recovery points. 43826234Swpaul next(); 43926234Swpaul break loop; 44026234Swpaul default: 44126234Swpaul // So we can recover after EOL. 44226234Swpaul nextOrEOL(); 44326234Swpaul break; 44426234Swpaul } 44526234Swpaul } 44626234Swpaul } 44726234Swpaul 44826234Swpaul /** 44926234Swpaul * Set up a new block. 45026234Swpaul * 45126234Swpaul * @return New block. 45226234Swpaul */ 45326234Swpaul private ParserContextBlockNode newBlock() { 45426234Swpaul return lc.push(new ParserContextBlockNode(token)); 45526234Swpaul } 45626234Swpaul 45726234Swpaul private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) { 45826234Swpaul // Build function name. 45926234Swpaul final StringBuilder sb = new StringBuilder(); 46026234Swpaul 46126234Swpaul final ParserContextFunctionNode parentFunction = lc.getCurrentFunction(); 46226234Swpaul if (parentFunction != null && !parentFunction.isProgram()) { 463228662Sdim sb.append(parentFunction.getName()).append('$'); 46426234Swpaul } 46526234Swpaul 46626234Swpaul assert ident.getName() != null; 46726234Swpaul sb.append(ident.getName()); 46826234Swpaul 46926234Swpaul final String name = namespace.uniqueName(sb.toString()); 47026234Swpaul assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name; 47126234Swpaul 47226234Swpaul int flags = 0; 47326234Swpaul if (isStrictMode) { 47426234Swpaul flags |= FunctionNode.IS_STRICT; 47526234Swpaul } 47626234Swpaul if (parentFunction == null) { 47726234Swpaul flags |= FunctionNode.IS_PROGRAM; 47826234Swpaul } 47926234Swpaul 48026234Swpaul final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters); 48126234Swpaul functionNode.setFlag(flags); 48226234Swpaul return functionNode; 48326234Swpaul } 48426234Swpaul 48526234Swpaul private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){ 48626234Swpaul final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED; 48726234Swpaul // Start new block. 48826234Swpaul final FunctionNode functionNode = 48926234Swpaul new FunctionNode( 49026234Swpaul source, 49126234Swpaul functionLine, 492228662Sdim body.getToken(), 493228662Sdim Token.descPosition(body.getToken()), 49426234Swpaul startToken, 49526234Swpaul function.getLastToken(), 49626234Swpaul namespace, 49726234Swpaul ident, 49826234Swpaul function.getName(), 49926234Swpaul parameters, 50026234Swpaul kind, 50126234Swpaul function.getFlags(), 50226234Swpaul body, 50326234Swpaul state, 50426234Swpaul function.getEndParserState()); 50526234Swpaul 50626234Swpaul printAST(functionNode); 50726234Swpaul 50826234Swpaul return functionNode; 50926234Swpaul } 51026234Swpaul 51126234Swpaul /** 51226234Swpaul * Restore the current block. 51326234Swpaul */ 51426234Swpaul private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) { 51526234Swpaul return lc.pop(block); 51626234Swpaul } 51726234Swpaul 51826234Swpaul /** 51926234Swpaul * Get the statements in a block. 520228662Sdim * @return Block statements. 52126234Swpaul */ 52226234Swpaul private Block getBlock(final boolean needsBraces) { 52326234Swpaul final long blockToken = token; 52426234Swpaul final ParserContextBlockNode newBlock = newBlock(); 52526234Swpaul try { 52626234Swpaul // Block opening brace. 52726234Swpaul if (needsBraces) { 52826234Swpaul expect(LBRACE); 52926234Swpaul } 53026234Swpaul // Accumulate block statements. 53126234Swpaul statementList(); 53226234Swpaul 53326234Swpaul } finally { 53426234Swpaul restoreBlock(newBlock); 53526234Swpaul } 53626234Swpaul 53726234Swpaul // Block closing brace. 53826234Swpaul if (needsBraces) { 53926234Swpaul expect(RBRACE); 54026234Swpaul } 54126234Swpaul 54226234Swpaul return new Block(blockToken, finish, newBlock.getFlags(), newBlock.getStatements()); 54326234Swpaul } 54426234Swpaul 54526234Swpaul 54626234Swpaul /** 54726234Swpaul * Get all the statements generated by a single statement. 548228662Sdim * @return Statements. 54926234Swpaul */ 55026234Swpaul private Block getStatement() { 55126234Swpaul if (type == LBRACE) { 55226234Swpaul return getBlock(true); 55326234Swpaul } 55426234Swpaul // Set up new block. Captures first token. 55526234Swpaul final ParserContextBlockNode newBlock = newBlock(); 55626234Swpaul try { 55726234Swpaul statement(); 55826234Swpaul } finally { 55926234Swpaul restoreBlock(newBlock); 56026234Swpaul } 56126234Swpaul return new Block(newBlock.getToken(), finish, newBlock.getFlags(), newBlock.getStatements()); 56226234Swpaul } 56326234Swpaul 56426234Swpaul /** 56526234Swpaul * Detect calls to special functions. 56626234Swpaul * @param ident Called function. 56726234Swpaul */ 56826234Swpaul private void detectSpecialFunction(final IdentNode ident) { 56926234Swpaul final String name = ident.getName(); 57026234Swpaul 57126234Swpaul if (EVAL.symbolName().equals(name)) { 57226234Swpaul markEval(lc); 57326234Swpaul } 57426234Swpaul } 57526234Swpaul 57626234Swpaul /** 57726234Swpaul * Detect use of special properties. 578239991Sed * @param ident Referenced property. 57926234Swpaul */ 58026234Swpaul private void detectSpecialProperty(final IdentNode ident) { 58126234Swpaul if (isArguments(ident)) { 58226234Swpaul lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS); 58326234Swpaul } 58426234Swpaul } 58526234Swpaul 58626234Swpaul private boolean useBlockScope() { 58726234Swpaul return env._es6; 58826234Swpaul } 58926234Swpaul 59026234Swpaul private static boolean isArguments(final String name) { 59126234Swpaul return ARGUMENTS_NAME.equals(name); 59226234Swpaul } 59326234Swpaul 59426234Swpaul private static boolean isArguments(final IdentNode ident) { 59526234Swpaul return isArguments(ident.getName()); 59626234Swpaul } 59726234Swpaul 59826234Swpaul /** 59926234Swpaul * Tells whether a IdentNode can be used as L-value of an assignment 60026234Swpaul * 60126234Swpaul * @param ident IdentNode to be checked 60226234Swpaul * @return whether the ident can be used as L-value 60326234Swpaul */ 60426234Swpaul private static boolean checkIdentLValue(final IdentNode ident) { 60526234Swpaul return Token.descType(ident.getToken()).getKind() != TokenKind.KEYWORD; 60626234Swpaul } 60726234Swpaul 60826234Swpaul /** 60926234Swpaul * Verify an assignment expression. 61026234Swpaul * @param op Operation token. 61126234Swpaul * @param lhs Left hand side expression. 61226234Swpaul * @param rhs Right hand side expression. 61326234Swpaul * @return Verified expression. 61426234Swpaul */ 61526234Swpaul private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) { 61626234Swpaul final TokenType opType = Token.descType(op); 61726234Swpaul 61826234Swpaul switch (opType) { 61926234Swpaul case ASSIGN: 62026234Swpaul case ASSIGN_ADD: 62126234Swpaul case ASSIGN_BIT_AND: 62226234Swpaul case ASSIGN_BIT_OR: 62326234Swpaul case ASSIGN_BIT_XOR: 62426234Swpaul case ASSIGN_DIV: 62526234Swpaul case ASSIGN_MOD: 62626234Swpaul case ASSIGN_MUL: 62726234Swpaul case ASSIGN_SAR: 62826234Swpaul case ASSIGN_SHL: 62926234Swpaul case ASSIGN_SHR: 63026234Swpaul case ASSIGN_SUB: 63126234Swpaul if (!(lhs instanceof AccessNode || 63226234Swpaul lhs instanceof IndexNode || 63326234Swpaul lhs instanceof IdentNode)) { 63426234Swpaul return referenceError(lhs, rhs, env._early_lvalue_error); 63526234Swpaul } 63626234Swpaul 63726234Swpaul if (lhs instanceof IdentNode) { 63826234Swpaul if (!checkIdentLValue((IdentNode)lhs)) { 63926234Swpaul return referenceError(lhs, rhs, false); 64026234Swpaul } 64126234Swpaul verifyStrictIdent((IdentNode)lhs, "assignment"); 64226234Swpaul } 64326234Swpaul break; 64426234Swpaul 64595658Sdes default: 64626234Swpaul break; 64726234Swpaul } 64826234Swpaul 64926234Swpaul // Build up node. 65026234Swpaul if(BinaryNode.isLogical(opType)) { 65126234Swpaul return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); 65295658Sdes } 65326234Swpaul return new BinaryNode(op, lhs, rhs); 65426234Swpaul } 65526234Swpaul 65695658Sdes 65795658Sdes /** 65826234Swpaul * Reduce increment/decrement to simpler operations. 65926234Swpaul * @param firstToken First token. 66026234Swpaul * @param tokenType Operation token (INCPREFIX/DEC.) 66126234Swpaul * @param expression Left hand side expression. 66226234Swpaul * @param isPostfix Prefix or postfix. 66395658Sdes * @return Reduced expression. 66495658Sdes */ 66526234Swpaul private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) { 66626234Swpaul if (isPostfix) { 66726234Swpaul return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); 66826234Swpaul } 66926234Swpaul 67095658Sdes return new UnaryNode(firstToken, expression); 67195658Sdes } 67226234Swpaul 67326234Swpaul /** 67426234Swpaul * ----------------------------------------------------------------------- 67526234Swpaul * 67626234Swpaul * Grammar based on 67795658Sdes * 67895658Sdes * ECMAScript Language Specification 67926234Swpaul * ECMA-262 5th Edition / December 2009 68026234Swpaul * 68126234Swpaul * ----------------------------------------------------------------------- 68226234Swpaul */ 68326234Swpaul 68495658Sdes /** 68595658Sdes * Program : 68626234Swpaul * SourceElements? 68726234Swpaul * 68826234Swpaul * See 14 68926234Swpaul * 69026234Swpaul * Parse the top level script. 69195658Sdes */ 69295658Sdes private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) { 69326234Swpaul // Make a pseudo-token for the script holding its start and length. 69426234Swpaul final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength()); 69526234Swpaul final int functionLine = line; 69626234Swpaul 69726234Swpaul final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName); 69895658Sdes final ParserContextFunctionNode script = createParserContextFunctionNode( 69995658Sdes ident, 70026234Swpaul functionToken, 70126234Swpaul FunctionNode.Kind.SCRIPT, 70226234Swpaul functionLine, 70326234Swpaul Collections.<IdentNode>emptyList()); 70426234Swpaul lc.push(script); 70526234Swpaul final ParserContextBlockNode body = newBlock(); 70695658Sdes 70795658Sdes functionDeclarations = new ArrayList<>(); 70826234Swpaul sourceElements(allowPropertyFunction); 70926234Swpaul addFunctionDeclarations(script); 71026234Swpaul functionDeclarations = null; 71126234Swpaul 71226234Swpaul restoreBlock(body); 71326234Swpaul body.setFlag(Block.NEEDS_SCOPE); 71495658Sdes final Block programBody = new Block(functionToken, functionLine, body.getFlags(), body.getStatements()); 71526234Swpaul lc.pop(script); 71626234Swpaul script.setLastToken(token); 71726234Swpaul 71826234Swpaul expect(EOF); 71926234Swpaul 72026234Swpaul return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody); 72195658Sdes } 72226234Swpaul 72326234Swpaul /** 72426234Swpaul * Directive value or null if statement is not a directive. 72526234Swpaul * 72626234Swpaul * @param stmt Statement to be checked 72726234Swpaul * @return Directive value if the given statement is a directive 72826234Swpaul */ 72926234Swpaul private String getDirective(final Node stmt) { 73026234Swpaul if (stmt instanceof ExpressionStatement) { 73126234Swpaul final Node expr = ((ExpressionStatement)stmt).getExpression(); 73226234Swpaul if (expr instanceof LiteralNode) { 73326234Swpaul final LiteralNode<?> lit = (LiteralNode<?>)expr; 73426234Swpaul final long litToken = lit.getToken(); 73526234Swpaul final TokenType tt = Token.descType(litToken); 73626234Swpaul // A directive is either a string or an escape string 73726234Swpaul if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) { 73826234Swpaul // Make sure that we don't unescape anything. Return as seen in source! 73926234Swpaul return source.getString(lit.getStart(), Token.descLength(litToken)); 74026234Swpaul } 74126234Swpaul } 74226234Swpaul } 74326234Swpaul 74426234Swpaul return null; 74526234Swpaul } 74626234Swpaul 74726234Swpaul /** 74826234Swpaul * SourceElements : 74926234Swpaul * SourceElement 75095658Sdes * SourceElements SourceElement 75195658Sdes * 75226234Swpaul * See 14 75326234Swpaul * 75426234Swpaul * Parse the elements of the script or function. 75526234Swpaul */ 75695658Sdes private void sourceElements(final boolean shouldAllowPropertyFunction) { 75726234Swpaul List<Node> directiveStmts = null; 75826234Swpaul boolean checkDirective = true; 75926234Swpaul boolean allowPropertyFunction = shouldAllowPropertyFunction; 76026234Swpaul final boolean oldStrictMode = isStrictMode; 76195658Sdes 76226234Swpaul 76326234Swpaul try { 76426234Swpaul // If is a script, then process until the end of the script. 76526234Swpaul while (type != EOF) { 76626234Swpaul // Break if the end of a code block. 76726234Swpaul if (type == RBRACE) { 76826234Swpaul break; 76926234Swpaul } 77026234Swpaul 77126234Swpaul try { 77226234Swpaul // Get the next element. 77326234Swpaul statement(true, allowPropertyFunction); 77426234Swpaul allowPropertyFunction = false; 77526234Swpaul 776100120Salfred // check for directive prologues 77726234Swpaul if (checkDirective) { 778100120Salfred // skip any debug statement like line number to get actual first line 779100120Salfred final Statement lastStatement = lc.getLastStatement(); 78026234Swpaul 78126234Swpaul // get directive prologue, if any 78226234Swpaul final String directive = getDirective(lastStatement); 78326234Swpaul 78426234Swpaul // If we have seen first non-directive statement, 78574627Salfred // no more directive statements!! 78626234Swpaul checkDirective = directive != null; 78726234Swpaul 78826234Swpaul if (checkDirective) { 78926234Swpaul if (!oldStrictMode) { 79026234Swpaul if (directiveStmts == null) { 79126234Swpaul directiveStmts = new ArrayList<>(); 792228662Sdim } 79326234Swpaul directiveStmts.add(lastStatement); 79426234Swpaul } 79526234Swpaul 79626234Swpaul // handle use strict directive 79726234Swpaul if ("use strict".equals(directive)) { 79826234Swpaul isStrictMode = true; 79926234Swpaul final ParserContextFunctionNode function = lc.getCurrentFunction(); 80026234Swpaul function.setFlag(FunctionNode.IS_STRICT); 80126234Swpaul 80226234Swpaul // We don't need to check these, if lexical environment is already strict 803228662Sdim if (!oldStrictMode && directiveStmts != null) { 80426234Swpaul // check that directives preceding this one do not violate strictness 80526234Swpaul for (final Node statement : directiveStmts) { 80626234Swpaul // the get value will force unescape of preceeding 80726234Swpaul // escaped string directives 80826234Swpaul getValue(statement.getToken()); 80926234Swpaul } 81026234Swpaul 81126234Swpaul // verify that function name as well as parameter names 81226234Swpaul // satisfy strict mode restrictions. 81326234Swpaul verifyStrictIdent(function.getIdent(), "function name"); 81426234Swpaul for (final IdentNode param : function.getParameters()) { 81526234Swpaul verifyStrictIdent(param, "function parameter"); 81626234Swpaul } 81726234Swpaul } 81826234Swpaul } else if (Context.DEBUG) { 81926234Swpaul final int flag = FunctionNode.getDirectiveFlag(directive); 82026234Swpaul if (flag != 0) { 82126234Swpaul final ParserContextFunctionNode function = lc.getCurrentFunction(); 822 function.setFlag(flag); 823 } 824 } 825 } 826 } 827 } catch (final Exception e) { 828 //recover parsing 829 recover(e); 830 } 831 832 // No backtracking from here on. 833 stream.commit(k); 834 } 835 } finally { 836 isStrictMode = oldStrictMode; 837 } 838 } 839 840 /** 841 * Statement : 842 * Block 843 * VariableStatement 844 * EmptyStatement 845 * ExpressionStatement 846 * IfStatement 847 * IterationStatement 848 * ContinueStatement 849 * BreakStatement 850 * ReturnStatement 851 * WithStatement 852 * LabelledStatement 853 * SwitchStatement 854 * ThrowStatement 855 * TryStatement 856 * DebuggerStatement 857 * 858 * see 12 859 * 860 * Parse any of the basic statement types. 861 */ 862 private void statement() { 863 statement(false, false); 864 } 865 866 /** 867 * @param topLevel does this statement occur at the "top level" of a script or a function? 868 */ 869 private void statement(final boolean topLevel, final boolean allowPropertyFunction) { 870 if (type == FUNCTION) { 871 // As per spec (ECMA section 12), function declarations as arbitrary statement 872 // is not "portable". Implementation can issue a warning or disallow the same. 873 functionExpression(true, topLevel); 874 return; 875 } 876 877 switch (type) { 878 case LBRACE: 879 block(); 880 break; 881 case VAR: 882 variableStatement(type, true); 883 break; 884 case SEMICOLON: 885 emptyStatement(); 886 break; 887 case IF: 888 ifStatement(); 889 break; 890 case FOR: 891 forStatement(); 892 break; 893 case WHILE: 894 whileStatement(); 895 break; 896 case DO: 897 doStatement(); 898 break; 899 case CONTINUE: 900 continueStatement(); 901 break; 902 case BREAK: 903 breakStatement(); 904 break; 905 case RETURN: 906 returnStatement(); 907 break; 908 case YIELD: 909 yieldStatement(); 910 break; 911 case WITH: 912 withStatement(); 913 break; 914 case SWITCH: 915 switchStatement(); 916 break; 917 case THROW: 918 throwStatement(); 919 break; 920 case TRY: 921 tryStatement(); 922 break; 923 case DEBUGGER: 924 debuggerStatement(); 925 break; 926 case RPAREN: 927 case RBRACKET: 928 case EOF: 929 expect(SEMICOLON); 930 break; 931 default: 932 if (useBlockScope() && (type == LET || type == CONST)) { 933 variableStatement(type, true); 934 break; 935 } 936 if (env._const_as_var && type == CONST) { 937 variableStatement(TokenType.VAR, true); 938 break; 939 } 940 941 if (type == IDENT || isNonStrictModeIdent()) { 942 if (T(k + 1) == COLON) { 943 labelStatement(); 944 return; 945 } 946 if(allowPropertyFunction) { 947 final String ident = (String)getValue(); 948 final long propertyToken = token; 949 final int propertyLine = line; 950 if("get".equals(ident)) { 951 next(); 952 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); 953 return; 954 } else if("set".equals(ident)) { 955 next(); 956 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); 957 return; 958 } 959 } 960 } 961 962 expressionStatement(); 963 break; 964 } 965 } 966 967 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { 968 final FunctionNode fn = propertyFunction.functionNode; 969 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); 970 } 971 972 /** 973 * block : 974 * { StatementList? } 975 * 976 * see 12.1 977 * 978 * Parse a statement block. 979 */ 980 private void block() { 981 appendStatement(new BlockStatement(line, getBlock(true))); 982 } 983 984 /** 985 * StatementList : 986 * Statement 987 * StatementList Statement 988 * 989 * See 12.1 990 * 991 * Parse a list of statements. 992 */ 993 private void statementList() { 994 // Accumulate statements until end of list. */ 995loop: 996 while (type != EOF) { 997 switch (type) { 998 case EOF: 999 case CASE: 1000 case DEFAULT: 1001 case RBRACE: 1002 break loop; 1003 default: 1004 break; 1005 } 1006 1007 // Get next statement. 1008 statement(); 1009 } 1010 } 1011 1012 /** 1013 * Make sure that in strict mode, the identifier name used is allowed. 1014 * 1015 * @param ident Identifier that is verified 1016 * @param contextString String used in error message to give context to the user 1017 */ 1018 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 1019 if (isStrictMode) { 1020 switch (ident.getName()) { 1021 case "eval": 1022 case "arguments": 1023 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1024 default: 1025 break; 1026 } 1027 1028 if (ident.isFutureStrictName()) { 1029 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1030 } 1031 } 1032 } 1033 1034 /** 1035 * VariableStatement : 1036 * var VariableDeclarationList ; 1037 * 1038 * VariableDeclarationList : 1039 * VariableDeclaration 1040 * VariableDeclarationList , VariableDeclaration 1041 * 1042 * VariableDeclaration : 1043 * Identifier Initializer? 1044 * 1045 * Initializer : 1046 * = AssignmentExpression 1047 * 1048 * See 12.2 1049 * 1050 * Parse a VAR statement. 1051 * @param isStatement True if a statement (not used in a FOR.) 1052 */ 1053 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) { 1054 // VAR tested in caller. 1055 next(); 1056 1057 final List<VarNode> vars = new ArrayList<>(); 1058 int varFlags = VarNode.IS_STATEMENT; 1059 if (varType == LET) { 1060 varFlags |= VarNode.IS_LET; 1061 } else if (varType == CONST) { 1062 varFlags |= VarNode.IS_CONST; 1063 } 1064 1065 while (true) { 1066 // Get starting token. 1067 final int varLine = line; 1068 final long varToken = token; 1069 // Get name of var. 1070 final IdentNode name = getIdent(); 1071 verifyStrictIdent(name, "variable name"); 1072 1073 // Assume no init. 1074 Expression init = null; 1075 1076 // Look for initializer assignment. 1077 if (type == ASSIGN) { 1078 next(); 1079 1080 // Get initializer expression. Suppress IN if not statement. 1081 defaultNames.push(name); 1082 try { 1083 init = assignmentExpression(!isStatement); 1084 } finally { 1085 defaultNames.pop(); 1086 } 1087 } else if (varType == CONST) { 1088 throw error(AbstractParser.message("missing.const.assignment", name.getName())); 1089 } 1090 1091 // Allocate var node. 1092 final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags); 1093 vars.add(var); 1094 appendStatement(var); 1095 1096 if (type != COMMARIGHT) { 1097 break; 1098 } 1099 next(); 1100 } 1101 1102 // If is a statement then handle end of line. 1103 if (isStatement) { 1104 endOfLine(); 1105 } 1106 1107 return vars; 1108 } 1109 1110 /** 1111 * EmptyStatement : 1112 * ; 1113 * 1114 * See 12.3 1115 * 1116 * Parse an empty statement. 1117 */ 1118 private void emptyStatement() { 1119 if (env._empty_statements) { 1120 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); 1121 } 1122 1123 // SEMICOLON checked in caller. 1124 next(); 1125 } 1126 1127 /** 1128 * ExpressionStatement : 1129 * Expression ; // [lookahead ~( or function )] 1130 * 1131 * See 12.4 1132 * 1133 * Parse an expression used in a statement block. 1134 */ 1135 private void expressionStatement() { 1136 // Lookahead checked in caller. 1137 final int expressionLine = line; 1138 final long expressionToken = token; 1139 1140 // Get expression and add as statement. 1141 final Expression expression = expression(); 1142 1143 ExpressionStatement expressionStatement = null; 1144 if (expression != null) { 1145 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); 1146 appendStatement(expressionStatement); 1147 } else { 1148 expect(null); 1149 } 1150 1151 endOfLine(); 1152 } 1153 1154 /** 1155 * IfStatement : 1156 * if ( Expression ) Statement else Statement 1157 * if ( Expression ) Statement 1158 * 1159 * See 12.5 1160 * 1161 * Parse an IF statement. 1162 */ 1163 private void ifStatement() { 1164 // Capture IF token. 1165 final int ifLine = line; 1166 final long ifToken = token; 1167 // IF tested in caller. 1168 next(); 1169 1170 expect(LPAREN); 1171 final Expression test = expression(); 1172 expect(RPAREN); 1173 final Block pass = getStatement(); 1174 1175 Block fail = null; 1176 if (type == ELSE) { 1177 next(); 1178 fail = getStatement(); 1179 } 1180 1181 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 1182 } 1183 1184 /** 1185 * ... IterationStatement: 1186 * ... 1187 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement 1188 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement 1189 * for ( LeftHandSideExpression in Expression ) Statement 1190 * for ( var VariableDeclaration[NoIn] in Expression ) Statement 1191 * 1192 * See 12.6 1193 * 1194 * Parse a FOR statement. 1195 */ 1196 private void forStatement() { 1197 final long forToken = token; 1198 final int forLine = line; 1199 // When ES6 for-let is enabled we create a container block to capture the LET. 1200 final int startLine = start; 1201 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null; 1202 1203 1204 // Create FOR node, capturing FOR token. 1205 final ParserContextLoopNode forNode = new ParserContextLoopNode(); 1206 lc.push(forNode); 1207 Block body = null; 1208 List<VarNode> vars = null; 1209 Expression init = null; 1210 JoinPredecessorExpression test = null; 1211 JoinPredecessorExpression modify = null; 1212 1213 int flags = 0; 1214 1215 try { 1216 // FOR tested in caller. 1217 next(); 1218 1219 // Nashorn extension: for each expression. 1220 // iterate property values rather than property names. 1221 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 1222 flags |= ForNode.IS_FOR_EACH; 1223 next(); 1224 } 1225 1226 expect(LPAREN); 1227 1228 1229 switch (type) { 1230 case VAR: 1231 // Var statements captured in for outer block. 1232 vars = variableStatement(type, false); 1233 break; 1234 case SEMICOLON: 1235 break; 1236 default: 1237 if (useBlockScope() && (type == LET || type == CONST)) { 1238 // LET/CONST captured in container block created above. 1239 vars = variableStatement(type, false); 1240 break; 1241 } 1242 if (env._const_as_var && type == CONST) { 1243 // Var statements captured in for outer block. 1244 vars = variableStatement(TokenType.VAR, false); 1245 break; 1246 } 1247 1248 init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 1249 break; 1250 } 1251 1252 switch (type) { 1253 case SEMICOLON: 1254 // for (init; test; modify) 1255 1256 // for each (init; test; modify) is invalid 1257 if ((flags & ForNode.IS_FOR_EACH) != 0) { 1258 throw error(AbstractParser.message("for.each.without.in"), token); 1259 } 1260 1261 expect(SEMICOLON); 1262 if (type != SEMICOLON) { 1263 test = joinPredecessorExpression(); 1264 } 1265 expect(SEMICOLON); 1266 if (type != RPAREN) { 1267 modify = joinPredecessorExpression(); 1268 } 1269 break; 1270 1271 case IN: 1272 flags |= ForNode.IS_FOR_IN; 1273 test = new JoinPredecessorExpression(); 1274 if (vars != null) { 1275 // for (var i in obj) 1276 if (vars.size() == 1) { 1277 init = new IdentNode(vars.get(0).getName()); 1278 } else { 1279 // for (var i, j in obj) is invalid 1280 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 1281 } 1282 1283 } else { 1284 // for (expr in obj) 1285 assert init != null : "for..in init expression can not be null here"; 1286 1287 // check if initial expression is a valid L-value 1288 if (!(init instanceof AccessNode || 1289 init instanceof IndexNode || 1290 init instanceof IdentNode)) { 1291 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1292 } 1293 1294 if (init instanceof IdentNode) { 1295 if (!checkIdentLValue((IdentNode)init)) { 1296 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1297 } 1298 verifyStrictIdent((IdentNode)init, "for-in iterator"); 1299 } 1300 } 1301 1302 next(); 1303 1304 // Get the collection expression. 1305 modify = joinPredecessorExpression(); 1306 break; 1307 1308 default: 1309 expect(SEMICOLON); 1310 break; 1311 } 1312 1313 expect(RPAREN); 1314 1315 // Set the for body. 1316 body = getStatement(); 1317 } finally { 1318 lc.pop(forNode); 1319 if (vars != null) { 1320 for (final VarNode var : vars) { 1321 appendStatement(var); 1322 } 1323 } 1324 if (body != null) { 1325 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); 1326 } 1327 if (outer != null) { 1328 restoreBlock(outer); 1329 appendStatement(new BlockStatement(startLine, new Block( 1330 outer.getToken(), 1331 body.getFinish(), 1332 outer.getStatements()))); 1333 } 1334 } 1335 } 1336 1337 /** 1338 * ...IterationStatement : 1339 * ... 1340 * while ( Expression ) Statement 1341 * ... 1342 * 1343 * See 12.6 1344 * 1345 * Parse while statement. 1346 */ 1347 private void whileStatement() { 1348 // Capture WHILE token. 1349 final long whileToken = token; 1350 final int whileLine = line; 1351 // WHILE tested in caller. 1352 next(); 1353 1354 final ParserContextLoopNode whileNode = new ParserContextLoopNode(); 1355 lc.push(whileNode); 1356 1357 JoinPredecessorExpression test = null; 1358 Block body = null; 1359 1360 try { 1361 expect(LPAREN); 1362 test = joinPredecessorExpression(); 1363 expect(RPAREN); 1364 body = getStatement(); 1365 } finally { 1366 lc.pop(whileNode); 1367 if (body != null){ 1368 appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body)); 1369 } 1370 } 1371 } 1372 1373 /** 1374 * ...IterationStatement : 1375 * ... 1376 * do Statement while( Expression ) ; 1377 * ... 1378 * 1379 * See 12.6 1380 * 1381 * Parse DO WHILE statement. 1382 */ 1383 private void doStatement() { 1384 // Capture DO token. 1385 final long doToken = token; 1386 int doLine = 0; 1387 // DO tested in the caller. 1388 next(); 1389 1390 final ParserContextLoopNode doWhileNode = new ParserContextLoopNode(); 1391 lc.push(doWhileNode); 1392 1393 Block body = null; 1394 JoinPredecessorExpression test = null; 1395 1396 try { 1397 // Get DO body. 1398 body = getStatement(); 1399 1400 expect(WHILE); 1401 expect(LPAREN); 1402 doLine = line; 1403 test = joinPredecessorExpression(); 1404 expect(RPAREN); 1405 1406 if (type == SEMICOLON) { 1407 endOfLine(); 1408 } 1409 } finally { 1410 lc.pop(doWhileNode); 1411 appendStatement(new WhileNode(doLine, doToken, finish, true, test, body)); 1412 } 1413 } 1414 1415 /** 1416 * ContinueStatement : 1417 * continue Identifier? ; // [no LineTerminator here] 1418 * 1419 * See 12.7 1420 * 1421 * Parse CONTINUE statement. 1422 */ 1423 private void continueStatement() { 1424 // Capture CONTINUE token. 1425 final int continueLine = line; 1426 final long continueToken = token; 1427 // CONTINUE tested in caller. 1428 nextOrEOL(); 1429 1430 ParserContextLabelNode labelNode = null; 1431 1432 // SEMICOLON or label. 1433 switch (type) { 1434 case RBRACE: 1435 case SEMICOLON: 1436 case EOL: 1437 case EOF: 1438 break; 1439 1440 default: 1441 final IdentNode ident = getIdent(); 1442 labelNode = lc.findLabel(ident.getName()); 1443 1444 if (labelNode == null) { 1445 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1446 } 1447 1448 break; 1449 } 1450 1451 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1452 final ParserContextLoopNode targetNode = lc.getContinueTo(labelName); 1453 1454 if (targetNode == null) { 1455 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 1456 } 1457 1458 endOfLine(); 1459 1460 // Construct and add CONTINUE node. 1461 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); 1462 } 1463 1464 /** 1465 * BreakStatement : 1466 * break Identifier? ; // [no LineTerminator here] 1467 * 1468 * See 12.8 1469 * 1470 */ 1471 private void breakStatement() { 1472 // Capture BREAK token. 1473 final int breakLine = line; 1474 final long breakToken = token; 1475 // BREAK tested in caller. 1476 nextOrEOL(); 1477 1478 ParserContextLabelNode labelNode = null; 1479 1480 // SEMICOLON or label. 1481 switch (type) { 1482 case RBRACE: 1483 case SEMICOLON: 1484 case EOL: 1485 case EOF: 1486 break; 1487 1488 default: 1489 final IdentNode ident = getIdent(); 1490 labelNode = lc.findLabel(ident.getName()); 1491 1492 if (labelNode == null) { 1493 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1494 } 1495 1496 break; 1497 } 1498 1499 //either an explicit label - then get its node or just a "break" - get first breakable 1500 //targetNode is what we are breaking out from. 1501 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1502 final ParserContextBreakableNode targetNode = lc.getBreakable(labelName); 1503 if (targetNode == null) { 1504 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 1505 } 1506 1507 endOfLine(); 1508 1509 // Construct and add BREAK node. 1510 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); 1511 } 1512 1513 /** 1514 * ReturnStatement : 1515 * return Expression? ; // [no LineTerminator here] 1516 * 1517 * See 12.9 1518 * 1519 * Parse RETURN statement. 1520 */ 1521 private void returnStatement() { 1522 // check for return outside function 1523 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { 1524 throw error(AbstractParser.message("invalid.return")); 1525 } 1526 1527 // Capture RETURN token. 1528 final int returnLine = line; 1529 final long returnToken = token; 1530 // RETURN tested in caller. 1531 nextOrEOL(); 1532 1533 Expression expression = null; 1534 1535 // SEMICOLON or expression. 1536 switch (type) { 1537 case RBRACE: 1538 case SEMICOLON: 1539 case EOL: 1540 case EOF: 1541 break; 1542 1543 default: 1544 expression = expression(); 1545 break; 1546 } 1547 1548 endOfLine(); 1549 1550 // Construct and add RETURN node. 1551 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); 1552 } 1553 1554 /** 1555 * YieldStatement : 1556 * yield Expression? ; // [no LineTerminator here] 1557 * 1558 * JavaScript 1.8 1559 * 1560 * Parse YIELD statement. 1561 */ 1562 private void yieldStatement() { 1563 // Capture YIELD token. 1564 final int yieldLine = line; 1565 final long yieldToken = token; 1566 // YIELD tested in caller. 1567 nextOrEOL(); 1568 1569 Expression expression = null; 1570 1571 // SEMICOLON or expression. 1572 switch (type) { 1573 case RBRACE: 1574 case SEMICOLON: 1575 case EOL: 1576 case EOF: 1577 break; 1578 1579 default: 1580 expression = expression(); 1581 break; 1582 } 1583 1584 endOfLine(); 1585 1586 // Construct and add YIELD node. 1587 appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); 1588 } 1589 1590 /** 1591 * WithStatement : 1592 * with ( Expression ) Statement 1593 * 1594 * See 12.10 1595 * 1596 * Parse WITH statement. 1597 */ 1598 private void withStatement() { 1599 // Capture WITH token. 1600 final int withLine = line; 1601 final long withToken = token; 1602 // WITH tested in caller. 1603 next(); 1604 1605 // ECMA 12.10.1 strict mode restrictions 1606 if (isStrictMode) { 1607 throw error(AbstractParser.message("strict.no.with"), withToken); 1608 } 1609 1610 Expression expression = null; 1611 Block body = null; 1612 try { 1613 expect(LPAREN); 1614 expression = expression(); 1615 expect(RPAREN); 1616 body = getStatement(); 1617 } finally { 1618 appendStatement(new WithNode(withLine, withToken, finish, expression, body)); 1619 } 1620 1621 } 1622 1623 /** 1624 * SwitchStatement : 1625 * switch ( Expression ) CaseBlock 1626 * 1627 * CaseBlock : 1628 * { CaseClauses? } 1629 * { CaseClauses? DefaultClause CaseClauses } 1630 * 1631 * CaseClauses : 1632 * CaseClause 1633 * CaseClauses CaseClause 1634 * 1635 * CaseClause : 1636 * case Expression : StatementList? 1637 * 1638 * DefaultClause : 1639 * default : StatementList? 1640 * 1641 * See 12.11 1642 * 1643 * Parse SWITCH statement. 1644 */ 1645 private void switchStatement() { 1646 final int switchLine = line; 1647 final long switchToken = token; 1648 // SWITCH tested in caller. 1649 next(); 1650 1651 // Create and add switch statement. 1652 final ParserContextSwitchNode switchNode= new ParserContextSwitchNode(); 1653 lc.push(switchNode); 1654 1655 CaseNode defaultCase = null; 1656 // Prepare to accumulate cases. 1657 final List<CaseNode> cases = new ArrayList<>(); 1658 1659 Expression expression = null; 1660 1661 try { 1662 expect(LPAREN); 1663 expression = expression(); 1664 expect(RPAREN); 1665 1666 expect(LBRACE); 1667 1668 1669 while (type != RBRACE) { 1670 // Prepare for next case. 1671 Expression caseExpression = null; 1672 final long caseToken = token; 1673 1674 switch (type) { 1675 case CASE: 1676 next(); 1677 caseExpression = expression(); 1678 break; 1679 1680 case DEFAULT: 1681 if (defaultCase != null) { 1682 throw error(AbstractParser.message("duplicate.default.in.switch")); 1683 } 1684 next(); 1685 break; 1686 1687 default: 1688 // Force an error. 1689 expect(CASE); 1690 break; 1691 } 1692 1693 expect(COLON); 1694 1695 // Get CASE body. 1696 final Block statements = getBlock(false); 1697 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); 1698 1699 if (caseExpression == null) { 1700 defaultCase = caseNode; 1701 } 1702 1703 cases.add(caseNode); 1704 } 1705 1706 next(); 1707 } finally { 1708 lc.pop(switchNode); 1709 appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase)); 1710 } 1711 } 1712 1713 /** 1714 * LabelledStatement : 1715 * Identifier : Statement 1716 * 1717 * See 12.12 1718 * 1719 * Parse label statement. 1720 */ 1721 private void labelStatement() { 1722 // Capture label token. 1723 final long labelToken = token; 1724 // Get label ident. 1725 final IdentNode ident = getIdent(); 1726 1727 expect(COLON); 1728 1729 if (lc.findLabel(ident.getName()) != null) { 1730 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 1731 } 1732 1733 final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName()); 1734 Block body = null; 1735 try { 1736 lc.push(labelNode); 1737 body = getStatement(); 1738 } finally { 1739 assert lc.peek() instanceof ParserContextLabelNode; 1740 lc.pop(labelNode); 1741 if (ident != null){ 1742 appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body)); 1743 } 1744 } 1745 } 1746 1747 /** 1748 * ThrowStatement : 1749 * throw Expression ; // [no LineTerminator here] 1750 * 1751 * See 12.13 1752 * 1753 * Parse throw statement. 1754 */ 1755 private void throwStatement() { 1756 // Capture THROW token. 1757 final int throwLine = line; 1758 final long throwToken = token; 1759 // THROW tested in caller. 1760 nextOrEOL(); 1761 1762 Expression expression = null; 1763 1764 // SEMICOLON or expression. 1765 switch (type) { 1766 case RBRACE: 1767 case SEMICOLON: 1768 case EOL: 1769 break; 1770 1771 default: 1772 expression = expression(); 1773 break; 1774 } 1775 1776 if (expression == null) { 1777 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 1778 } 1779 1780 endOfLine(); 1781 1782 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); 1783 } 1784 1785 /** 1786 * TryStatement : 1787 * try Block Catch 1788 * try Block Finally 1789 * try Block Catch Finally 1790 * 1791 * Catch : 1792 * catch( Identifier if Expression ) Block 1793 * catch( Identifier ) Block 1794 * 1795 * Finally : 1796 * finally Block 1797 * 1798 * See 12.14 1799 * 1800 * Parse TRY statement. 1801 */ 1802 private void tryStatement() { 1803 // Capture TRY token. 1804 final int tryLine = line; 1805 final long tryToken = token; 1806 // TRY tested in caller. 1807 next(); 1808 1809 // Container block needed to act as target for labeled break statements 1810 final int startLine = line; 1811 final ParserContextBlockNode outer = newBlock(); 1812 // Create try. 1813 1814 try { 1815 final Block tryBody = getBlock(true); 1816 final List<Block> catchBlocks = new ArrayList<>(); 1817 1818 while (type == CATCH) { 1819 final int catchLine = line; 1820 final long catchToken = token; 1821 next(); 1822 expect(LPAREN); 1823 final IdentNode exception = getIdent(); 1824 1825 // ECMA 12.4.1 strict mode restrictions 1826 verifyStrictIdent(exception, "catch argument"); 1827 1828 // Nashorn extension: catch clause can have optional 1829 // condition. So, a single try can have more than one 1830 // catch clause each with it's own condition. 1831 final Expression ifExpression; 1832 if (!env._no_syntax_extensions && type == IF) { 1833 next(); 1834 // Get the exception condition. 1835 ifExpression = expression(); 1836 } else { 1837 ifExpression = null; 1838 } 1839 1840 expect(RPAREN); 1841 1842 final ParserContextBlockNode catchBlock = newBlock(); 1843 try { 1844 // Get CATCH body. 1845 final Block catchBody = getBlock(true); 1846 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); 1847 appendStatement(catchNode); 1848 } finally { 1849 restoreBlock(catchBlock); 1850 catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags(), catchBlock.getStatements())); 1851 } 1852 1853 // If unconditional catch then should to be the end. 1854 if (ifExpression == null) { 1855 break; 1856 } 1857 } 1858 1859 // Prepare to capture finally statement. 1860 Block finallyStatements = null; 1861 1862 if (type == FINALLY) { 1863 next(); 1864 finallyStatements = getBlock(true); 1865 } 1866 1867 // Need at least one catch or a finally. 1868 if (catchBlocks.isEmpty() && finallyStatements == null) { 1869 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 1870 } 1871 1872 final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements); 1873 // Add try. 1874 assert lc.peek() == outer; 1875 appendStatement(tryNode); 1876 } finally { 1877 restoreBlock(outer); 1878 } 1879 1880 appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags(), outer.getStatements()))); 1881 } 1882 1883 /** 1884 * DebuggerStatement : 1885 * debugger ; 1886 * 1887 * See 12.15 1888 * 1889 * Parse debugger statement. 1890 */ 1891 private void debuggerStatement() { 1892 // Capture DEBUGGER token. 1893 final int debuggerLine = line; 1894 final long debuggerToken = token; 1895 // DEBUGGER tested in caller. 1896 next(); 1897 endOfLine(); 1898 appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, Collections.<Expression>emptyList()))); 1899 } 1900 1901 /** 1902 * PrimaryExpression : 1903 * this 1904 * Identifier 1905 * Literal 1906 * ArrayLiteral 1907 * ObjectLiteral 1908 * ( Expression ) 1909 * 1910 * See 11.1 1911 * 1912 * Parse primary expression. 1913 * @return Expression node. 1914 */ 1915 @SuppressWarnings("fallthrough") 1916 private Expression primaryExpression() { 1917 // Capture first token. 1918 final int primaryLine = line; 1919 final long primaryToken = token; 1920 1921 switch (type) { 1922 case THIS: 1923 final String name = type.getName(); 1924 next(); 1925 lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS); 1926 return new IdentNode(primaryToken, finish, name); 1927 case IDENT: 1928 final IdentNode ident = getIdent(); 1929 if (ident == null) { 1930 break; 1931 } 1932 detectSpecialProperty(ident); 1933 return ident; 1934 case OCTAL: 1935 if (isStrictMode) { 1936 throw error(AbstractParser.message("strict.no.octal"), token); 1937 } 1938 case STRING: 1939 case ESCSTRING: 1940 case DECIMAL: 1941 case HEXADECIMAL: 1942 case FLOATING: 1943 case REGEX: 1944 case XML: 1945 return getLiteral(); 1946 case EXECSTRING: 1947 return execString(primaryLine, primaryToken); 1948 case FALSE: 1949 next(); 1950 return LiteralNode.newInstance(primaryToken, finish, false); 1951 case TRUE: 1952 next(); 1953 return LiteralNode.newInstance(primaryToken, finish, true); 1954 case NULL: 1955 next(); 1956 return LiteralNode.newInstance(primaryToken, finish); 1957 case LBRACKET: 1958 return arrayLiteral(); 1959 case LBRACE: 1960 return objectLiteral(); 1961 case LPAREN: 1962 next(); 1963 1964 final Expression expression = expression(); 1965 1966 expect(RPAREN); 1967 1968 return expression; 1969 1970 default: 1971 // In this context some operator tokens mark the start of a literal. 1972 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 1973 next(); 1974 return getLiteral(); 1975 } 1976 if (isNonStrictModeIdent()) { 1977 return getIdent(); 1978 } 1979 break; 1980 } 1981 1982 return null; 1983 } 1984 1985 /** 1986 * Convert execString to a call to $EXEC. 1987 * 1988 * @param primaryToken Original string token. 1989 * @return callNode to $EXEC. 1990 */ 1991 CallNode execString(final int primaryLine, final long primaryToken) { 1992 // Synthesize an ident to call $EXEC. 1993 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 1994 // Skip over EXECSTRING. 1995 next(); 1996 // Set up argument list for call. 1997 // Skip beginning of edit string expression. 1998 expect(LBRACE); 1999 // Add the following expression to arguments. 2000 final List<Expression> arguments = Collections.singletonList(expression()); 2001 // Skip ending of edit string expression. 2002 expect(RBRACE); 2003 2004 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2005 } 2006 2007 /** 2008 * ArrayLiteral : 2009 * [ Elision? ] 2010 * [ ElementList ] 2011 * [ ElementList , Elision? ] 2012 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2013 * 2014 * ElementList : Elision? AssignmentExpression 2015 * ElementList , Elision? AssignmentExpression 2016 * 2017 * Elision : 2018 * , 2019 * Elision , 2020 * 2021 * See 12.1.4 2022 * JavaScript 1.8 2023 * 2024 * Parse array literal. 2025 * @return Expression node. 2026 */ 2027 private LiteralNode<Expression[]> arrayLiteral() { 2028 // Capture LBRACKET token. 2029 final long arrayToken = token; 2030 // LBRACKET tested in caller. 2031 next(); 2032 2033 // Prepare to accummulating elements. 2034 final List<Expression> elements = new ArrayList<>(); 2035 // Track elisions. 2036 boolean elision = true; 2037loop: 2038 while (true) { 2039 switch (type) { 2040 case RBRACKET: 2041 next(); 2042 2043 break loop; 2044 2045 case COMMARIGHT: 2046 next(); 2047 2048 // If no prior expression 2049 if (elision) { 2050 elements.add(null); 2051 } 2052 2053 elision = true; 2054 2055 break; 2056 2057 default: 2058 if (!elision) { 2059 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2060 } 2061 // Add expression element. 2062 final Expression expression = assignmentExpression(false); 2063 2064 if (expression != null) { 2065 elements.add(expression); 2066 } else { 2067 expect(RBRACKET); 2068 } 2069 2070 elision = false; 2071 break; 2072 } 2073 } 2074 2075 return LiteralNode.newInstance(arrayToken, finish, elements); 2076 } 2077 2078 /** 2079 * ObjectLiteral : 2080 * { } 2081 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2082 * 2083 * PropertyNameAndValueList : 2084 * PropertyAssignment 2085 * PropertyNameAndValueList , PropertyAssignment 2086 * 2087 * See 11.1.5 2088 * 2089 * Parse an object literal. 2090 * @return Expression node. 2091 */ 2092 private ObjectNode objectLiteral() { 2093 // Capture LBRACE token. 2094 final long objectToken = token; 2095 // LBRACE tested in caller. 2096 next(); 2097 2098 // Object context. 2099 // Prepare to accumulate elements. 2100 final List<PropertyNode> elements = new ArrayList<>(); 2101 final Map<String, Integer> map = new HashMap<>(); 2102 2103 // Create a block for the object literal. 2104 boolean commaSeen = true; 2105loop: 2106 while (true) { 2107 switch (type) { 2108 case RBRACE: 2109 next(); 2110 break loop; 2111 2112 case COMMARIGHT: 2113 if (commaSeen) { 2114 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2115 } 2116 next(); 2117 commaSeen = true; 2118 break; 2119 2120 default: 2121 if (!commaSeen) { 2122 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2123 } 2124 2125 commaSeen = false; 2126 // Get and add the next property. 2127 final PropertyNode property = propertyAssignment(); 2128 final String key = property.getKeyName(); 2129 final Integer existing = map.get(key); 2130 2131 if (existing == null) { 2132 map.put(key, elements.size()); 2133 elements.add(property); 2134 break; 2135 } 2136 2137 final PropertyNode existingProperty = elements.get(existing); 2138 2139 // ECMA section 11.1.5 Object Initialiser 2140 // point # 4 on property assignment production 2141 final Expression value = property.getValue(); 2142 final FunctionNode getter = property.getGetter(); 2143 final FunctionNode setter = property.getSetter(); 2144 2145 final Expression prevValue = existingProperty.getValue(); 2146 final FunctionNode prevGetter = existingProperty.getGetter(); 2147 final FunctionNode prevSetter = existingProperty.getSetter(); 2148 2149 // ECMA 11.1.5 strict mode restrictions 2150 if (isStrictMode && value != null && prevValue != null) { 2151 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2152 } 2153 2154 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2155 final boolean isAccessor = getter != null || setter != null; 2156 2157 // data property redefined as accessor property 2158 if (prevValue != null && isAccessor) { 2159 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2160 } 2161 2162 // accessor property redefined as data 2163 if (isPrevAccessor && value != null) { 2164 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2165 } 2166 2167 if (isAccessor && isPrevAccessor) { 2168 if (getter != null && prevGetter != null || 2169 setter != null && prevSetter != null) { 2170 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2171 } 2172 } 2173 2174 if (value != null) { 2175 elements.add(property); 2176 } else if (getter != null) { 2177 elements.set(existing, existingProperty.setGetter(getter)); 2178 } else if (setter != null) { 2179 elements.set(existing, existingProperty.setSetter(setter)); 2180 } 2181 break; 2182 } 2183 } 2184 2185 return new ObjectNode(objectToken, finish, elements); 2186 } 2187 2188 /** 2189 * PropertyName : 2190 * IdentifierName 2191 * StringLiteral 2192 * NumericLiteral 2193 * 2194 * See 11.1.5 2195 * 2196 * @return PropertyName node 2197 */ 2198 @SuppressWarnings("fallthrough") 2199 private PropertyKey propertyName() { 2200 switch (type) { 2201 case IDENT: 2202 return getIdent().setIsPropertyName(); 2203 case OCTAL: 2204 if (isStrictMode) { 2205 throw error(AbstractParser.message("strict.no.octal"), token); 2206 } 2207 case STRING: 2208 case ESCSTRING: 2209 case DECIMAL: 2210 case HEXADECIMAL: 2211 case FLOATING: 2212 return getLiteral(); 2213 default: 2214 return getIdentifierName().setIsPropertyName(); 2215 } 2216 } 2217 2218 /** 2219 * PropertyAssignment : 2220 * PropertyName : AssignmentExpression 2221 * get PropertyName ( ) { FunctionBody } 2222 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2223 * 2224 * PropertySetParameterList : 2225 * Identifier 2226 * 2227 * PropertyName : 2228 * IdentifierName 2229 * StringLiteral 2230 * NumericLiteral 2231 * 2232 * See 11.1.5 2233 * 2234 * Parse an object literal property. 2235 * @return Property or reference node. 2236 */ 2237 private PropertyNode propertyAssignment() { 2238 // Capture firstToken. 2239 final long propertyToken = token; 2240 final int functionLine = line; 2241 2242 PropertyKey propertyName; 2243 2244 if (type == IDENT) { 2245 // Get IDENT. 2246 final String ident = (String)expectValue(IDENT); 2247 2248 if (type != COLON) { 2249 final long getSetToken = propertyToken; 2250 2251 switch (ident) { 2252 case "get": 2253 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 2254 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); 2255 2256 case "set": 2257 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 2258 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); 2259 default: 2260 break; 2261 } 2262 } 2263 2264 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 2265 } else { 2266 propertyName = propertyName(); 2267 } 2268 2269 expect(COLON); 2270 2271 defaultNames.push(propertyName); 2272 try { 2273 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2274 } finally { 2275 defaultNames.pop(); 2276 } 2277 } 2278 2279 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 2280 final PropertyKey getIdent = propertyName(); 2281 final String getterName = getIdent.getPropertyName(); 2282 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2283 expect(LPAREN); 2284 expect(RPAREN); 2285 2286 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); 2287 lc.push(functionNode); 2288 2289 final Block functionBody = functionBody(functionNode); 2290 2291 lc.pop(functionNode); 2292 2293 final FunctionNode function = createFunctionNode( 2294 functionNode, 2295 getSetToken, 2296 getNameNode, 2297 Collections.<IdentNode>emptyList(), 2298 FunctionNode.Kind.GETTER, 2299 functionLine, 2300 functionBody); 2301 2302 return new PropertyFunction(getIdent, function); 2303 } 2304 2305 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 2306 final PropertyKey setIdent = propertyName(); 2307 final String setterName = setIdent.getPropertyName(); 2308 final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2309 expect(LPAREN); 2310 // be sloppy and allow missing setter parameter even though 2311 // spec does not permit it! 2312 final IdentNode argIdent; 2313 if (type == IDENT || isNonStrictModeIdent()) { 2314 argIdent = getIdent(); 2315 verifyStrictIdent(argIdent, "setter argument"); 2316 } else { 2317 argIdent = null; 2318 } 2319 expect(RPAREN); 2320 final List<IdentNode> parameters = new ArrayList<>(); 2321 if (argIdent != null) { 2322 parameters.add(argIdent); 2323 } 2324 2325 2326 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); 2327 lc.push(functionNode); 2328 2329 final Block functionBody = functionBody(functionNode); 2330 2331 lc.pop(functionNode); 2332 2333 final FunctionNode function = createFunctionNode( 2334 functionNode, 2335 getSetToken, 2336 setNameNode, 2337 parameters, 2338 FunctionNode.Kind.SETTER, 2339 functionLine, 2340 functionBody); 2341 2342 return new PropertyFunction(setIdent, function); 2343 } 2344 2345 private static class PropertyFunction { 2346 final PropertyKey ident; 2347 final FunctionNode functionNode; 2348 2349 PropertyFunction(final PropertyKey ident, final FunctionNode function) { 2350 this.ident = ident; 2351 this.functionNode = function; 2352 } 2353 } 2354 2355 /** 2356 * LeftHandSideExpression : 2357 * NewExpression 2358 * CallExpression 2359 * 2360 * CallExpression : 2361 * MemberExpression Arguments 2362 * CallExpression Arguments 2363 * CallExpression [ Expression ] 2364 * CallExpression . IdentifierName 2365 * 2366 * See 11.2 2367 * 2368 * Parse left hand side expression. 2369 * @return Expression node. 2370 */ 2371 private Expression leftHandSideExpression() { 2372 int callLine = line; 2373 long callToken = token; 2374 2375 Expression lhs = memberExpression(); 2376 2377 if (type == LPAREN) { 2378 final List<Expression> arguments = optimizeList(argumentList()); 2379 2380 // Catch special functions. 2381 if (lhs instanceof IdentNode) { 2382 detectSpecialFunction((IdentNode)lhs); 2383 } 2384 2385 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2386 } 2387 2388loop: 2389 while (true) { 2390 // Capture token. 2391 callLine = line; 2392 callToken = token; 2393 2394 switch (type) { 2395 case LPAREN: 2396 // Get NEW or FUNCTION arguments. 2397 final List<Expression> arguments = optimizeList(argumentList()); 2398 2399 // Create call node. 2400 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2401 2402 break; 2403 2404 case LBRACKET: 2405 next(); 2406 2407 // Get array index. 2408 final Expression rhs = expression(); 2409 2410 expect(RBRACKET); 2411 2412 // Create indexing node. 2413 lhs = new IndexNode(callToken, finish, lhs, rhs); 2414 2415 break; 2416 2417 case PERIOD: 2418 next(); 2419 2420 final IdentNode property = getIdentifierName(); 2421 2422 // Create property access node. 2423 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2424 2425 break; 2426 2427 default: 2428 break loop; 2429 } 2430 } 2431 2432 return lhs; 2433 } 2434 2435 /** 2436 * NewExpression : 2437 * MemberExpression 2438 * new NewExpression 2439 * 2440 * See 11.2 2441 * 2442 * Parse new expression. 2443 * @return Expression node. 2444 */ 2445 private Expression newExpression() { 2446 final long newToken = token; 2447 // NEW is tested in caller. 2448 next(); 2449 2450 // Get function base. 2451 final int callLine = line; 2452 final Expression constructor = memberExpression(); 2453 if (constructor == null) { 2454 return null; 2455 } 2456 // Get arguments. 2457 ArrayList<Expression> arguments; 2458 2459 // Allow for missing arguments. 2460 if (type == LPAREN) { 2461 arguments = argumentList(); 2462 } else { 2463 arguments = new ArrayList<>(); 2464 } 2465 2466 // Nashorn extension: This is to support the following interface implementation 2467 // syntax: 2468 // 2469 // var r = new java.lang.Runnable() { 2470 // run: function() { println("run"); } 2471 // }; 2472 // 2473 // The object literal following the "new Constructor()" expresssion 2474 // is passed as an additional (last) argument to the constructor. 2475 if (!env._no_syntax_extensions && type == LBRACE) { 2476 arguments.add(objectLiteral()); 2477 } 2478 2479 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 2480 2481 return new UnaryNode(newToken, callNode); 2482 } 2483 2484 /** 2485 * MemberExpression : 2486 * PrimaryExpression 2487 * FunctionExpression 2488 * MemberExpression [ Expression ] 2489 * MemberExpression . IdentifierName 2490 * new MemberExpression Arguments 2491 * 2492 * See 11.2 2493 * 2494 * Parse member expression. 2495 * @return Expression node. 2496 */ 2497 private Expression memberExpression() { 2498 // Prepare to build operation. 2499 Expression lhs; 2500 2501 switch (type) { 2502 case NEW: 2503 // Get new expression. 2504 lhs = newExpression(); 2505 break; 2506 2507 case FUNCTION: 2508 // Get function expression. 2509 lhs = functionExpression(false, false); 2510 break; 2511 2512 default: 2513 // Get primary expression. 2514 lhs = primaryExpression(); 2515 break; 2516 } 2517 2518loop: 2519 while (true) { 2520 // Capture token. 2521 final long callToken = token; 2522 2523 switch (type) { 2524 case LBRACKET: 2525 next(); 2526 2527 // Get array index. 2528 final Expression index = expression(); 2529 2530 expect(RBRACKET); 2531 2532 // Create indexing node. 2533 lhs = new IndexNode(callToken, finish, lhs, index); 2534 2535 break; 2536 2537 case PERIOD: 2538 if (lhs == null) { 2539 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2540 } 2541 2542 next(); 2543 2544 final IdentNode property = getIdentifierName(); 2545 2546 // Create property access node. 2547 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2548 2549 break; 2550 2551 default: 2552 break loop; 2553 } 2554 } 2555 2556 return lhs; 2557 } 2558 2559 /** 2560 * Arguments : 2561 * ( ) 2562 * ( ArgumentList ) 2563 * 2564 * ArgumentList : 2565 * AssignmentExpression 2566 * ArgumentList , AssignmentExpression 2567 * 2568 * See 11.2 2569 * 2570 * Parse function call arguments. 2571 * @return Argument list. 2572 */ 2573 private ArrayList<Expression> argumentList() { 2574 // Prepare to accumulate list of arguments. 2575 final ArrayList<Expression> nodeList = new ArrayList<>(); 2576 // LPAREN tested in caller. 2577 next(); 2578 2579 // Track commas. 2580 boolean first = true; 2581 2582 while (type != RPAREN) { 2583 // Comma prior to every argument except the first. 2584 if (!first) { 2585 expect(COMMARIGHT); 2586 } else { 2587 first = false; 2588 } 2589 2590 // Get argument expression. 2591 nodeList.add(assignmentExpression(false)); 2592 } 2593 2594 expect(RPAREN); 2595 return nodeList; 2596 } 2597 2598 private static <T> List<T> optimizeList(final ArrayList<T> list) { 2599 switch(list.size()) { 2600 case 0: { 2601 return Collections.emptyList(); 2602 } 2603 case 1: { 2604 return Collections.singletonList(list.get(0)); 2605 } 2606 default: { 2607 list.trimToSize(); 2608 return list; 2609 } 2610 } 2611 } 2612 2613 /** 2614 * FunctionDeclaration : 2615 * function Identifier ( FormalParameterList? ) { FunctionBody } 2616 * 2617 * FunctionExpression : 2618 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2619 * 2620 * See 13 2621 * 2622 * Parse function declaration. 2623 * @param isStatement True if for is a statement. 2624 * 2625 * @return Expression node. 2626 */ 2627 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2628 final long functionToken = token; 2629 final int functionLine = line; 2630 // FUNCTION is tested in caller. 2631 next(); 2632 2633 IdentNode name = null; 2634 2635 if (type == IDENT || isNonStrictModeIdent()) { 2636 name = getIdent(); 2637 verifyStrictIdent(name, "function name"); 2638 } else if (isStatement) { 2639 // Nashorn extension: anonymous function statements 2640 if (env._no_syntax_extensions) { 2641 expect(IDENT); 2642 } 2643 } 2644 2645 // name is null, generate anonymous name 2646 boolean isAnonymous = false; 2647 if (name == null) { 2648 final String tmpName = getDefaultValidFunctionName(functionLine); 2649 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2650 isAnonymous = true; 2651 } 2652 2653 expect(LPAREN); 2654 final List<IdentNode> parameters = formalParameterList(); 2655 expect(RPAREN); 2656 2657 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); 2658 lc.push(functionNode); 2659 Block functionBody = null; 2660 try{ 2661 functionBody = functionBody(functionNode); 2662 } finally { 2663 lc.pop(functionNode); 2664 } 2665 2666 if (isStatement) { 2667 if (topLevel || useBlockScope()) { 2668 functionNode.setFlag(FunctionNode.IS_DECLARED); 2669 } else if (isStrictMode) { 2670 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2671 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2672 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2673 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2674 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2675 } 2676 if (isArguments(name)) { 2677 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); 2678 } 2679 } 2680 2681 if (isAnonymous) { 2682 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 2683 } 2684 2685 final int arity = parameters.size(); 2686 2687 final boolean strict = functionNode.isStrict(); 2688 if (arity > 1) { 2689 final HashSet<String> parametersSet = new HashSet<>(arity); 2690 2691 for (int i = arity - 1; i >= 0; i--) { 2692 final IdentNode parameter = parameters.get(i); 2693 String parameterName = parameter.getName(); 2694 2695 if (isArguments(parameterName)) { 2696 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2697 } 2698 2699 if (parametersSet.contains(parameterName)) { 2700 // redefinition of parameter name 2701 if (strict) { 2702 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2703 } 2704 // rename in non-strict mode 2705 parameterName = functionNode.uniqueName(parameterName); 2706 final long parameterToken = parameter.getToken(); 2707 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2708 } 2709 2710 parametersSet.add(parameterName); 2711 } 2712 } else if (arity == 1) { 2713 if (isArguments(parameters.get(0))) { 2714 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2715 } 2716 } 2717 2718 final FunctionNode function = createFunctionNode( 2719 functionNode, 2720 functionToken, 2721 name, 2722 parameters, 2723 FunctionNode.Kind.NORMAL, 2724 functionLine, 2725 functionBody); 2726 2727 if (isStatement) { 2728 int varFlags = VarNode.IS_STATEMENT; 2729 if (!topLevel && useBlockScope()) { 2730 // mark ES6 block functions as lexically scoped 2731 varFlags |= VarNode.IS_LET; 2732 } 2733 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); 2734 if (topLevel) { 2735 functionDeclarations.add(varNode); 2736 } else if (useBlockScope()) { 2737 prependStatement(varNode); // Hoist to beginning of current block 2738 } else { 2739 appendStatement(varNode); 2740 } 2741 } 2742 2743 return function; 2744 } 2745 2746 private String getDefaultValidFunctionName(final int functionLine) { 2747 final String defaultFunctionName = getDefaultFunctionName(); 2748 return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2749 } 2750 2751 private static boolean isValidIdentifier(final String name) { 2752 if(name == null || name.isEmpty()) { 2753 return false; 2754 } 2755 if(!Character.isJavaIdentifierStart(name.charAt(0))) { 2756 return false; 2757 } 2758 for(int i = 1; i < name.length(); ++i) { 2759 if(!Character.isJavaIdentifierPart(name.charAt(i))) { 2760 return false; 2761 } 2762 } 2763 return true; 2764 } 2765 2766 private String getDefaultFunctionName() { 2767 if(!defaultNames.isEmpty()) { 2768 final Object nameExpr = defaultNames.peek(); 2769 if(nameExpr instanceof PropertyKey) { 2770 markDefaultNameUsed(); 2771 return ((PropertyKey)nameExpr).getPropertyName(); 2772 } else if(nameExpr instanceof AccessNode) { 2773 markDefaultNameUsed(); 2774 return ((AccessNode)nameExpr).getProperty(); 2775 } 2776 } 2777 return null; 2778 } 2779 2780 private void markDefaultNameUsed() { 2781 defaultNames.pop(); 2782 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 2783 // from. Can't be null 2784 defaultNames.push(""); 2785 } 2786 2787 /** 2788 * FormalParameterList : 2789 * Identifier 2790 * FormalParameterList , Identifier 2791 * 2792 * See 13 2793 * 2794 * Parse function parameter list. 2795 * @return List of parameter nodes. 2796 */ 2797 private List<IdentNode> formalParameterList() { 2798 return formalParameterList(RPAREN); 2799 } 2800 2801 /** 2802 * Same as the other method of the same name - except that the end 2803 * token type expected is passed as argument to this method. 2804 * 2805 * FormalParameterList : 2806 * Identifier 2807 * FormalParameterList , Identifier 2808 * 2809 * See 13 2810 * 2811 * Parse function parameter list. 2812 * @return List of parameter nodes. 2813 */ 2814 private List<IdentNode> formalParameterList(final TokenType endType) { 2815 // Prepare to gather parameters. 2816 final ArrayList<IdentNode> parameters = new ArrayList<>(); 2817 // Track commas. 2818 boolean first = true; 2819 2820 while (type != endType) { 2821 // Comma prior to every argument except the first. 2822 if (!first) { 2823 expect(COMMARIGHT); 2824 } else { 2825 first = false; 2826 } 2827 2828 // Get and add parameter. 2829 final IdentNode ident = getIdent(); 2830 2831 // ECMA 13.1 strict mode restrictions 2832 verifyStrictIdent(ident, "function parameter"); 2833 2834 parameters.add(ident); 2835 } 2836 2837 parameters.trimToSize(); 2838 return parameters; 2839 } 2840 2841 /** 2842 * FunctionBody : 2843 * SourceElements? 2844 * 2845 * See 13 2846 * 2847 * Parse function body. 2848 * @return function node (body.) 2849 */ 2850 private Block functionBody(final ParserContextFunctionNode functionNode) { 2851 long lastToken = 0L; 2852 ParserContextBlockNode body = null; 2853 final long bodyToken = token; 2854 Block functionBody; 2855 int bodyFinish = 0; 2856 2857 2858 final boolean parseBody; 2859 Object endParserState = null; 2860 try { 2861 // Create a new function block. 2862 body = newBlock(); 2863 assert functionNode != null; 2864 final int functionId = functionNode.getId(); 2865 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 2866 // Nashorn extension: expression closures 2867 if (!env._no_syntax_extensions && type != LBRACE) { 2868 /* 2869 * Example: 2870 * 2871 * function square(x) x * x; 2872 * print(square(3)); 2873 */ 2874 2875 // just expression as function body 2876 final Expression expr = assignmentExpression(true); 2877 lastToken = previousToken; 2878 functionNode.setLastToken(previousToken); 2879 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2880 // EOL uses length field to store the line number 2881 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 2882 // Only create the return node if we aren't skipping nested functions. Note that we aren't 2883 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 2884 // they don't end with a single well known token, so it'd be very hard to get correctly (see 2885 // the note below for reasoning on skipping happening before instead of after RBRACE for 2886 // details). 2887 if (parseBody) { 2888 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 2889 appendStatement(returnNode); 2890 } 2891 } else { 2892 expectDontAdvance(LBRACE); 2893 if (parseBody || !skipFunctionBody(functionNode)) { 2894 next(); 2895 // Gather the function elements. 2896 final List<Statement> prevFunctionDecls = functionDeclarations; 2897 functionDeclarations = new ArrayList<>(); 2898 try { 2899 sourceElements(false); 2900 addFunctionDeclarations(functionNode); 2901 } finally { 2902 functionDeclarations = prevFunctionDecls; 2903 } 2904 2905 lastToken = token; 2906 if (parseBody) { 2907 // Since the lexer can read ahead and lexify some number of tokens in advance and have 2908 // them buffered in the TokenStream, we need to produce a lexer state as it was just 2909 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 2910 // ahead) state. 2911 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 2912 2913 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 2914 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 2915 // state after it. The reason is that RBRACE is a well-known token that we can expect and 2916 // will never involve us getting into a weird lexer state, and as such is a great reparse 2917 // point. Typical example of a weird lexer state after RBRACE would be: 2918 // function this_is_skipped() { ... } "use strict"; 2919 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 2920 // of compensating for the possibility of a string literal (or similar) after RBRACE, 2921 // we'll rather just restart parsing from this well-known, friendly token instead. 2922 } 2923 } 2924 bodyFinish = finish; 2925 functionNode.setLastToken(token); 2926 expect(RBRACE); 2927 } 2928 } finally { 2929 restoreBlock(body); 2930 } 2931 2932 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 2933 2934 if (parseBody) { 2935 functionNode.setEndParserState(endParserState); 2936 } else if (!body.getStatements().isEmpty()){ 2937 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 2938 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 2939 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 2940 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 2941 // nested bodies early if we were supposed to skip 'em. 2942 body.setStatements(Collections.<Statement>emptyList()); 2943 } 2944 2945 if (reparsedFunction != null) { 2946 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 2947 // eagerly parsed the code. We're doing it because some flags would be set based on the 2948 // content of the function, or even content of its nested functions, most of which are normally 2949 // skipped during an on-demand compilation. 2950 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2951 if (data != null) { 2952 // Data can be null if when we originally parsed the file, we removed the function declaration 2953 // as it was dead code. 2954 functionNode.setFlag(data.getFunctionFlags()); 2955 // This compensates for missing markEval() in case the function contains an inner function 2956 // that contains eval(), that now we didn't discover since we skipped the inner function. 2957 if (functionNode.hasNestedEval()) { 2958 assert functionNode.hasScopeBlock(); 2959 body.setFlag(Block.NEEDS_SCOPE); 2960 } 2961 } 2962 } 2963 functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements()); 2964 return functionBody; 2965 } 2966 2967 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { 2968 if (reparsedFunction == null) { 2969 // Not reparsing, so don't skip any function body. 2970 return false; 2971 } 2972 // Skip to the RBRACE of this function, and continue parsing from there. 2973 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2974 if (data == null) { 2975 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 2976 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 2977 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 2978 return false; 2979 } 2980 final ParserState parserState = (ParserState)data.getEndParserState(); 2981 assert parserState != null; 2982 2983 stream.reset(); 2984 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions); 2985 line = parserState.line; 2986 linePosition = parserState.linePosition; 2987 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 2988 // the RBRACE. 2989 type = SEMICOLON; 2990 k = -1; 2991 next(); 2992 2993 return true; 2994 } 2995 2996 /** 2997 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 2998 * for resuming parsing after skipping a function body. 2999 */ 3000 private static class ParserState implements Serializable { 3001 private final int position; 3002 private final int line; 3003 private final int linePosition; 3004 3005 private static final long serialVersionUID = -2382565130754093694L; 3006 3007 ParserState(final int position, final int line, final int linePosition) { 3008 this.position = position; 3009 this.line = line; 3010 this.linePosition = linePosition; 3011 } 3012 3013 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) { 3014 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true); 3015 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 3016 return newLexer; 3017 } 3018 } 3019 3020 private void printAST(final FunctionNode functionNode) { 3021 if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { 3022 env.getErr().println(new ASTWriter(functionNode)); 3023 } 3024 3025 if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { 3026 env.getErr().println(new PrintVisitor(functionNode, true, false)); 3027 } 3028 } 3029 3030 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { 3031 VarNode lastDecl = null; 3032 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 3033 Statement decl = functionDeclarations.get(i); 3034 if (lastDecl == null && decl instanceof VarNode) { 3035 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 3036 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); 3037 } 3038 prependStatement(decl); 3039 } 3040 } 3041 3042 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 3043 if (earlyError) { 3044 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 3045 } 3046 final ArrayList<Expression> args = new ArrayList<>(); 3047 args.add(lhs); 3048 if (rhs == null) { 3049 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 3050 } else { 3051 args.add(rhs); 3052 } 3053 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 3054 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 3055 } 3056 3057 /* 3058 * parse LHS [a, b, ..., c]. 3059 * 3060 * JavaScript 1.8. 3061 */ 3062 //private Node destructureExpression() { 3063 // return null; 3064 //} 3065 3066 /** 3067 * PostfixExpression : 3068 * LeftHandSideExpression 3069 * LeftHandSideExpression ++ // [no LineTerminator here] 3070 * LeftHandSideExpression -- // [no LineTerminator here] 3071 * 3072 * See 11.3 3073 * 3074 * UnaryExpression : 3075 * PostfixExpression 3076 * delete UnaryExpression 3077 * Node UnaryExpression 3078 * typeof UnaryExpression 3079 * ++ UnaryExpression 3080 * -- UnaryExpression 3081 * + UnaryExpression 3082 * - UnaryExpression 3083 * ~ UnaryExpression 3084 * ! UnaryExpression 3085 * 3086 * See 11.4 3087 * 3088 * Parse unary expression. 3089 * @return Expression node. 3090 */ 3091 private Expression unaryExpression() { 3092 final int unaryLine = line; 3093 final long unaryToken = token; 3094 3095 switch (type) { 3096 case DELETE: { 3097 next(); 3098 final Expression expr = unaryExpression(); 3099 if (expr instanceof BaseNode || expr instanceof IdentNode) { 3100 return new UnaryNode(unaryToken, expr); 3101 } 3102 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 3103 return LiteralNode.newInstance(unaryToken, finish, true); 3104 } 3105 case VOID: 3106 case TYPEOF: 3107 case ADD: 3108 case SUB: 3109 case BIT_NOT: 3110 case NOT: 3111 next(); 3112 final Expression expr = unaryExpression(); 3113 return new UnaryNode(unaryToken, expr); 3114 3115 case INCPREFIX: 3116 case DECPREFIX: 3117 final TokenType opType = type; 3118 next(); 3119 3120 final Expression lhs = leftHandSideExpression(); 3121 // ++, -- without operand.. 3122 if (lhs == null) { 3123 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3124 } 3125 3126 if (!(lhs instanceof AccessNode || 3127 lhs instanceof IndexNode || 3128 lhs instanceof IdentNode)) { 3129 return referenceError(lhs, null, env._early_lvalue_error); 3130 } 3131 3132 if (lhs instanceof IdentNode) { 3133 if (!checkIdentLValue((IdentNode)lhs)) { 3134 return referenceError(lhs, null, false); 3135 } 3136 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3137 } 3138 3139 return incDecExpression(unaryToken, opType, lhs, false); 3140 3141 default: 3142 break; 3143 } 3144 3145 Expression expression = leftHandSideExpression(); 3146 3147 if (last != EOL) { 3148 switch (type) { 3149 case INCPREFIX: 3150 case DECPREFIX: 3151 final TokenType opType = type; 3152 final Expression lhs = expression; 3153 // ++, -- without operand.. 3154 if (lhs == null) { 3155 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3156 } 3157 3158 if (!(lhs instanceof AccessNode || 3159 lhs instanceof IndexNode || 3160 lhs instanceof IdentNode)) { 3161 next(); 3162 return referenceError(lhs, null, env._early_lvalue_error); 3163 } 3164 if (lhs instanceof IdentNode) { 3165 if (!checkIdentLValue((IdentNode)lhs)) { 3166 next(); 3167 return referenceError(lhs, null, false); 3168 } 3169 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3170 } 3171 expression = incDecExpression(token, type, expression, true); 3172 next(); 3173 break; 3174 default: 3175 break; 3176 } 3177 } 3178 3179 if (expression == null) { 3180 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3181 } 3182 3183 return expression; 3184 } 3185 3186 /** 3187 * MultiplicativeExpression : 3188 * UnaryExpression 3189 * MultiplicativeExpression * UnaryExpression 3190 * MultiplicativeExpression / UnaryExpression 3191 * MultiplicativeExpression % UnaryExpression 3192 * 3193 * See 11.5 3194 * 3195 * AdditiveExpression : 3196 * MultiplicativeExpression 3197 * AdditiveExpression + MultiplicativeExpression 3198 * AdditiveExpression - MultiplicativeExpression 3199 * 3200 * See 11.6 3201 * 3202 * ShiftExpression : 3203 * AdditiveExpression 3204 * ShiftExpression << AdditiveExpression 3205 * ShiftExpression >> AdditiveExpression 3206 * ShiftExpression >>> AdditiveExpression 3207 * 3208 * See 11.7 3209 * 3210 * RelationalExpression : 3211 * ShiftExpression 3212 * RelationalExpression < ShiftExpression 3213 * RelationalExpression > ShiftExpression 3214 * RelationalExpression <= ShiftExpression 3215 * RelationalExpression >= ShiftExpression 3216 * RelationalExpression instanceof ShiftExpression 3217 * RelationalExpression in ShiftExpression // if !noIf 3218 * 3219 * See 11.8 3220 * 3221 * RelationalExpression 3222 * EqualityExpression == RelationalExpression 3223 * EqualityExpression != RelationalExpression 3224 * EqualityExpression === RelationalExpression 3225 * EqualityExpression !== RelationalExpression 3226 * 3227 * See 11.9 3228 * 3229 * BitwiseANDExpression : 3230 * EqualityExpression 3231 * BitwiseANDExpression & EqualityExpression 3232 * 3233 * BitwiseXORExpression : 3234 * BitwiseANDExpression 3235 * BitwiseXORExpression ^ BitwiseANDExpression 3236 * 3237 * BitwiseORExpression : 3238 * BitwiseXORExpression 3239 * BitwiseORExpression | BitwiseXORExpression 3240 * 3241 * See 11.10 3242 * 3243 * LogicalANDExpression : 3244 * BitwiseORExpression 3245 * LogicalANDExpression && BitwiseORExpression 3246 * 3247 * LogicalORExpression : 3248 * LogicalANDExpression 3249 * LogicalORExpression || LogicalANDExpression 3250 * 3251 * See 11.11 3252 * 3253 * ConditionalExpression : 3254 * LogicalORExpression 3255 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 3256 * 3257 * See 11.12 3258 * 3259 * AssignmentExpression : 3260 * ConditionalExpression 3261 * LeftHandSideExpression AssignmentOperator AssignmentExpression 3262 * 3263 * AssignmentOperator : 3264 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 3265 * 3266 * See 11.13 3267 * 3268 * Expression : 3269 * AssignmentExpression 3270 * Expression , AssignmentExpression 3271 * 3272 * See 11.14 3273 * 3274 * Parse expression. 3275 * @return Expression node. 3276 */ 3277 private Expression expression() { 3278 // TODO - Destructuring array. 3279 // Include commas in expression parsing. 3280 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 3281 } 3282 3283 private JoinPredecessorExpression joinPredecessorExpression() { 3284 return new JoinPredecessorExpression(expression()); 3285 } 3286 3287 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 3288 // Get the precedence of the next operator. 3289 int precedence = type.getPrecedence(); 3290 Expression lhs = exprLhs; 3291 3292 // While greater precedence. 3293 while (type.isOperator(noIn) && precedence >= minPrecedence) { 3294 // Capture the operator token. 3295 final long op = token; 3296 3297 if (type == TERNARY) { 3298 // Skip operator. 3299 next(); 3300 3301 // Pass expression. Middle expression of a conditional expression can be a "in" 3302 // expression - even in the contexts where "in" is not permitted. 3303 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 3304 3305 expect(COLON); 3306 3307 // Fail expression. 3308 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3309 3310 // Build up node. 3311 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 3312 } else { 3313 // Skip operator. 3314 next(); 3315 3316 // Get the next primary expression. 3317 Expression rhs; 3318 final boolean isAssign = Token.descType(op) == ASSIGN; 3319 if(isAssign) { 3320 defaultNames.push(lhs); 3321 } 3322 try { 3323 rhs = unaryExpression(); 3324 // Get precedence of next operator. 3325 int nextPrecedence = type.getPrecedence(); 3326 3327 // Subtask greater precedence. 3328 while (type.isOperator(noIn) && 3329 (nextPrecedence > precedence || 3330 nextPrecedence == precedence && !type.isLeftAssociative())) { 3331 rhs = expression(rhs, nextPrecedence, noIn); 3332 nextPrecedence = type.getPrecedence(); 3333 } 3334 } finally { 3335 if(isAssign) { 3336 defaultNames.pop(); 3337 } 3338 } 3339 lhs = verifyAssignment(op, lhs, rhs); 3340 } 3341 3342 precedence = type.getPrecedence(); 3343 } 3344 3345 return lhs; 3346 } 3347 3348 private Expression assignmentExpression(final boolean noIn) { 3349 // TODO - Handle decompose. 3350 // Exclude commas in expression parsing. 3351 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3352 } 3353 3354 /** 3355 * Parse an end of line. 3356 */ 3357 private void endOfLine() { 3358 switch (type) { 3359 case SEMICOLON: 3360 case EOL: 3361 next(); 3362 break; 3363 case RPAREN: 3364 case RBRACKET: 3365 case RBRACE: 3366 case EOF: 3367 break; 3368 default: 3369 if (last != EOL) { 3370 expect(SEMICOLON); 3371 } 3372 break; 3373 } 3374 } 3375 3376 @Override 3377 public String toString() { 3378 return "'JavaScript Parsing'"; 3379 } 3380 3381 private static void markEval(final ParserContext lc) { 3382 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 3383 boolean flaggedCurrentFn = false; 3384 while (iter.hasNext()) { 3385 final ParserContextFunctionNode fn = iter.next(); 3386 if (!flaggedCurrentFn) { 3387 fn.setFlag(FunctionNode.HAS_EVAL); 3388 flaggedCurrentFn = true; 3389 } else { 3390 fn.setFlag(FunctionNode.HAS_NESTED_EVAL); 3391 } 3392 final ParserContextBlockNode body = lc.getFunctionBody(fn); 3393 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 3394 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 3395 // this method when the parser skips a nested function. 3396 body.setFlag(Block.NEEDS_SCOPE); 3397 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); 3398 } 3399 } 3400 3401 private void prependStatement(final Statement statement) { 3402 lc.prependStatementToCurrentNode(statement); 3403 } 3404 3405 private void appendStatement(final Statement statement) { 3406 lc.appendStatementToCurrentNode(statement); 3407 } 3408} 3409