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