Parser.java revision 1710:7fb2bf00347b
1/*
2 * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.parser;
27
28import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX;
29import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
30import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM;
31import static jdk.nashorn.internal.parser.TokenType.ARROW;
32import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
33import static jdk.nashorn.internal.parser.TokenType.CASE;
34import static jdk.nashorn.internal.parser.TokenType.CATCH;
35import static jdk.nashorn.internal.parser.TokenType.CLASS;
36import static jdk.nashorn.internal.parser.TokenType.COLON;
37import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
38import static jdk.nashorn.internal.parser.TokenType.COMMENT;
39import static jdk.nashorn.internal.parser.TokenType.CONST;
40import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
41import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
42import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS;
43import static jdk.nashorn.internal.parser.TokenType.ELSE;
44import static jdk.nashorn.internal.parser.TokenType.EOF;
45import static jdk.nashorn.internal.parser.TokenType.EOL;
46import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT;
47import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
48import static jdk.nashorn.internal.parser.TokenType.EXPORT;
49import static jdk.nashorn.internal.parser.TokenType.EXTENDS;
50import static jdk.nashorn.internal.parser.TokenType.FINALLY;
51import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
52import static jdk.nashorn.internal.parser.TokenType.IDENT;
53import static jdk.nashorn.internal.parser.TokenType.IF;
54import static jdk.nashorn.internal.parser.TokenType.IMPORT;
55import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
56import static jdk.nashorn.internal.parser.TokenType.LBRACE;
57import static jdk.nashorn.internal.parser.TokenType.LBRACKET;
58import static jdk.nashorn.internal.parser.TokenType.LET;
59import static jdk.nashorn.internal.parser.TokenType.LPAREN;
60import static jdk.nashorn.internal.parser.TokenType.MUL;
61import static jdk.nashorn.internal.parser.TokenType.PERIOD;
62import static jdk.nashorn.internal.parser.TokenType.RBRACE;
63import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
64import static jdk.nashorn.internal.parser.TokenType.RPAREN;
65import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
66import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY;
67import static jdk.nashorn.internal.parser.TokenType.STATIC;
68import static jdk.nashorn.internal.parser.TokenType.STRING;
69import static jdk.nashorn.internal.parser.TokenType.SUPER;
70import static jdk.nashorn.internal.parser.TokenType.TEMPLATE;
71import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD;
72import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE;
73import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL;
74import static jdk.nashorn.internal.parser.TokenType.TERNARY;
75import static jdk.nashorn.internal.parser.TokenType.VAR;
76import static jdk.nashorn.internal.parser.TokenType.VOID;
77import static jdk.nashorn.internal.parser.TokenType.WHILE;
78import static jdk.nashorn.internal.parser.TokenType.YIELD;
79import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR;
80
81import java.io.Serializable;
82import java.util.ArrayDeque;
83import java.util.ArrayList;
84import java.util.Collections;
85import java.util.Deque;
86import java.util.HashMap;
87import java.util.HashSet;
88import java.util.Iterator;
89import java.util.List;
90import java.util.Map;
91import java.util.Objects;
92import java.util.function.Consumer;
93import jdk.nashorn.internal.codegen.CompilerConstants;
94import jdk.nashorn.internal.codegen.Namespace;
95import jdk.nashorn.internal.ir.AccessNode;
96import jdk.nashorn.internal.ir.BaseNode;
97import jdk.nashorn.internal.ir.BinaryNode;
98import jdk.nashorn.internal.ir.Block;
99import jdk.nashorn.internal.ir.BlockStatement;
100import jdk.nashorn.internal.ir.BreakNode;
101import jdk.nashorn.internal.ir.CallNode;
102import jdk.nashorn.internal.ir.CaseNode;
103import jdk.nashorn.internal.ir.CatchNode;
104import jdk.nashorn.internal.ir.ClassNode;
105import jdk.nashorn.internal.ir.ContinueNode;
106import jdk.nashorn.internal.ir.DebuggerNode;
107import jdk.nashorn.internal.ir.EmptyNode;
108import jdk.nashorn.internal.ir.ErrorNode;
109import jdk.nashorn.internal.ir.Expression;
110import jdk.nashorn.internal.ir.ExpressionList;
111import jdk.nashorn.internal.ir.ExpressionStatement;
112import jdk.nashorn.internal.ir.ForNode;
113import jdk.nashorn.internal.ir.FunctionNode;
114import jdk.nashorn.internal.ir.IdentNode;
115import jdk.nashorn.internal.ir.IfNode;
116import jdk.nashorn.internal.ir.IndexNode;
117import jdk.nashorn.internal.ir.JoinPredecessorExpression;
118import jdk.nashorn.internal.ir.LabelNode;
119import jdk.nashorn.internal.ir.LexicalContext;
120import jdk.nashorn.internal.ir.LiteralNode;
121import jdk.nashorn.internal.ir.Module;
122import jdk.nashorn.internal.ir.Node;
123import jdk.nashorn.internal.ir.ObjectNode;
124import jdk.nashorn.internal.ir.PropertyKey;
125import jdk.nashorn.internal.ir.PropertyNode;
126import jdk.nashorn.internal.ir.ReturnNode;
127import jdk.nashorn.internal.ir.RuntimeNode;
128import jdk.nashorn.internal.ir.Statement;
129import jdk.nashorn.internal.ir.SwitchNode;
130import jdk.nashorn.internal.ir.TernaryNode;
131import jdk.nashorn.internal.ir.ThrowNode;
132import jdk.nashorn.internal.ir.TryNode;
133import jdk.nashorn.internal.ir.UnaryNode;
134import jdk.nashorn.internal.ir.VarNode;
135import jdk.nashorn.internal.ir.WhileNode;
136import jdk.nashorn.internal.ir.WithNode;
137import jdk.nashorn.internal.ir.debug.ASTWriter;
138import jdk.nashorn.internal.ir.debug.PrintVisitor;
139import jdk.nashorn.internal.ir.visitor.NodeVisitor;
140import jdk.nashorn.internal.runtime.Context;
141import jdk.nashorn.internal.runtime.ErrorManager;
142import jdk.nashorn.internal.runtime.JSErrorType;
143import jdk.nashorn.internal.runtime.ParserException;
144import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
145import jdk.nashorn.internal.runtime.ScriptEnvironment;
146import jdk.nashorn.internal.runtime.ScriptingFunctions;
147import jdk.nashorn.internal.runtime.Source;
148import jdk.nashorn.internal.runtime.Timing;
149import jdk.nashorn.internal.runtime.linker.NameCodec;
150import jdk.nashorn.internal.runtime.logging.DebugLogger;
151import jdk.nashorn.internal.runtime.logging.Loggable;
152import jdk.nashorn.internal.runtime.logging.Logger;
153
154/**
155 * Builds the IR.
156 */
157@Logger(name="parser")
158public class Parser extends AbstractParser implements Loggable {
159    private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName();
160
161    /** Current env. */
162    private final ScriptEnvironment env;
163
164    /** Is scripting mode. */
165    private final boolean scripting;
166
167    private List<Statement> functionDeclarations;
168
169    private final ParserContext lc;
170    private final Deque<Object> defaultNames;
171
172    /** Namespace for function names where not explicitly given */
173    private final Namespace namespace;
174
175    private final DebugLogger log;
176
177    /** to receive line information from Lexer when scanning multine literals. */
178    protected final Lexer.LineInfoReceiver lineInfoReceiver;
179
180    private RecompilableScriptFunctionData reparsedFunction;
181
182    /**
183     * Constructor
184     *
185     * @param env     script environment
186     * @param source  source to parse
187     * @param errors  error manager
188     */
189    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) {
190        this(env, source, errors, env._strict, null);
191    }
192
193    /**
194     * Constructor
195     *
196     * @param env     script environment
197     * @param source  source to parse
198     * @param errors  error manager
199     * @param strict  strict
200     * @param log debug logger if one is needed
201     */
202    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) {
203        this(env, source, errors, strict, 0, log);
204    }
205
206    /**
207     * Construct a parser.
208     *
209     * @param env     script environment
210     * @param source  source to parse
211     * @param errors  error manager
212     * @param strict  parser created with strict mode enabled.
213     * @param lineOffset line offset to start counting lines from
214     * @param log debug logger if one is needed
215     */
216    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
217        super(source, errors, strict, lineOffset);
218        this.lc = new ParserContext();
219        this.defaultNames = new ArrayDeque<>();
220        this.env = env;
221        this.namespace = new Namespace(env.getNamespace());
222        this.scripting = env._scripting;
223        if (this.scripting) {
224            this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
225                @Override
226                public void lineInfo(final int receiverLine, final int receiverLinePosition) {
227                    // update the parser maintained line information
228                    Parser.this.line = receiverLine;
229                    Parser.this.linePosition = receiverLinePosition;
230                }
231            };
232        } else {
233            // non-scripting mode script can't have multi-line literals
234            this.lineInfoReceiver = null;
235        }
236
237        this.log = log == null ? DebugLogger.DISABLED_LOGGER : log;
238    }
239
240    @Override
241    public DebugLogger getLogger() {
242        return log;
243    }
244
245    @Override
246    public DebugLogger initLogger(final Context context) {
247        return context.getLogger(this.getClass());
248    }
249
250    /**
251     * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can
252     * preserve their already assigned name, as that name doesn't appear in their source text.
253     * @param name the name for the first parsed function.
254     */
255    public void setFunctionName(final String name) {
256        defaultNames.push(createIdentNode(0, 0, name));
257    }
258
259    /**
260     * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this
261     * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation).
262     * This will trigger various special behaviors, such as skipping nested function bodies.
263     * @param reparsedFunction the function being reparsed.
264     */
265    public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) {
266        this.reparsedFunction = reparsedFunction;
267    }
268
269    /**
270     * Execute parse and return the resulting function node.
271     * Errors will be thrown and the error manager will contain information
272     * if parsing should fail
273     *
274     * This is the default parse call, which will name the function node
275     * {code :program} {@link CompilerConstants#PROGRAM}
276     *
277     * @return function node resulting from successful parse
278     */
279    public FunctionNode parse() {
280        return parse(PROGRAM.symbolName(), 0, source.getLength(), false);
281    }
282
283    /**
284     * Set up first token. Skips opening EOL.
285     */
286    private void scanFirstToken() {
287        k = -1;
288        next();
289    }
290
291    /**
292     * Execute parse and return the resulting function node.
293     * Errors will be thrown and the error manager will contain information
294     * if parsing should fail
295     *
296     * This should be used to create one and only one function node
297     *
298     * @param scriptName name for the script, given to the parsed FunctionNode
299     * @param startPos start position in source
300     * @param len length of parse
301     * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by
302     * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a
303     * property getter or setter in an object literal.
304     *
305     * @return function node resulting from successful parse
306     */
307    public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) {
308        final boolean isTimingEnabled = env.isTimingEnabled();
309        final long t0 = isTimingEnabled ? System.nanoTime() : 0L;
310        log.info(this, " begin for '", scriptName, "'");
311
312        try {
313            stream = new TokenStream();
314            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
315            lexer.line = lexer.pendingLine = lineOffset + 1;
316            line = lineOffset;
317
318            scanFirstToken();
319            // Begin parse.
320            return program(scriptName, allowPropertyFunction);
321        } catch (final Exception e) {
322            handleParseException(e);
323
324            return null;
325        } finally {
326            final String end = this + " end '" + scriptName + "'";
327            if (isTimingEnabled) {
328                env._timing.accumulateTime(toString(), System.nanoTime() - t0);
329                log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms");
330            } else {
331                log.info(end);
332            }
333        }
334    }
335
336    /**
337     * Parse and return the resulting module.
338     * Errors will be thrown and the error manager will contain information
339     * if parsing should fail
340     *
341     * @param moduleName name for the module, given to the parsed FunctionNode
342     * @param startPos start position in source
343     * @param len length of parse
344     *
345     * @return function node resulting from successful parse
346     */
347    public FunctionNode parseModule(final String moduleName, final int startPos, final int len) {
348        try {
349            stream = new TokenStream();
350            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
351            lexer.line = lexer.pendingLine = lineOffset + 1;
352            line = lineOffset;
353
354            scanFirstToken();
355            // Begin parse.
356            return module(moduleName);
357        } catch (final Exception e) {
358            handleParseException(e);
359
360            return null;
361        }
362    }
363
364    /**
365     * Entry point for parsing a module.
366     *
367     * @param moduleName the module name
368     * @return the parsed module
369     */
370    public FunctionNode parseModule(final String moduleName) {
371        return parseModule(moduleName, 0, source.getLength());
372    }
373
374    /**
375     * Parse and return the list of function parameter list. A comma
376     * separated list of function parameter identifiers is expected to be parsed.
377     * Errors will be thrown and the error manager will contain information
378     * if parsing should fail. This method is used to check if parameter Strings
379     * passed to "Function" constructor is a valid or not.
380     *
381     * @return the list of IdentNodes representing the formal parameter list
382     */
383    public List<IdentNode> parseFormalParameterList() {
384        try {
385            stream = new TokenStream();
386            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
387
388            scanFirstToken();
389
390            return formalParameterList(TokenType.EOF, false);
391        } catch (final Exception e) {
392            handleParseException(e);
393            return null;
394        }
395    }
396
397    /**
398     * Execute parse and return the resulting function node.
399     * Errors will be thrown and the error manager will contain information
400     * if parsing should fail. This method is used to check if code String
401     * passed to "Function" constructor is a valid function body or not.
402     *
403     * @return function node resulting from successful parse
404     */
405    public FunctionNode parseFunctionBody() {
406        try {
407            stream = new TokenStream();
408            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
409            final int functionLine = line;
410
411            scanFirstToken();
412
413            // Make a fake token for the function.
414            final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
415            // Set up the function to append elements.
416
417            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName());
418            final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList());
419            lc.push(function);
420
421            final ParserContextBlockNode body = newBlock();
422
423            functionDeclarations = new ArrayList<>();
424            sourceElements(false);
425            addFunctionDeclarations(function);
426            functionDeclarations = null;
427
428            restoreBlock(body);
429            body.setFlag(Block.NEEDS_SCOPE);
430
431            final Block functionBody = new Block(functionToken, source.getLength() - 1,
432                body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
433            lc.pop(function);
434
435            expect(EOF);
436
437            final FunctionNode functionNode = createFunctionNode(
438                    function,
439                    functionToken,
440                    ident,
441                    Collections.<IdentNode>emptyList(),
442                    FunctionNode.Kind.NORMAL,
443                    functionLine,
444                    functionBody);
445            printAST(functionNode);
446            return functionNode;
447        } catch (final Exception e) {
448            handleParseException(e);
449            return null;
450        }
451    }
452
453    private void handleParseException(final Exception e) {
454        // Extract message from exception.  The message will be in error
455        // message format.
456        String message = e.getMessage();
457
458        // If empty message.
459        if (message == null) {
460            message = e.toString();
461        }
462
463        // Issue message.
464        if (e instanceof ParserException) {
465            errors.error((ParserException)e);
466        } else {
467            errors.error(message);
468        }
469
470        if (env._dump_on_error) {
471            e.printStackTrace(env.getErr());
472        }
473    }
474
475    /**
476     * Skip to a good parsing recovery point.
477     */
478    private void recover(final Exception e) {
479        if (e != null) {
480            // Extract message from exception.  The message will be in error
481            // message format.
482            String message = e.getMessage();
483
484            // If empty message.
485            if (message == null) {
486                message = e.toString();
487            }
488
489            // Issue message.
490            if (e instanceof ParserException) {
491                errors.error((ParserException)e);
492            } else {
493                errors.error(message);
494            }
495
496            if (env._dump_on_error) {
497                e.printStackTrace(env.getErr());
498            }
499        }
500
501        // Skip to a recovery point.
502        loop:
503        while (true) {
504            switch (type) {
505            case EOF:
506                // Can not go any further.
507                break loop;
508            case EOL:
509            case SEMICOLON:
510            case RBRACE:
511                // Good recovery points.
512                next();
513                break loop;
514            default:
515                // So we can recover after EOL.
516                nextOrEOL();
517                break;
518            }
519        }
520    }
521
522    /**
523     * Set up a new block.
524     *
525     * @return New block.
526     */
527    private ParserContextBlockNode newBlock() {
528        return lc.push(new ParserContextBlockNode(token));
529    }
530
531    private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) {
532        // Build function name.
533        final StringBuilder sb = new StringBuilder();
534
535        final ParserContextFunctionNode parentFunction = lc.getCurrentFunction();
536        if (parentFunction != null && !parentFunction.isProgram()) {
537            sb.append(parentFunction.getName()).append(CompilerConstants.NESTED_FUNCTION_SEPARATOR.symbolName());
538        }
539
540        assert ident.getName() != null;
541        sb.append(ident.getName());
542
543        final String name = namespace.uniqueName(sb.toString());
544        assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name;
545
546        int flags = 0;
547        if (isStrictMode) {
548            flags |= FunctionNode.IS_STRICT;
549        }
550        if (parentFunction == null) {
551            flags |= FunctionNode.IS_PROGRAM;
552        }
553
554        final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters);
555        functionNode.setFlag(flags);
556        return functionNode;
557    }
558
559    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) {
560        // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody();
561        // Start new block.
562        final FunctionNode functionNode =
563            new FunctionNode(
564                source,
565                functionLine,
566                body.getToken(),
567                Token.descPosition(body.getToken()),
568                startToken,
569                function.getLastToken(),
570                namespace,
571                ident,
572                function.getName(),
573                parameters,
574                kind,
575                function.getFlags(),
576                body,
577                function.getEndParserState(),
578                function.getModule(),
579                function.getDebugFlags());
580
581        printAST(functionNode);
582
583        return functionNode;
584    }
585
586    /**
587     * Restore the current block.
588     */
589    private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) {
590        return lc.pop(block);
591    }
592
593    /**
594     * Get the statements in a block.
595     * @return Block statements.
596     */
597    private Block getBlock(final boolean needsBraces) {
598        final long blockToken = token;
599        final ParserContextBlockNode newBlock = newBlock();
600        try {
601            // Block opening brace.
602            if (needsBraces) {
603                expect(LBRACE);
604            }
605            // Accumulate block statements.
606            statementList();
607
608        } finally {
609            restoreBlock(newBlock);
610        }
611
612        // Block closing brace.
613        if (needsBraces) {
614            expect(RBRACE);
615        }
616
617        final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC);
618        return new Block(blockToken, finish, flags, newBlock.getStatements());
619    }
620
621    /**
622     * Get the statements in a case clause.
623     */
624    private List<Statement> caseStatementList() {
625        final ParserContextBlockNode newBlock = newBlock();
626        try {
627            statementList();
628        } finally {
629            restoreBlock(newBlock);
630        }
631        return newBlock.getStatements();
632    }
633
634    /**
635     * Get all the statements generated by a single statement.
636     * @return Statements.
637     */
638    private Block getStatement() {
639        return getStatement(false);
640    }
641
642    private Block getStatement(boolean labelledStatement) {
643        if (type == LBRACE) {
644            return getBlock(true);
645        }
646        // Set up new block. Captures first token.
647        final ParserContextBlockNode newBlock = newBlock();
648        try {
649            statement(false, false, true, labelledStatement);
650        } finally {
651            restoreBlock(newBlock);
652        }
653        return new Block(newBlock.getToken(), finish, newBlock.getFlags() | Block.IS_SYNTHETIC, newBlock.getStatements());
654    }
655
656    /**
657     * Detect calls to special functions.
658     * @param ident Called function.
659     */
660    private void detectSpecialFunction(final IdentNode ident) {
661        final String name = ident.getName();
662
663        if (EVAL.symbolName().equals(name)) {
664            markEval(lc);
665        } else if (SUPER.getName().equals(name)) {
666            assert ident.isDirectSuper();
667            markSuperCall(lc);
668        }
669    }
670
671    /**
672     * Detect use of special properties.
673     * @param ident Referenced property.
674     */
675    private void detectSpecialProperty(final IdentNode ident) {
676        if (isArguments(ident)) {
677            // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); }
678            getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS);
679        }
680    }
681
682    private boolean useBlockScope() {
683        return env._es6;
684    }
685
686    private boolean isES6() {
687        return env._es6;
688    }
689
690    private static boolean isArguments(final String name) {
691        return ARGUMENTS_NAME.equals(name);
692    }
693
694    static boolean isArguments(final IdentNode ident) {
695        return isArguments(ident.getName());
696    }
697
698    /**
699     * Tells whether a IdentNode can be used as L-value of an assignment
700     *
701     * @param ident IdentNode to be checked
702     * @return whether the ident can be used as L-value
703     */
704    private static boolean checkIdentLValue(final IdentNode ident) {
705        return ident.tokenType().getKind() != TokenKind.KEYWORD;
706    }
707
708    /**
709     * Verify an assignment expression.
710     * @param op  Operation token.
711     * @param lhs Left hand side expression.
712     * @param rhs Right hand side expression.
713     * @return Verified expression.
714     */
715    private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) {
716        final TokenType opType = Token.descType(op);
717
718        switch (opType) {
719        case ASSIGN:
720        case ASSIGN_ADD:
721        case ASSIGN_BIT_AND:
722        case ASSIGN_BIT_OR:
723        case ASSIGN_BIT_XOR:
724        case ASSIGN_DIV:
725        case ASSIGN_MOD:
726        case ASSIGN_MUL:
727        case ASSIGN_SAR:
728        case ASSIGN_SHL:
729        case ASSIGN_SHR:
730        case ASSIGN_SUB:
731            if (lhs instanceof IdentNode) {
732                if (!checkIdentLValue((IdentNode)lhs)) {
733                    return referenceError(lhs, rhs, false);
734                }
735                verifyIdent((IdentNode)lhs, "assignment");
736                break;
737            } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) {
738                break;
739            } else if (opType == ASSIGN && isDestructuringLhs(lhs)) {
740                verifyDestructuringAssignmentPattern(lhs, "assignment");
741                break;
742            } else {
743                return referenceError(lhs, rhs, env._early_lvalue_error);
744            }
745        default:
746            break;
747        }
748
749        // Build up node.
750        if(BinaryNode.isLogical(opType)) {
751            return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
752        }
753        return new BinaryNode(op, lhs, rhs);
754    }
755
756    private boolean isDestructuringLhs(Expression lhs) {
757        if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) {
758            return isES6();
759        }
760        return false;
761    }
762
763    private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) {
764        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
765        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
766            @Override
767            public boolean enterLiteralNode(LiteralNode<?> literalNode) {
768                if (literalNode.isArray()) {
769                    boolean restElement = false;
770                    for (Expression element : literalNode.getElementExpressions()) {
771                        if (element != null) {
772                            if (restElement) {
773                                throw error(String.format("Unexpected element after rest element"), element.getToken());
774                            }
775                            if (element.isTokenType(SPREAD_ARRAY)) {
776                                restElement = true;
777                                Expression lvalue = ((UnaryNode) element).getExpression();
778                                if (!checkValidLValue(lvalue, contextString)) {
779                                    throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken());
780                                }
781                            }
782                            element.accept(this);
783                        }
784                    }
785                    return false;
786                } else {
787                    return enterDefault(literalNode);
788                }
789            }
790
791            @Override
792            public boolean enterObjectNode(ObjectNode objectNode) {
793                return true;
794            }
795
796            @Override
797            public boolean enterPropertyNode(PropertyNode propertyNode) {
798                if (propertyNode.getValue() != null) {
799                    propertyNode.getValue().accept(this);
800                    return false;
801                } else {
802                    return enterDefault(propertyNode);
803                }
804            }
805
806            @Override
807            public boolean enterIdentNode(IdentNode identNode) {
808                verifyIdent(identNode, contextString);
809                if (!checkIdentLValue(identNode)) {
810                    referenceError(identNode, null, true);
811                    return false;
812                }
813                return false;
814            }
815
816            @Override
817            public boolean enterAccessNode(AccessNode accessNode) {
818                return false;
819            }
820
821            @Override
822            public boolean enterIndexNode(IndexNode indexNode) {
823                return false;
824            }
825
826            @Override
827            public boolean enterBinaryNode(BinaryNode binaryNode) {
828                if (binaryNode.isTokenType(ASSIGN)) {
829                    binaryNode.lhs().accept(this);
830                    // Initializer(rhs) can be any AssignmentExpression
831                    return false;
832                } else {
833                    return enterDefault(binaryNode);
834                }
835            }
836
837            @Override
838            public boolean enterUnaryNode(UnaryNode unaryNode) {
839                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
840                    // rest element
841                    return true;
842                } else {
843                    return enterDefault(unaryNode);
844                }
845            }
846
847            @Override
848            protected boolean enterDefault(Node node) {
849                throw error(String.format("unexpected node in AssignmentPattern: %s", node));
850            }
851        });
852    }
853
854    private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
855        final TokenType opType = Token.descType(op);
856
857        // Build up node.
858        if (BinaryNode.isLogical(opType)) {
859            return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
860        }
861        return new BinaryNode(op, lhs, rhs);
862    }
863
864
865    /**
866     * Reduce increment/decrement to simpler operations.
867     * @param firstToken First token.
868     * @param tokenType  Operation token (INCPREFIX/DEC.)
869     * @param expression Left hand side expression.
870     * @param isPostfix  Prefix or postfix.
871     * @return           Reduced expression.
872     */
873    private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) {
874        if (isPostfix) {
875            return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
876        }
877
878        return new UnaryNode(firstToken, expression);
879    }
880
881    /**
882     * -----------------------------------------------------------------------
883     *
884     * Grammar based on
885     *
886     *      ECMAScript Language Specification
887     *      ECMA-262 5th Edition / December 2009
888     *
889     * -----------------------------------------------------------------------
890     */
891
892    /**
893     * Program :
894     *      SourceElements?
895     *
896     * See 14
897     *
898     * Parse the top level script.
899     */
900    private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) {
901        // Make a pseudo-token for the script holding its start and length.
902        final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
903        final int  functionLine  = line;
904
905        final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName);
906        final ParserContextFunctionNode script = createParserContextFunctionNode(
907                ident,
908                functionToken,
909                FunctionNode.Kind.SCRIPT,
910                functionLine,
911                Collections.<IdentNode>emptyList());
912        lc.push(script);
913        final ParserContextBlockNode body = newBlock();
914
915        functionDeclarations = new ArrayList<>();
916        sourceElements(allowPropertyFunction);
917        addFunctionDeclarations(script);
918        functionDeclarations = null;
919
920        restoreBlock(body);
921        body.setFlag(Block.NEEDS_SCOPE);
922        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
923        lc.pop(script);
924        script.setLastToken(token);
925
926        expect(EOF);
927
928        return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody);
929    }
930
931    /**
932     * Directive value or null if statement is not a directive.
933     *
934     * @param stmt Statement to be checked
935     * @return Directive value if the given statement is a directive
936     */
937    private String getDirective(final Node stmt) {
938        if (stmt instanceof ExpressionStatement) {
939            final Node expr = ((ExpressionStatement)stmt).getExpression();
940            if (expr instanceof LiteralNode) {
941                final LiteralNode<?> lit = (LiteralNode<?>)expr;
942                final long litToken = lit.getToken();
943                final TokenType tt = Token.descType(litToken);
944                // A directive is either a string or an escape string
945                if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) {
946                    // Make sure that we don't unescape anything. Return as seen in source!
947                    return source.getString(lit.getStart(), Token.descLength(litToken));
948                }
949            }
950        }
951
952        return null;
953    }
954
955    /**
956     * SourceElements :
957     *      SourceElement
958     *      SourceElements SourceElement
959     *
960     * See 14
961     *
962     * Parse the elements of the script or function.
963     */
964    private void sourceElements(final boolean shouldAllowPropertyFunction) {
965        List<Node>    directiveStmts        = null;
966        boolean       checkDirective        = true;
967        boolean       allowPropertyFunction = shouldAllowPropertyFunction;
968        final boolean oldStrictMode         = isStrictMode;
969
970
971        try {
972            // If is a script, then process until the end of the script.
973            while (type != EOF) {
974                // Break if the end of a code block.
975                if (type == RBRACE) {
976                    break;
977                }
978
979                try {
980                    // Get the next element.
981                    statement(true, allowPropertyFunction, false, false);
982                    allowPropertyFunction = false;
983
984                    // check for directive prologues
985                    if (checkDirective) {
986                        // skip any debug statement like line number to get actual first line
987                        final Statement lastStatement = lc.getLastStatement();
988
989                        // get directive prologue, if any
990                        final String directive = getDirective(lastStatement);
991
992                        // If we have seen first non-directive statement,
993                        // no more directive statements!!
994                        checkDirective = directive != null;
995
996                        if (checkDirective) {
997                            if (!oldStrictMode) {
998                                if (directiveStmts == null) {
999                                    directiveStmts = new ArrayList<>();
1000                                }
1001                                directiveStmts.add(lastStatement);
1002                            }
1003
1004                            // handle use strict directive
1005                            if ("use strict".equals(directive)) {
1006                                isStrictMode = true;
1007                                final ParserContextFunctionNode function = lc.getCurrentFunction();
1008                                function.setFlag(FunctionNode.IS_STRICT);
1009
1010                                // We don't need to check these, if lexical environment is already strict
1011                                if (!oldStrictMode && directiveStmts != null) {
1012                                    // check that directives preceding this one do not violate strictness
1013                                    for (final Node statement : directiveStmts) {
1014                                        // the get value will force unescape of preceding
1015                                        // escaped string directives
1016                                        getValue(statement.getToken());
1017                                    }
1018
1019                                    // verify that function name as well as parameter names
1020                                    // satisfy strict mode restrictions.
1021                                    verifyIdent(function.getIdent(), "function name");
1022                                    for (final IdentNode param : function.getParameters()) {
1023                                        verifyIdent(param, "function parameter");
1024                                    }
1025                                }
1026                            } else if (Context.DEBUG) {
1027                                final int debugFlag = FunctionNode.getDirectiveFlag(directive);
1028                                if (debugFlag != 0) {
1029                                    final ParserContextFunctionNode function = lc.getCurrentFunction();
1030                                    function.setDebugFlag(debugFlag);
1031                                }
1032                            }
1033                        }
1034                    }
1035                } catch (final Exception e) {
1036                    final int errorLine = line;
1037                    final long errorToken = token;
1038                    //recover parsing
1039                    recover(e);
1040                    final ErrorNode errorExpr = new ErrorNode(errorToken, finish);
1041                    final ExpressionStatement expressionStatement = new ExpressionStatement(errorLine, errorToken, finish, errorExpr);
1042                    appendStatement(expressionStatement);
1043                }
1044
1045                // No backtracking from here on.
1046                stream.commit(k);
1047            }
1048        } finally {
1049            isStrictMode = oldStrictMode;
1050        }
1051    }
1052
1053    /**
1054     * Parse any of the basic statement types.
1055     *
1056     * Statement :
1057     *      BlockStatement
1058     *      VariableStatement
1059     *      EmptyStatement
1060     *      ExpressionStatement
1061     *      IfStatement
1062     *      BreakableStatement
1063     *      ContinueStatement
1064     *      BreakStatement
1065     *      ReturnStatement
1066     *      WithStatement
1067     *      LabelledStatement
1068     *      ThrowStatement
1069     *      TryStatement
1070     *      DebuggerStatement
1071     *
1072     * BreakableStatement :
1073     *      IterationStatement
1074     *      SwitchStatement
1075     *
1076     * BlockStatement :
1077     *      Block
1078     *
1079     * Block :
1080     *      { StatementList opt }
1081     *
1082     * StatementList :
1083     *      StatementListItem
1084     *      StatementList StatementListItem
1085     *
1086     * StatementItem :
1087     *      Statement
1088     *      Declaration
1089     *
1090     * Declaration :
1091     *     HoistableDeclaration
1092     *     ClassDeclaration
1093     *     LexicalDeclaration
1094     *
1095     * HoistableDeclaration :
1096     *     FunctionDeclaration
1097     *     GeneratorDeclaration
1098     */
1099    private void statement() {
1100        statement(false, false, false, false);
1101    }
1102
1103    /**
1104     * @param topLevel does this statement occur at the "top level" of a script or a function?
1105     * @param allowPropertyFunction allow property "get" and "set" functions?
1106     * @param singleStatement are we in a single statement context?
1107     */
1108    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) {
1109        switch (type) {
1110        case LBRACE:
1111            block();
1112            break;
1113        case VAR:
1114            variableStatement(type);
1115            break;
1116        case SEMICOLON:
1117            emptyStatement();
1118            break;
1119        case IF:
1120            ifStatement();
1121            break;
1122        case FOR:
1123            forStatement();
1124            break;
1125        case WHILE:
1126            whileStatement();
1127            break;
1128        case DO:
1129            doStatement();
1130            break;
1131        case CONTINUE:
1132            continueStatement();
1133            break;
1134        case BREAK:
1135            breakStatement();
1136            break;
1137        case RETURN:
1138            returnStatement();
1139            break;
1140        case WITH:
1141            withStatement();
1142            break;
1143        case SWITCH:
1144            switchStatement();
1145            break;
1146        case THROW:
1147            throwStatement();
1148            break;
1149        case TRY:
1150            tryStatement();
1151            break;
1152        case DEBUGGER:
1153            debuggerStatement();
1154            break;
1155        case RPAREN:
1156        case RBRACKET:
1157        case EOF:
1158            expect(SEMICOLON);
1159            break;
1160        case FUNCTION:
1161            // As per spec (ECMA section 12), function declarations as arbitrary statement
1162            // is not "portable". Implementation can issue a warning or disallow the same.
1163            if (singleStatement) {
1164                // ES6 B.3.2 Labelled Function Declarations
1165                // It is a Syntax Error if any strict mode source code matches this rule:
1166                // LabelledItem : FunctionDeclaration.
1167                if (!labelledStatement || isStrictMode) {
1168                    throw error(AbstractParser.message("expected.stmt", "function declaration"), token);
1169                }
1170            }
1171            functionExpression(true, topLevel || labelledStatement);
1172            return;
1173        default:
1174            if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) {
1175                if (singleStatement) {
1176                    throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
1177                }
1178                variableStatement(type);
1179                break;
1180            } else if (type == CLASS && isES6()) {
1181                if (singleStatement) {
1182                    throw error(AbstractParser.message("expected.stmt", "class declaration"), token);
1183                }
1184                classDeclaration(false);
1185                break;
1186            }
1187            if (env._const_as_var && type == CONST) {
1188                variableStatement(TokenType.VAR);
1189                break;
1190            }
1191
1192            if (type == IDENT || isNonStrictModeIdent()) {
1193                if (T(k + 1) == COLON) {
1194                    labelStatement();
1195                    return;
1196                }
1197                if(allowPropertyFunction) {
1198                    final String ident = (String)getValue();
1199                    final long propertyToken = token;
1200                    final int propertyLine = line;
1201                    if ("get".equals(ident)) {
1202                        next();
1203                        addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
1204                        return;
1205                    } else if ("set".equals(ident)) {
1206                        next();
1207                        addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
1208                        return;
1209                    }
1210                }
1211            }
1212
1213            expressionStatement();
1214            break;
1215        }
1216    }
1217
1218    private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) {
1219        final FunctionNode fn = propertyFunction.functionNode;
1220        functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn));
1221    }
1222
1223    /**
1224     * ClassDeclaration[Yield, Default] :
1225     *   class BindingIdentifier[?Yield] ClassTail[?Yield]
1226     *   [+Default] class ClassTail[?Yield]
1227     */
1228    private ClassNode classDeclaration(boolean isDefault) {
1229        int classLineNumber = line;
1230
1231        ClassNode classExpression = classExpression(!isDefault);
1232
1233        if (!isDefault) {
1234            VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST);
1235            appendStatement(classVar);
1236        }
1237        return classExpression;
1238    }
1239
1240    /**
1241     * ClassExpression[Yield] :
1242     *   class BindingIdentifier[?Yield]opt ClassTail[?Yield]
1243     */
1244    private ClassNode classExpression(boolean isStatement) {
1245        assert type == CLASS;
1246        int classLineNumber = line;
1247        long classToken = token;
1248        next();
1249
1250        IdentNode className = null;
1251        if (isStatement || type == IDENT) {
1252            className = getIdent();
1253        }
1254
1255        return classTail(classLineNumber, classToken, className);
1256    }
1257
1258    private static final class ClassElementKey {
1259        private final boolean isStatic;
1260        private final String propertyName;
1261
1262        private ClassElementKey(boolean isStatic, String propertyName) {
1263            this.isStatic = isStatic;
1264            this.propertyName = propertyName;
1265        }
1266
1267        @Override
1268        public int hashCode() {
1269            final int prime = 31;
1270            int result = 1;
1271            result = prime * result + (isStatic ? 1231 : 1237);
1272            result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
1273            return result;
1274        }
1275
1276        @Override
1277        public boolean equals(Object obj) {
1278            if (obj instanceof ClassElementKey) {
1279                ClassElementKey other = (ClassElementKey) obj;
1280                return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName);
1281            }
1282            return false;
1283        }
1284    }
1285
1286    /**
1287     * Parse ClassTail and ClassBody.
1288     *
1289     * ClassTail[Yield] :
1290     *   ClassHeritage[?Yield]opt { ClassBody[?Yield]opt }
1291     * ClassHeritage[Yield] :
1292     *   extends LeftHandSideExpression[?Yield]
1293     *
1294     * ClassBody[Yield] :
1295     *   ClassElementList[?Yield]
1296     * ClassElementList[Yield] :
1297     *   ClassElement[?Yield]
1298     *   ClassElementList[?Yield] ClassElement[?Yield]
1299     * ClassElement[Yield] :
1300     *   MethodDefinition[?Yield]
1301     *   static MethodDefinition[?Yield]
1302     *   ;
1303     */
1304    private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) {
1305        final boolean oldStrictMode = isStrictMode;
1306        isStrictMode = true;
1307        try {
1308            Expression classHeritage = null;
1309            if (type == EXTENDS) {
1310                next();
1311                classHeritage = leftHandSideExpression();
1312            }
1313
1314            expect(LBRACE);
1315
1316            PropertyNode constructor = null;
1317            final ArrayList<PropertyNode> classElements = new ArrayList<>();
1318            final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>();
1319            for (;;) {
1320                if (type == SEMICOLON) {
1321                    next();
1322                    continue;
1323                }
1324                if (type == RBRACE) {
1325                    break;
1326                }
1327                final long classElementToken = token;
1328                boolean isStatic = false;
1329                if (type == STATIC) {
1330                    isStatic = true;
1331                    next();
1332                }
1333                boolean generator = false;
1334                if (isES6() && type == MUL) {
1335                    generator = true;
1336                    next();
1337                }
1338                final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator);
1339                if (classElement.isComputed()) {
1340                    classElements.add(classElement);
1341                } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) {
1342                    if (constructor == null) {
1343                        constructor = classElement;
1344                    } else {
1345                        throw error(AbstractParser.message("multiple.constructors"), classElementToken);
1346                    }
1347                } else {
1348                    // Check for duplicate method definitions and combine accessor methods.
1349                    // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names).
1350
1351                    final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName());
1352                    final Integer existing = keyToIndexMap.get(key);
1353
1354                    if (existing == null) {
1355                        keyToIndexMap.put(key, classElements.size());
1356                        classElements.add(classElement);
1357                    } else {
1358                        final PropertyNode existingProperty = classElements.get(existing);
1359
1360                        final Expression   value  = classElement.getValue();
1361                        final FunctionNode getter = classElement.getGetter();
1362                        final FunctionNode setter = classElement.getSetter();
1363
1364                        if (value != null || existingProperty.getValue() != null) {
1365                            keyToIndexMap.put(key, classElements.size());
1366                            classElements.add(classElement);
1367                        } else if (getter != null) {
1368                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
1369                            classElements.set(existing, existingProperty.setGetter(getter));
1370                        } else if (setter != null) {
1371                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
1372                            classElements.set(existing, existingProperty.setSetter(setter));
1373                        }
1374                    }
1375                }
1376            }
1377
1378            final long lastToken = token;
1379            expect(RBRACE);
1380
1381            if (constructor == null) {
1382                constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null);
1383            }
1384
1385            classElements.trimToSize();
1386            return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements);
1387        } finally {
1388            isStrictMode = oldStrictMode;
1389        }
1390    }
1391
1392    private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) {
1393        final int ctorFinish = finish;
1394        final List<Statement> statements;
1395        final List<IdentNode> parameters;
1396        final long identToken = Token.recast(classToken, TokenType.IDENT);
1397        if (subclass) {
1398            final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper();
1399            final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter();
1400            final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent);
1401            final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false);
1402            statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall));
1403            parameters = Collections.singletonList(argsIdent);
1404        } else {
1405            statements = Collections.emptyList();
1406            parameters = Collections.emptyList();
1407        }
1408
1409        final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements);
1410        final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor");
1411        final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters);
1412        function.setLastToken(lastToken);
1413
1414        function.setFlag(FunctionNode.ES6_IS_METHOD);
1415        function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR);
1416        if (subclass) {
1417            function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR);
1418            function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
1419        }
1420        if (className == null) {
1421            function.setFlag(FunctionNode.IS_ANONYMOUS);
1422        }
1423
1424        final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode(
1425                        function,
1426                        classToken,
1427                        ctorName,
1428                        parameters,
1429                        FunctionNode.Kind.NORMAL,
1430                        classLineNumber,
1431                        body
1432                        ), null, null, false, false);
1433        return constructor;
1434    }
1435
1436    private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) {
1437        final long methodToken = token;
1438        final int methodLine = line;
1439        final boolean computed = type == LBRACKET;
1440        final boolean isIdent = type == IDENT;
1441        final Expression propertyName = propertyName();
1442        int flags = FunctionNode.ES6_IS_METHOD;
1443        if (!computed) {
1444            final String name = ((PropertyKey)propertyName).getPropertyName();
1445            if (!generator && isIdent && type != LPAREN && name.equals("get")) {
1446                final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags);
1447                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
1448                return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed);
1449            } else if (!generator && isIdent && type != LPAREN && name.equals("set")) {
1450                final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags);
1451                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
1452                return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed);
1453            } else {
1454                if (!isStatic && !generator && name.equals("constructor")) {
1455                    flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR;
1456                    if (subclass) {
1457                        flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR;
1458                    }
1459                }
1460                verifyAllowedMethodName(propertyName, isStatic, computed, generator, false);
1461            }
1462        }
1463        final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed);
1464        return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed);
1465    }
1466
1467    /**
1468     * ES6 14.5.1 Static Semantics: Early Errors.
1469     */
1470    private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) {
1471        if (!computed) {
1472            if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) {
1473                throw error(AbstractParser.message("generator.constructor"), key.getToken());
1474            }
1475            if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) {
1476                throw error(AbstractParser.message("accessor.constructor"), key.getToken());
1477            }
1478            if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) {
1479                throw error(AbstractParser.message("static.prototype.method"), key.getToken());
1480            }
1481        }
1482    }
1483
1484    /**
1485     * block :
1486     *      { StatementList? }
1487     *
1488     * see 12.1
1489     *
1490     * Parse a statement block.
1491     */
1492    private void block() {
1493        appendStatement(new BlockStatement(line, getBlock(true)));
1494    }
1495
1496    /**
1497     * StatementList :
1498     *      Statement
1499     *      StatementList Statement
1500     *
1501     * See 12.1
1502     *
1503     * Parse a list of statements.
1504     */
1505    private void statementList() {
1506        // Accumulate statements until end of list. */
1507        loop:
1508        while (type != EOF) {
1509            switch (type) {
1510            case EOF:
1511            case CASE:
1512            case DEFAULT:
1513            case RBRACE:
1514                break loop;
1515            default:
1516                break;
1517            }
1518
1519            // Get next statement.
1520            statement();
1521        }
1522    }
1523
1524    /**
1525     * Make sure that the identifier name used is allowed.
1526     *
1527     * @param ident         Identifier that is verified
1528     * @param contextString String used in error message to give context to the user
1529     */
1530    private void verifyIdent(final IdentNode ident, final String contextString) {
1531        verifyStrictIdent(ident, contextString);
1532        if (isES6()) {
1533            final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
1534            if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) {
1535                throw error(expectMessage(IDENT));
1536            }
1537        }
1538    }
1539
1540    /**
1541     * Make sure that in strict mode, the identifier name used is allowed.
1542     *
1543     * @param ident         Identifier that is verified
1544     * @param contextString String used in error message to give context to the user
1545     */
1546    private void verifyStrictIdent(final IdentNode ident, final String contextString) {
1547        if (isStrictMode) {
1548            switch (ident.getName()) {
1549            case "eval":
1550            case "arguments":
1551                throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1552            default:
1553                break;
1554            }
1555
1556            if (ident.isFutureStrictName()) {
1557                throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1558            }
1559        }
1560    }
1561
1562    /*
1563     * VariableStatement :
1564     *      var VariableDeclarationList ;
1565     *
1566     * VariableDeclarationList :
1567     *      VariableDeclaration
1568     *      VariableDeclarationList , VariableDeclaration
1569     *
1570     * VariableDeclaration :
1571     *      Identifier Initializer?
1572     *
1573     * Initializer :
1574     *      = AssignmentExpression
1575     *
1576     * See 12.2
1577     *
1578     * Parse a VAR statement.
1579     * @param isStatement True if a statement (not used in a FOR.)
1580     */
1581    private void variableStatement(final TokenType varType) {
1582        variableDeclarationList(varType, true, -1);
1583    }
1584
1585    private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) {
1586        // VAR tested in caller.
1587        assert varType == VAR || varType == LET || varType == CONST;
1588        next();
1589
1590        final List<Expression> bindings = new ArrayList<>();
1591        int varFlags = 0;
1592        if (varType == LET) {
1593            varFlags |= VarNode.IS_LET;
1594        } else if (varType == CONST) {
1595            varFlags |= VarNode.IS_CONST;
1596        }
1597
1598        Expression missingAssignment = null;
1599        while (true) {
1600            // Get starting token.
1601            final int  varLine  = line;
1602            final long varToken = token;
1603            // Get name of var.
1604            if (type == YIELD && inGeneratorFunction()) {
1605                expect(IDENT);
1606            }
1607
1608            final String contextString = "variable name";
1609            Expression binding = bindingIdentifierOrPattern(contextString);
1610            final boolean isDestructuring = !(binding instanceof IdentNode);
1611            if (isDestructuring) {
1612                final int finalVarFlags = varFlags;
1613                verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() {
1614                    public void accept(final IdentNode identNode) {
1615                        verifyIdent(identNode, contextString);
1616                        final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags);
1617                        appendStatement(var);
1618                    }
1619                });
1620            }
1621
1622            // Assume no init.
1623            Expression init = null;
1624
1625            // Look for initializer assignment.
1626            if (type == ASSIGN) {
1627                next();
1628
1629                // Get initializer expression. Suppress IN if not statement.
1630                if (!isDestructuring) {
1631                    defaultNames.push(binding);
1632                }
1633                try {
1634                    init = assignmentExpression(!isStatement);
1635                } finally {
1636                    if (!isDestructuring) {
1637                        defaultNames.pop();
1638                    }
1639                }
1640            } else if (isStatement) {
1641                if (isDestructuring) {
1642                    throw error(AbstractParser.message("missing.destructuring.assignment"), token);
1643                } else if (varType == CONST) {
1644                    throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName()));
1645                }
1646                // else, if we are in a for loop, delay checking until we know the kind of loop
1647            }
1648
1649            if (!isDestructuring) {
1650                assert init != null || varType != CONST || !isStatement;
1651                final IdentNode ident = (IdentNode)binding;
1652                if (!isStatement && ident.getName().equals("let")) {
1653                    throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1
1654                }
1655                // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
1656                final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident;
1657                binding = name;
1658                final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags);
1659                appendStatement(var);
1660                if (init == null && varType == CONST) {
1661                    if (missingAssignment == null) {
1662                        missingAssignment = binding;
1663                    }
1664                }
1665            } else {
1666                assert init != null || !isStatement;
1667                binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init);
1668                if (isStatement) {
1669                    appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding));
1670                } else if (init == null) {
1671                    if (missingAssignment == null) {
1672                        missingAssignment = binding;
1673                    }
1674                }
1675            }
1676            bindings.add(binding);
1677
1678            if (type != COMMARIGHT) {
1679                break;
1680            }
1681            next();
1682        }
1683
1684        // If is a statement then handle end of line.
1685        if (isStatement) {
1686            endOfLine();
1687        } else {
1688            if (type == SEMICOLON) {
1689                // late check for missing assignment, now we know it's a for (init; test; modify) loop
1690                if (missingAssignment != null) {
1691                    if (missingAssignment instanceof IdentNode) {
1692                        throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName()));
1693                    } else {
1694                        throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken());
1695                    }
1696                }
1697            }
1698        }
1699
1700        return bindings;
1701    }
1702
1703    private boolean isBindingIdentifier() {
1704        return type == IDENT || isNonStrictModeIdent();
1705    }
1706
1707    private IdentNode bindingIdentifier(final String contextString) {
1708        final IdentNode name = getIdent();
1709        verifyIdent(name, contextString);
1710        return name;
1711    }
1712
1713    private Expression bindingPattern() {
1714        if (type == LBRACKET) {
1715            return arrayLiteral();
1716        } else if (type == LBRACE) {
1717            return objectLiteral();
1718        } else {
1719            throw error(AbstractParser.message("expected.binding"));
1720        }
1721    }
1722
1723    private Expression bindingIdentifierOrPattern(final String contextString) {
1724        if (isBindingIdentifier() || !isES6()) {
1725            return bindingIdentifier(contextString);
1726        } else {
1727            return bindingPattern();
1728        }
1729    }
1730
1731    /**
1732     * Verify destructuring variable declaration binding pattern and extract bound variable declarations.
1733     */
1734    private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) {
1735        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
1736        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
1737            @Override
1738            public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
1739                if (literalNode.isArray()) {
1740                    boolean restElement = false;
1741                    for (final Expression element : literalNode.getElementExpressions()) {
1742                        if (restElement) {
1743                            throw error(String.format("Unexpected element after rest element"), element.getToken());
1744                        }
1745                        if (element != null) {
1746                            if (element.isTokenType(SPREAD_ARRAY)) {
1747                                restElement = true;
1748                                if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) {
1749                                    throw error(String.format("Expected a valid binding identifier"), element.getToken());
1750
1751                                }
1752                            }
1753                            element.accept(this);
1754                        }
1755                    }
1756                    return false;
1757                } else {
1758                    return enterDefault(literalNode);
1759                }
1760            }
1761
1762            @Override
1763            public boolean enterObjectNode(final ObjectNode objectNode) {
1764                return true;
1765            }
1766
1767            @Override
1768            public boolean enterPropertyNode(final PropertyNode propertyNode) {
1769                if (propertyNode.getValue() != null) {
1770                    propertyNode.getValue().accept(this);
1771                    return false;
1772                } else {
1773                    return enterDefault(propertyNode);
1774                }
1775            }
1776
1777            @Override
1778            public boolean enterIdentNode(final IdentNode identNode) {
1779                identifierCallback.accept(identNode);
1780                return false;
1781            }
1782
1783            @Override
1784            public boolean enterBinaryNode(final BinaryNode binaryNode) {
1785                if (binaryNode.isTokenType(ASSIGN)) {
1786                    binaryNode.lhs().accept(this);
1787                    // Initializer(rhs) can be any AssignmentExpression
1788                    return false;
1789                } else {
1790                    return enterDefault(binaryNode);
1791                }
1792            }
1793
1794            @Override
1795            public boolean enterUnaryNode(final UnaryNode unaryNode) {
1796                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
1797                    // rest element
1798                    return true;
1799                } else {
1800                    return enterDefault(unaryNode);
1801                }
1802            }
1803
1804            @Override
1805            protected boolean enterDefault(final Node node) {
1806                throw error(String.format("unexpected node in BindingPattern: %s", node));
1807            }
1808        });
1809    }
1810
1811    /**
1812     * EmptyStatement :
1813     *      ;
1814     *
1815     * See 12.3
1816     *
1817     * Parse an empty statement.
1818     */
1819    private void emptyStatement() {
1820        if (env._empty_statements) {
1821            appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
1822        }
1823
1824        // SEMICOLON checked in caller.
1825        next();
1826    }
1827
1828    /**
1829     * ExpressionStatement :
1830     *      Expression ; // [lookahead ~({ or  function )]
1831     *
1832     * See 12.4
1833     *
1834     * Parse an expression used in a statement block.
1835     */
1836    private void expressionStatement() {
1837        // Lookahead checked in caller.
1838        final int  expressionLine  = line;
1839        final long expressionToken = token;
1840
1841        // Get expression and add as statement.
1842        final Expression expression = expression();
1843
1844        ExpressionStatement expressionStatement = null;
1845        if (expression != null) {
1846            expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression);
1847            appendStatement(expressionStatement);
1848        } else {
1849            expect(null);
1850        }
1851
1852        endOfLine();
1853    }
1854
1855    /**
1856     * IfStatement :
1857     *      if ( Expression ) Statement else Statement
1858     *      if ( Expression ) Statement
1859     *
1860     * See 12.5
1861     *
1862     * Parse an IF statement.
1863     */
1864    private void ifStatement() {
1865        // Capture IF token.
1866        final int  ifLine  = line;
1867        final long ifToken = token;
1868         // IF tested in caller.
1869        next();
1870
1871        expect(LPAREN);
1872        final Expression test = expression();
1873        expect(RPAREN);
1874        final Block pass = getStatement();
1875
1876        Block fail = null;
1877        if (type == ELSE) {
1878            next();
1879            fail = getStatement();
1880        }
1881
1882        appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1883    }
1884
1885    /**
1886     * ... IterationStatement:
1887     *           ...
1888     *           for ( Expression[NoIn]?; Expression? ; Expression? ) Statement
1889     *           for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement
1890     *           for ( LeftHandSideExpression in Expression ) Statement
1891     *           for ( var VariableDeclaration[NoIn] in Expression ) Statement
1892     *
1893     * See 12.6
1894     *
1895     * Parse a FOR statement.
1896     */
1897    @SuppressWarnings("fallthrough")
1898    private void forStatement() {
1899        final long forToken = token;
1900        final int forLine = line;
1901        // start position of this for statement. This is used
1902        // for sort order for variables declared in the initializer
1903        // part of this 'for' statement (if any).
1904        final int forStart = Token.descPosition(forToken);
1905        // When ES6 for-let is enabled we create a container block to capture the LET.
1906        final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
1907
1908        // Create FOR node, capturing FOR token.
1909        final ParserContextLoopNode forNode = new ParserContextLoopNode();
1910        lc.push(forNode);
1911        Block body = null;
1912        List<Expression> vars = null;
1913        Expression init = null;
1914        JoinPredecessorExpression test = null;
1915        JoinPredecessorExpression modify = null;
1916
1917        int flags = 0;
1918        boolean isForOf = false;
1919
1920        try {
1921            // FOR tested in caller.
1922            next();
1923
1924            // Nashorn extension: for each expression.
1925            // iterate property values rather than property names.
1926            if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1927                flags |= ForNode.IS_FOR_EACH;
1928                next();
1929            }
1930
1931            expect(LPAREN);
1932
1933            switch (type) {
1934            case VAR:
1935                // Var declaration captured in for outer block.
1936                vars = variableDeclarationList(type, false, forStart);
1937                break;
1938            case SEMICOLON:
1939                break;
1940            default:
1941                if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) {
1942                    flags |= ForNode.PER_ITERATION_SCOPE;
1943                    // LET/CONST declaration captured in container block created above.
1944                    vars = variableDeclarationList(type, false, forStart);
1945                    break;
1946                }
1947                if (env._const_as_var && type == CONST) {
1948                    // Var declaration captured in for outer block.
1949                    vars = variableDeclarationList(TokenType.VAR, false, forStart);
1950                    break;
1951                }
1952
1953                init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
1954                break;
1955            }
1956
1957            switch (type) {
1958            case SEMICOLON:
1959                // for (init; test; modify)
1960
1961                // for each (init; test; modify) is invalid
1962                if ((flags & ForNode.IS_FOR_EACH) != 0) {
1963                    throw error(AbstractParser.message("for.each.without.in"), token);
1964                }
1965
1966                expect(SEMICOLON);
1967                if (type != SEMICOLON) {
1968                    test = joinPredecessorExpression();
1969                }
1970                expect(SEMICOLON);
1971                if (type != RPAREN) {
1972                    modify = joinPredecessorExpression();
1973                }
1974                break;
1975
1976            case IDENT:
1977                if (env._es6 && "of".equals(getValue())) {
1978                    isForOf = true;
1979                    // fall through
1980                } else {
1981                    expect(SEMICOLON); // fail with expected message
1982                    break;
1983                }
1984            case IN:
1985
1986                flags |= isForOf ? ForNode.IS_FOR_OF : ForNode.IS_FOR_IN;
1987                test = new JoinPredecessorExpression();
1988                if (vars != null) {
1989                    // for (var i in obj)
1990                    if (vars.size() == 1) {
1991                        init = new IdentNode((IdentNode)vars.get(0));
1992                        if (init.isTokenType(ASSIGN)) {
1993                            throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken());
1994                        }
1995                        assert init instanceof IdentNode || isDestructuringLhs(init);
1996                    } else {
1997                        // for (var i, j in obj) is invalid
1998                        throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken());
1999                    }
2000                } else {
2001                    // for (expr in obj)
2002                    assert init != null : "for..in/of init expression can not be null here";
2003
2004                    // check if initial expression is a valid L-value
2005                    if (!(init instanceof AccessNode ||
2006                          init instanceof IndexNode ||
2007                          init instanceof IdentNode)) {
2008                        throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
2009                    }
2010
2011                    if (init instanceof IdentNode) {
2012                        if (!checkIdentLValue((IdentNode)init)) {
2013                            throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
2014                        }
2015                        verifyStrictIdent((IdentNode)init, isForOf ? "for-of iterator" : "for-in iterator");
2016                    }
2017                }
2018
2019                next();
2020
2021                // For-of only allows AssignmentExpression.
2022                modify = isForOf ? new JoinPredecessorExpression(assignmentExpression(false)) : joinPredecessorExpression();
2023                break;
2024
2025            default:
2026                expect(SEMICOLON);
2027                break;
2028            }
2029
2030            expect(RPAREN);
2031
2032            // Set the for body.
2033            body = getStatement();
2034        } finally {
2035            lc.pop(forNode);
2036
2037            for (final Statement var : forNode.getStatements()) {
2038                assert var instanceof VarNode;
2039                appendStatement(var);
2040            }
2041            if (body != null) {
2042                appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
2043            }
2044            if (outer != null) {
2045                restoreBlock(outer);
2046                if (body != null) {
2047                    appendStatement(new BlockStatement(forLine, new Block(
2048                                    outer.getToken(),
2049                                    body.getFinish(),
2050                                    outer.getStatements())));
2051                }
2052            }
2053        }
2054    }
2055
2056    private boolean checkValidLValue(final Expression init, final String contextString) {
2057        if (init instanceof IdentNode) {
2058            if (!checkIdentLValue((IdentNode)init)) {
2059                return false;
2060            }
2061            verifyIdent((IdentNode)init, contextString);
2062            return true;
2063        } else if (init instanceof AccessNode || init instanceof IndexNode) {
2064            return true;
2065        } else if (isDestructuringLhs(init)) {
2066            verifyDestructuringAssignmentPattern(init, contextString);
2067            return true;
2068        } else {
2069            return false;
2070        }
2071    }
2072
2073    @SuppressWarnings("fallthrough")
2074    private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) {
2075        assert type == LET;
2076        for (int i = 1;; i++) {
2077            TokenType t = T(k + i);
2078            switch (t) {
2079            case EOL:
2080            case COMMENT:
2081                continue;
2082            case IDENT:
2083                if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) {
2084                    return false;
2085                }
2086                // fall through
2087            case LBRACKET:
2088            case LBRACE:
2089                return true;
2090            default:
2091                // accept future strict tokens in non-strict mode (including LET)
2092                if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) {
2093                    return true;
2094                }
2095                return false;
2096            }
2097        }
2098    }
2099
2100    /**
2101     * ...IterationStatement :
2102     *           ...
2103     *           while ( Expression ) Statement
2104     *           ...
2105     *
2106     * See 12.6
2107     *
2108     * Parse while statement.
2109     */
2110    private void whileStatement() {
2111        // Capture WHILE token.
2112        final long whileToken = token;
2113        final int whileLine = line;
2114        // WHILE tested in caller.
2115        next();
2116
2117        final ParserContextLoopNode whileNode = new ParserContextLoopNode();
2118        lc.push(whileNode);
2119
2120        JoinPredecessorExpression test = null;
2121        Block body = null;
2122
2123        try {
2124            expect(LPAREN);
2125            test = joinPredecessorExpression();
2126            expect(RPAREN);
2127            body = getStatement();
2128        } finally {
2129            lc.pop(whileNode);
2130        }
2131
2132        if (body != null) {
2133            appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
2134        }
2135    }
2136
2137    /**
2138     * ...IterationStatement :
2139     *           ...
2140     *           do Statement while( Expression ) ;
2141     *           ...
2142     *
2143     * See 12.6
2144     *
2145     * Parse DO WHILE statement.
2146     */
2147    private void doStatement() {
2148        // Capture DO token.
2149        final long doToken = token;
2150        int doLine = 0;
2151        // DO tested in the caller.
2152        next();
2153
2154        final ParserContextLoopNode doWhileNode = new ParserContextLoopNode();
2155        lc.push(doWhileNode);
2156
2157        Block body = null;
2158        JoinPredecessorExpression test = null;
2159
2160        try {
2161           // Get DO body.
2162            body = getStatement();
2163
2164            expect(WHILE);
2165            expect(LPAREN);
2166            doLine = line;
2167            test = joinPredecessorExpression();
2168            expect(RPAREN);
2169
2170            if (type == SEMICOLON) {
2171                endOfLine();
2172            }
2173        } finally {
2174            lc.pop(doWhileNode);
2175        }
2176
2177        appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
2178    }
2179
2180    /**
2181     * ContinueStatement :
2182     *      continue Identifier? ; // [no LineTerminator here]
2183     *
2184     * See 12.7
2185     *
2186     * Parse CONTINUE statement.
2187     */
2188    private void continueStatement() {
2189        // Capture CONTINUE token.
2190        final int  continueLine  = line;
2191        final long continueToken = token;
2192        // CONTINUE tested in caller.
2193        nextOrEOL();
2194
2195        ParserContextLabelNode labelNode = null;
2196
2197        // SEMICOLON or label.
2198        switch (type) {
2199        case RBRACE:
2200        case SEMICOLON:
2201        case EOL:
2202        case EOF:
2203            break;
2204
2205        default:
2206            final IdentNode ident = getIdent();
2207            labelNode = lc.findLabel(ident.getName());
2208
2209            if (labelNode == null) {
2210                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
2211            }
2212
2213            break;
2214        }
2215
2216        final String labelName = labelNode == null ? null : labelNode.getLabelName();
2217        final ParserContextLoopNode targetNode = lc.getContinueTo(labelName);
2218
2219        if (targetNode == null) {
2220            throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
2221        }
2222
2223        endOfLine();
2224
2225        // Construct and add CONTINUE node.
2226        appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName));
2227    }
2228
2229    /**
2230     * BreakStatement :
2231     *      break Identifier? ; // [no LineTerminator here]
2232     *
2233     * See 12.8
2234     *
2235     */
2236    private void breakStatement() {
2237        // Capture BREAK token.
2238        final int  breakLine  = line;
2239        final long breakToken = token;
2240        // BREAK tested in caller.
2241        nextOrEOL();
2242
2243        ParserContextLabelNode labelNode = null;
2244
2245        // SEMICOLON or label.
2246        switch (type) {
2247        case RBRACE:
2248        case SEMICOLON:
2249        case EOL:
2250        case EOF:
2251            break;
2252
2253        default:
2254            final IdentNode ident = getIdent();
2255            labelNode = lc.findLabel(ident.getName());
2256
2257            if (labelNode == null) {
2258                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
2259            }
2260
2261            break;
2262        }
2263
2264        //either an explicit label - then get its node or just a "break" - get first breakable
2265        //targetNode is what we are breaking out from.
2266        final String labelName = labelNode == null ? null : labelNode.getLabelName();
2267        final ParserContextBreakableNode targetNode = lc.getBreakable(labelName);
2268        if (targetNode == null) {
2269            throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
2270        }
2271
2272        endOfLine();
2273
2274        // Construct and add BREAK node.
2275        appendStatement(new BreakNode(breakLine, breakToken, finish, labelName));
2276    }
2277
2278    /**
2279     * ReturnStatement :
2280     *      return Expression? ; // [no LineTerminator here]
2281     *
2282     * See 12.9
2283     *
2284     * Parse RETURN statement.
2285     */
2286    private void returnStatement() {
2287        // check for return outside function
2288        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) {
2289            throw error(AbstractParser.message("invalid.return"));
2290        }
2291
2292        // Capture RETURN token.
2293        final int  returnLine  = line;
2294        final long returnToken = token;
2295        // RETURN tested in caller.
2296        nextOrEOL();
2297
2298        Expression expression = null;
2299
2300        // SEMICOLON or expression.
2301        switch (type) {
2302        case RBRACE:
2303        case SEMICOLON:
2304        case EOL:
2305        case EOF:
2306            break;
2307
2308        default:
2309            expression = expression();
2310            break;
2311        }
2312
2313        endOfLine();
2314
2315        // Construct and add RETURN node.
2316        appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
2317    }
2318
2319    /**
2320     * Parse YieldExpression.
2321     *
2322     * YieldExpression[In] :
2323     *   yield
2324     *   yield [no LineTerminator here] AssignmentExpression[?In, Yield]
2325     *   yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
2326     */
2327    @SuppressWarnings("fallthrough")
2328    private Expression yieldExpression(final boolean noIn) {
2329        assert inGeneratorFunction();
2330        // Capture YIELD token.
2331        long yieldToken = token;
2332        // YIELD tested in caller.
2333        assert type == YIELD;
2334        nextOrEOL();
2335
2336        Expression expression = null;
2337
2338        boolean yieldAsterisk = false;
2339        if (type == MUL) {
2340            yieldAsterisk = true;
2341            yieldToken = Token.recast(yieldToken, YIELD_STAR);
2342            next();
2343        }
2344
2345        switch (type) {
2346        case RBRACE:
2347        case SEMICOLON:
2348        case EOL:
2349        case EOF:
2350        case COMMARIGHT:
2351        case RPAREN:
2352        case RBRACKET:
2353        case COLON:
2354            if (!yieldAsterisk) {
2355                // treat (yield) as (yield void 0)
2356                expression = newUndefinedLiteral(yieldToken, finish);
2357                if (type == EOL) {
2358                    next();
2359                }
2360                break;
2361            } else {
2362                // AssignmentExpression required, fall through
2363            }
2364
2365        default:
2366            expression = assignmentExpression(noIn);
2367            break;
2368        }
2369
2370        // Construct and add YIELD node.
2371        return new UnaryNode(yieldToken, expression);
2372    }
2373
2374    private static UnaryNode newUndefinedLiteral(final long token, final int finish) {
2375        return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0));
2376    }
2377
2378    /**
2379     * WithStatement :
2380     *      with ( Expression ) Statement
2381     *
2382     * See 12.10
2383     *
2384     * Parse WITH statement.
2385     */
2386    private void withStatement() {
2387        // Capture WITH token.
2388        final int  withLine  = line;
2389        final long withToken = token;
2390        // WITH tested in caller.
2391        next();
2392
2393        // ECMA 12.10.1 strict mode restrictions
2394        if (isStrictMode) {
2395            throw error(AbstractParser.message("strict.no.with"), withToken);
2396        }
2397
2398        expect(LPAREN);
2399        final Expression expression = expression();
2400        expect(RPAREN);
2401        final Block body = getStatement();
2402
2403        appendStatement(new WithNode(withLine, withToken, finish, expression, body));
2404    }
2405
2406    /**
2407     * SwitchStatement :
2408     *      switch ( Expression ) CaseBlock
2409     *
2410     * CaseBlock :
2411     *      { CaseClauses? }
2412     *      { CaseClauses? DefaultClause CaseClauses }
2413     *
2414     * CaseClauses :
2415     *      CaseClause
2416     *      CaseClauses CaseClause
2417     *
2418     * CaseClause :
2419     *      case Expression : StatementList?
2420     *
2421     * DefaultClause :
2422     *      default : StatementList?
2423     *
2424     * See 12.11
2425     *
2426     * Parse SWITCH statement.
2427     */
2428    private void switchStatement() {
2429        final int  switchLine  = line;
2430        final long switchToken = token;
2431
2432        // Block to capture variables declared inside the switch statement.
2433        final ParserContextBlockNode switchBlock = newBlock();
2434
2435        // SWITCH tested in caller.
2436        next();
2437
2438        // Create and add switch statement.
2439        final ParserContextSwitchNode switchNode = new ParserContextSwitchNode();
2440        lc.push(switchNode);
2441
2442        CaseNode defaultCase = null;
2443        // Prepare to accumulate cases.
2444        final List<CaseNode> cases = new ArrayList<>();
2445
2446        Expression expression = null;
2447
2448        try {
2449            expect(LPAREN);
2450            expression = expression();
2451            expect(RPAREN);
2452
2453            expect(LBRACE);
2454
2455
2456            while (type != RBRACE) {
2457                // Prepare for next case.
2458                Expression caseExpression = null;
2459                final long caseToken = token;
2460
2461                switch (type) {
2462                case CASE:
2463                    next();
2464                    caseExpression = expression();
2465                    break;
2466
2467                case DEFAULT:
2468                    if (defaultCase != null) {
2469                        throw error(AbstractParser.message("duplicate.default.in.switch"));
2470                    }
2471                    next();
2472                    break;
2473
2474                default:
2475                    // Force an error.
2476                    expect(CASE);
2477                    break;
2478                }
2479
2480                expect(COLON);
2481
2482                // Get CASE body.
2483                final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList();
2484                final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
2485
2486                if (caseExpression == null) {
2487                    defaultCase = caseNode;
2488                }
2489
2490                cases.add(caseNode);
2491            }
2492
2493            next();
2494        } finally {
2495            lc.pop(switchNode);
2496            restoreBlock(switchBlock);
2497        }
2498
2499        final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase);
2500        appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement)));
2501    }
2502
2503    /**
2504     * LabelledStatement :
2505     *      Identifier : Statement
2506     *
2507     * See 12.12
2508     *
2509     * Parse label statement.
2510     */
2511    private void labelStatement() {
2512        // Capture label token.
2513        final long labelToken = token;
2514        // Get label ident.
2515        final IdentNode ident = getIdent();
2516
2517        expect(COLON);
2518
2519        if (lc.findLabel(ident.getName()) != null) {
2520            throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
2521        }
2522
2523        final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName());
2524        Block body = null;
2525        try {
2526            lc.push(labelNode);
2527            body = getStatement(true);
2528        } finally {
2529            assert lc.peek() instanceof ParserContextLabelNode;
2530            lc.pop(labelNode);
2531        }
2532
2533        appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
2534    }
2535
2536    /**
2537     * ThrowStatement :
2538     *      throw Expression ; // [no LineTerminator here]
2539     *
2540     * See 12.13
2541     *
2542     * Parse throw statement.
2543     */
2544    private void throwStatement() {
2545        // Capture THROW token.
2546        final int  throwLine  = line;
2547        final long throwToken = token;
2548        // THROW tested in caller.
2549        nextOrEOL();
2550
2551        Expression expression = null;
2552
2553        // SEMICOLON or expression.
2554        switch (type) {
2555        case RBRACE:
2556        case SEMICOLON:
2557        case EOL:
2558            break;
2559
2560        default:
2561            expression = expression();
2562            break;
2563        }
2564
2565        if (expression == null) {
2566            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2567        }
2568
2569        endOfLine();
2570
2571        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false));
2572    }
2573
2574    /**
2575     * TryStatement :
2576     *      try Block Catch
2577     *      try Block Finally
2578     *      try Block Catch Finally
2579     *
2580     * Catch :
2581     *      catch( Identifier if Expression ) Block
2582     *      catch( Identifier ) Block
2583     *
2584     * Finally :
2585     *      finally Block
2586     *
2587     * See 12.14
2588     *
2589     * Parse TRY statement.
2590     */
2591    private void tryStatement() {
2592        // Capture TRY token.
2593        final int  tryLine  = line;
2594        final long tryToken = token;
2595        // TRY tested in caller.
2596        next();
2597
2598        // Container block needed to act as target for labeled break statements
2599        final int startLine = line;
2600        final ParserContextBlockNode outer = newBlock();
2601        // Create try.
2602
2603        try {
2604            final Block       tryBody     = getBlock(true);
2605            final List<Block> catchBlocks = new ArrayList<>();
2606
2607            while (type == CATCH) {
2608                final int  catchLine  = line;
2609                final long catchToken = token;
2610                next();
2611                expect(LPAREN);
2612                final IdentNode exception = getIdent();
2613
2614                // ECMA 12.4.1 strict mode restrictions
2615                verifyStrictIdent(exception, "catch argument");
2616
2617                // Nashorn extension: catch clause can have optional
2618                // condition. So, a single try can have more than one
2619                // catch clause each with it's own condition.
2620                final Expression ifExpression;
2621                if (!env._no_syntax_extensions && type == IF) {
2622                    next();
2623                    // Get the exception condition.
2624                    ifExpression = expression();
2625                } else {
2626                    ifExpression = null;
2627                }
2628
2629                expect(RPAREN);
2630
2631                final ParserContextBlockNode catchBlock = newBlock();
2632                try {
2633                    // Get CATCH body.
2634                    final Block catchBody = getBlock(true);
2635                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
2636                    appendStatement(catchNode);
2637                } finally {
2638                    restoreBlock(catchBlock);
2639                    catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags() | Block.IS_SYNTHETIC, catchBlock.getStatements()));
2640                }
2641
2642                // If unconditional catch then should to be the end.
2643                if (ifExpression == null) {
2644                    break;
2645                }
2646            }
2647
2648            // Prepare to capture finally statement.
2649            Block finallyStatements = null;
2650
2651            if (type == FINALLY) {
2652                next();
2653                finallyStatements = getBlock(true);
2654            }
2655
2656            // Need at least one catch or a finally.
2657            if (catchBlocks.isEmpty() && finallyStatements == null) {
2658                throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
2659            }
2660
2661            final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements);
2662            // Add try.
2663            assert lc.peek() == outer;
2664            appendStatement(tryNode);
2665        } finally {
2666            restoreBlock(outer);
2667        }
2668
2669        appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags() | Block.IS_SYNTHETIC, outer.getStatements())));
2670    }
2671
2672    /**
2673     * DebuggerStatement :
2674     *      debugger ;
2675     *
2676     * See 12.15
2677     *
2678     * Parse debugger statement.
2679     */
2680    private void  debuggerStatement() {
2681        // Capture DEBUGGER token.
2682        final int  debuggerLine  = line;
2683        final long debuggerToken = token;
2684        // DEBUGGER tested in caller.
2685        next();
2686        endOfLine();
2687        appendStatement(new DebuggerNode(debuggerLine, debuggerToken, finish));
2688    }
2689
2690    /**
2691     * PrimaryExpression :
2692     *      this
2693     *      IdentifierReference
2694     *      Literal
2695     *      ArrayLiteral
2696     *      ObjectLiteral
2697     *      RegularExpressionLiteral
2698     *      TemplateLiteral
2699     *      CoverParenthesizedExpressionAndArrowParameterList
2700     *
2701     * CoverParenthesizedExpressionAndArrowParameterList :
2702     *      ( Expression )
2703     *      ( )
2704     *      ( ... BindingIdentifier )
2705     *      ( Expression , ... BindingIdentifier )
2706     *
2707     * Parse primary expression.
2708     * @return Expression node.
2709     */
2710    @SuppressWarnings("fallthrough")
2711    private Expression primaryExpression() {
2712        // Capture first token.
2713        final int  primaryLine  = line;
2714        final long primaryToken = token;
2715
2716        switch (type) {
2717        case THIS:
2718            final String name = type.getName();
2719            next();
2720            markThis(lc);
2721            return new IdentNode(primaryToken, finish, name);
2722        case IDENT:
2723            final IdentNode ident = getIdent();
2724            if (ident == null) {
2725                break;
2726            }
2727            detectSpecialProperty(ident);
2728            return ident;
2729        case OCTAL_LEGACY:
2730            if (isStrictMode) {
2731               throw error(AbstractParser.message("strict.no.octal"), token);
2732            }
2733        case STRING:
2734        case ESCSTRING:
2735        case DECIMAL:
2736        case HEXADECIMAL:
2737        case OCTAL:
2738        case BINARY_NUMBER:
2739        case FLOATING:
2740        case REGEX:
2741        case XML:
2742            return getLiteral();
2743        case EXECSTRING:
2744            return execString(primaryLine, primaryToken);
2745        case FALSE:
2746            next();
2747            return LiteralNode.newInstance(primaryToken, finish, false);
2748        case TRUE:
2749            next();
2750            return LiteralNode.newInstance(primaryToken, finish, true);
2751        case NULL:
2752            next();
2753            return LiteralNode.newInstance(primaryToken, finish);
2754        case LBRACKET:
2755            return arrayLiteral();
2756        case LBRACE:
2757            return objectLiteral();
2758        case LPAREN:
2759            next();
2760
2761            if (isES6()) {
2762                if (type == RPAREN) {
2763                    // ()
2764                    nextOrEOL();
2765                    expectDontAdvance(ARROW);
2766                    return new ExpressionList(primaryToken, finish, Collections.emptyList());
2767                } else if (type == ELLIPSIS) {
2768                    // (...rest)
2769                    final IdentNode restParam = formalParameterList(false).get(0);
2770                    expectDontAdvance(RPAREN);
2771                    nextOrEOL();
2772                    expectDontAdvance(ARROW);
2773                    return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam));
2774                }
2775            }
2776
2777            final Expression expression = expression();
2778
2779            expect(RPAREN);
2780
2781            return expression;
2782        case TEMPLATE:
2783        case TEMPLATE_HEAD:
2784            return templateLiteral();
2785
2786        default:
2787            // In this context some operator tokens mark the start of a literal.
2788            if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) {
2789                next();
2790                return getLiteral();
2791            }
2792            if (isNonStrictModeIdent()) {
2793                return getIdent();
2794            }
2795            break;
2796        }
2797
2798        return null;
2799    }
2800
2801    /**
2802     * Convert execString to a call to $EXEC.
2803     *
2804     * @param primaryToken Original string token.
2805     * @return callNode to $EXEC.
2806     */
2807    CallNode execString(final int primaryLine, final long primaryToken) {
2808        // Synthesize an ident to call $EXEC.
2809        final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
2810        // Skip over EXECSTRING.
2811        next();
2812        // Set up argument list for call.
2813        // Skip beginning of edit string expression.
2814        expect(LBRACE);
2815        // Add the following expression to arguments.
2816        final List<Expression> arguments = Collections.singletonList(expression());
2817        // Skip ending of edit string expression.
2818        expect(RBRACE);
2819
2820        return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false);
2821    }
2822
2823    /**
2824     * ArrayLiteral :
2825     *      [ Elision? ]
2826     *      [ ElementList ]
2827     *      [ ElementList , Elision? ]
2828     *      [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ]
2829     *
2830     * ElementList : Elision? AssignmentExpression
2831     *      ElementList , Elision? AssignmentExpression
2832     *
2833     * Elision :
2834     *      ,
2835     *      Elision ,
2836     *
2837     * See 12.1.4
2838     * JavaScript 1.8
2839     *
2840     * Parse array literal.
2841     * @return Expression node.
2842     */
2843    @SuppressWarnings("fallthrough")
2844    private LiteralNode<Expression[]> arrayLiteral() {
2845        // Capture LBRACKET token.
2846        final long arrayToken = token;
2847        // LBRACKET tested in caller.
2848        next();
2849
2850        // Prepare to accumulate elements.
2851        final List<Expression> elements = new ArrayList<>();
2852        // Track elisions.
2853        boolean elision = true;
2854        loop:
2855        while (true) {
2856            long spreadToken = 0;
2857            switch (type) {
2858            case RBRACKET:
2859                next();
2860
2861                break loop;
2862
2863            case COMMARIGHT:
2864                next();
2865
2866                // If no prior expression
2867                if (elision) {
2868                    elements.add(null);
2869                }
2870
2871                elision = true;
2872
2873                break;
2874
2875            case ELLIPSIS:
2876                if (isES6()) {
2877                    spreadToken = token;
2878                    next();
2879                }
2880                // fall through
2881
2882            default:
2883                if (!elision) {
2884                    throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2885                }
2886
2887                // Add expression element.
2888                Expression expression = assignmentExpression(false);
2889                if (expression != null) {
2890                    if (spreadToken != 0) {
2891                        expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression);
2892                    }
2893                    elements.add(expression);
2894                } else {
2895                    expect(RBRACKET);
2896                }
2897
2898                elision = false;
2899                break;
2900            }
2901        }
2902
2903        return LiteralNode.newInstance(arrayToken, finish, elements);
2904    }
2905
2906    /**
2907     * ObjectLiteral :
2908     *      { }
2909     *      { PropertyNameAndValueList } { PropertyNameAndValueList , }
2910     *
2911     * PropertyNameAndValueList :
2912     *      PropertyAssignment
2913     *      PropertyNameAndValueList , PropertyAssignment
2914     *
2915     * See 11.1.5
2916     *
2917     * Parse an object literal.
2918     * @return Expression node.
2919     */
2920    private ObjectNode objectLiteral() {
2921        // Capture LBRACE token.
2922        final long objectToken = token;
2923        // LBRACE tested in caller.
2924        next();
2925
2926        // Object context.
2927        // Prepare to accumulate elements.
2928        final List<PropertyNode> elements = new ArrayList<>();
2929        final Map<String, Integer> map = new HashMap<>();
2930
2931        // Create a block for the object literal.
2932        boolean commaSeen = true;
2933        loop:
2934        while (true) {
2935            switch (type) {
2936                case RBRACE:
2937                    next();
2938                    break loop;
2939
2940                case COMMARIGHT:
2941                    if (commaSeen) {
2942                        throw error(AbstractParser.message("expected.property.id", type.getNameOrType()));
2943                    }
2944                    next();
2945                    commaSeen = true;
2946                    break;
2947
2948                default:
2949                    if (!commaSeen) {
2950                        throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2951                    }
2952
2953                    commaSeen = false;
2954                    // Get and add the next property.
2955                    final PropertyNode property = propertyAssignment();
2956
2957                    if (property.isComputed()) {
2958                        elements.add(property);
2959                        break;
2960                    }
2961
2962                    final String key = property.getKeyName();
2963                    final Integer existing = map.get(key);
2964
2965                    if (existing == null) {
2966                        map.put(key, elements.size());
2967                        elements.add(property);
2968                        break;
2969                    }
2970
2971                    final PropertyNode existingProperty = elements.get(existing);
2972
2973                    // ECMA section 11.1.5 Object Initialiser
2974                    // point # 4 on property assignment production
2975                    final Expression   value  = property.getValue();
2976                    final FunctionNode getter = property.getGetter();
2977                    final FunctionNode setter = property.getSetter();
2978
2979                    final Expression   prevValue  = existingProperty.getValue();
2980                    final FunctionNode prevGetter = existingProperty.getGetter();
2981                    final FunctionNode prevSetter = existingProperty.getSetter();
2982
2983                    if (!isES6()) {
2984                        checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter);
2985                    } else {
2986                        if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() &&
2987                                        existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) {
2988                            throw error(AbstractParser.message("multiple.proto.key"), property.getToken());
2989                        }
2990                    }
2991
2992                    if (value != null || prevValue != null) {
2993                        map.put(key, elements.size());
2994                        elements.add(property);
2995                    } else if (getter != null) {
2996                        assert prevGetter != null || prevSetter != null;
2997                        elements.set(existing, existingProperty.setGetter(getter));
2998                    } else if (setter != null) {
2999                        assert prevGetter != null || prevSetter != null;
3000                        elements.set(existing, existingProperty.setSetter(setter));
3001                    }
3002                    break;
3003            }
3004        }
3005
3006        return new ObjectNode(objectToken, finish, elements);
3007    }
3008
3009    private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) {
3010        // ECMA 11.1.5 strict mode restrictions
3011        if (isStrictMode && value != null && prevValue != null) {
3012            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3013        }
3014
3015        final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
3016        final boolean isAccessor     = getter != null     || setter != null;
3017
3018        // data property redefined as accessor property
3019        if (prevValue != null && isAccessor) {
3020            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3021        }
3022
3023        // accessor property redefined as data
3024        if (isPrevAccessor && value != null) {
3025            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3026        }
3027
3028        if (isAccessor && isPrevAccessor) {
3029            if (getter != null && prevGetter != null ||
3030                    setter != null && prevSetter != null) {
3031                throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3032            }
3033        }
3034    }
3035
3036    /**
3037     * LiteralPropertyName :
3038     *      IdentifierName
3039     *      StringLiteral
3040     *      NumericLiteral
3041     *
3042     * @return PropertyName node
3043     */
3044    @SuppressWarnings("fallthrough")
3045    private PropertyKey literalPropertyName() {
3046        switch (type) {
3047        case IDENT:
3048            return getIdent().setIsPropertyName();
3049        case OCTAL_LEGACY:
3050            if (isStrictMode) {
3051                throw error(AbstractParser.message("strict.no.octal"), token);
3052            }
3053        case STRING:
3054        case ESCSTRING:
3055        case DECIMAL:
3056        case HEXADECIMAL:
3057        case OCTAL:
3058        case BINARY_NUMBER:
3059        case FLOATING:
3060            return getLiteral();
3061        default:
3062            return getIdentifierName().setIsPropertyName();
3063        }
3064    }
3065
3066    /**
3067     * ComputedPropertyName :
3068     *      AssignmentExpression
3069     *
3070     * @return PropertyName node
3071     */
3072    private Expression computedPropertyName() {
3073        expect(LBRACKET);
3074        Expression expression = assignmentExpression(false);
3075        expect(RBRACKET);
3076        return expression;
3077    }
3078
3079    /**
3080     * PropertyName :
3081     *      LiteralPropertyName
3082     *      ComputedPropertyName
3083     *
3084     * @return PropertyName node
3085     */
3086    private Expression propertyName() {
3087        if (type == LBRACKET && isES6()) {
3088            return computedPropertyName();
3089        } else {
3090            return (Expression)literalPropertyName();
3091        }
3092    }
3093
3094    /**
3095     * PropertyAssignment :
3096     *      PropertyName : AssignmentExpression
3097     *      get PropertyName ( ) { FunctionBody }
3098     *      set PropertyName ( PropertySetParameterList ) { FunctionBody }
3099     *
3100     * PropertySetParameterList :
3101     *      Identifier
3102     *
3103     * PropertyName :
3104     *      IdentifierName
3105     *      StringLiteral
3106     *      NumericLiteral
3107     *
3108     * See 11.1.5
3109     *
3110     * Parse an object literal property.
3111     * @return Property or reference node.
3112     */
3113    private PropertyNode propertyAssignment() {
3114        // Capture firstToken.
3115        final long propertyToken = token;
3116        final int  functionLine  = line;
3117
3118        final Expression propertyName;
3119        final boolean isIdentifier;
3120
3121        boolean generator = false;
3122        if (type == MUL && isES6()) {
3123            generator = true;
3124            next();
3125        }
3126
3127        final boolean computed = type == LBRACKET;
3128        if (type == IDENT) {
3129            // Get IDENT.
3130            final String ident = (String)expectValue(IDENT);
3131
3132            if (type != COLON && (type != LPAREN || !isES6())) {
3133                final long getSetToken = propertyToken;
3134
3135                switch (ident) {
3136                case "get":
3137                    final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine);
3138                    return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed);
3139
3140                case "set":
3141                    final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine);
3142                    return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed);
3143                default:
3144                    break;
3145                }
3146            }
3147
3148            isIdentifier = true;
3149            IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
3150            if (type == COLON && ident.equals("__proto__")) {
3151                identNode = identNode.setIsProtoPropertyName();
3152            }
3153            propertyName = identNode;
3154        } else {
3155            isIdentifier = isNonStrictModeIdent();
3156            propertyName = propertyName();
3157        }
3158
3159        Expression propertyValue;
3160
3161        if (generator) {
3162            expectDontAdvance(LPAREN);
3163        }
3164
3165        if (type == LPAREN && isES6()) {
3166            propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode;
3167        } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) {
3168            propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName());
3169            if (type == ASSIGN && isES6()) {
3170                // TODO if not destructuring, this is a SyntaxError
3171                final long assignToken = token;
3172                next();
3173                final Expression rhs = assignmentExpression(false);
3174                propertyValue = verifyAssignment(assignToken, propertyValue, rhs);
3175            }
3176        } else {
3177            expect(COLON);
3178
3179            defaultNames.push(propertyName);
3180            try {
3181                propertyValue = assignmentExpression(false);
3182            } finally {
3183                defaultNames.pop();
3184            }
3185        }
3186
3187        return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed);
3188    }
3189
3190    private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) {
3191        return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
3192    }
3193
3194    private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) {
3195        final boolean computed = type == LBRACKET;
3196        final Expression propertyName = propertyName();
3197        final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
3198        final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName));
3199        expect(LPAREN);
3200        expect(RPAREN);
3201
3202        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
3203        functionNode.setFlag(flags);
3204        if (computed) {
3205            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3206        }
3207        lc.push(functionNode);
3208
3209        Block functionBody;
3210
3211
3212        try {
3213            functionBody = functionBody(functionNode);
3214        } finally {
3215            lc.pop(functionNode);
3216        }
3217
3218        final FunctionNode  function = createFunctionNode(
3219                functionNode,
3220                getSetToken,
3221                getNameNode,
3222                Collections.<IdentNode>emptyList(),
3223                FunctionNode.Kind.GETTER,
3224                functionLine,
3225                functionBody);
3226
3227        return new PropertyFunction(propertyName, function, computed);
3228    }
3229
3230    private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
3231        return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
3232    }
3233
3234    private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) {
3235        final boolean computed = type == LBRACKET;
3236        final Expression propertyName = propertyName();
3237        final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
3238        final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName));
3239        expect(LPAREN);
3240        // be sloppy and allow missing setter parameter even though
3241        // spec does not permit it!
3242        final IdentNode argIdent;
3243        if (isBindingIdentifier()) {
3244            argIdent = getIdent();
3245            verifyIdent(argIdent, "setter argument");
3246        } else {
3247            argIdent = null;
3248        }
3249        expect(RPAREN);
3250        final List<IdentNode> parameters = new ArrayList<>();
3251        if (argIdent != null) {
3252            parameters.add(argIdent);
3253        }
3254
3255
3256        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
3257        functionNode.setFlag(flags);
3258        if (computed) {
3259            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3260        }
3261        lc.push(functionNode);
3262
3263        Block functionBody;
3264        try {
3265            functionBody = functionBody(functionNode);
3266        } finally {
3267            lc.pop(functionNode);
3268        }
3269
3270
3271        final FunctionNode  function = createFunctionNode(
3272                functionNode,
3273                getSetToken,
3274                setNameNode,
3275                parameters,
3276                FunctionNode.Kind.SETTER,
3277                functionLine,
3278                functionBody);
3279
3280        return new PropertyFunction(propertyName, function, computed);
3281    }
3282
3283    private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) {
3284        final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false);
3285        final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName);
3286
3287        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
3288        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null);
3289        functionNode.setFlag(flags);
3290        if (computed) {
3291            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3292        }
3293        lc.push(functionNode);
3294
3295        try {
3296            final ParserContextBlockNode parameterBlock = newBlock();
3297            final List<IdentNode> parameters;
3298            try {
3299                expect(LPAREN);
3300                parameters = formalParameterList(generator);
3301                functionNode.setParameters(parameters);
3302                expect(RPAREN);
3303            } finally {
3304                restoreBlock(parameterBlock);
3305            }
3306
3307            Block functionBody = functionBody(functionNode);
3308
3309            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
3310
3311            final FunctionNode  function = createFunctionNode(
3312                            functionNode,
3313                            methodToken,
3314                            methodNameNode,
3315                            parameters,
3316                            functionKind,
3317                            methodLine,
3318                            functionBody);
3319            return new PropertyFunction(key, function, computed);
3320        } finally {
3321            lc.pop(functionNode);
3322        }
3323    }
3324
3325    private static class PropertyFunction {
3326        final Expression key;
3327        final FunctionNode functionNode;
3328        final boolean computed;
3329
3330        PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) {
3331            this.key = key;
3332            this.functionNode = function;
3333            this.computed = computed;
3334        }
3335    }
3336
3337    /**
3338     * LeftHandSideExpression :
3339     *      NewExpression
3340     *      CallExpression
3341     *
3342     * CallExpression :
3343     *      MemberExpression Arguments
3344     *      SuperCall
3345     *      CallExpression Arguments
3346     *      CallExpression [ Expression ]
3347     *      CallExpression . IdentifierName
3348     *
3349     * SuperCall :
3350     *      super Arguments
3351     *
3352     * See 11.2
3353     *
3354     * Parse left hand side expression.
3355     * @return Expression node.
3356     */
3357    private Expression leftHandSideExpression() {
3358        int  callLine  = line;
3359        long callToken = token;
3360
3361        Expression lhs = memberExpression();
3362
3363        if (type == LPAREN) {
3364            final List<Expression> arguments = optimizeList(argumentList());
3365
3366            // Catch special functions.
3367            if (lhs instanceof IdentNode) {
3368                detectSpecialFunction((IdentNode)lhs);
3369            }
3370
3371            lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3372        }
3373
3374        loop:
3375        while (true) {
3376            // Capture token.
3377            callLine  = line;
3378            callToken = token;
3379
3380            switch (type) {
3381            case LPAREN: {
3382                // Get NEW or FUNCTION arguments.
3383                final List<Expression> arguments = optimizeList(argumentList());
3384
3385                // Create call node.
3386                lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3387
3388                break;
3389            }
3390            case LBRACKET: {
3391                next();
3392
3393                // Get array index.
3394                final Expression rhs = expression();
3395
3396                expect(RBRACKET);
3397
3398                // Create indexing node.
3399                lhs = new IndexNode(callToken, finish, lhs, rhs);
3400
3401                break;
3402            }
3403            case PERIOD: {
3404                next();
3405
3406                final IdentNode property = getIdentifierName();
3407
3408                // Create property access node.
3409                lhs = new AccessNode(callToken, finish, lhs, property.getName());
3410
3411                break;
3412            }
3413            case TEMPLATE:
3414            case TEMPLATE_HEAD: {
3415                // tagged template literal
3416                final List<Expression> arguments = templateLiteralArgumentList();
3417
3418                // Create call node.
3419                lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3420
3421                break;
3422            }
3423            default:
3424                break loop;
3425            }
3426        }
3427
3428        return lhs;
3429    }
3430
3431    /**
3432     * NewExpression :
3433     *      MemberExpression
3434     *      new NewExpression
3435     *
3436     * See 11.2
3437     *
3438     * Parse new expression.
3439     * @return Expression node.
3440     */
3441    private Expression newExpression() {
3442        final long newToken = token;
3443        // NEW is tested in caller.
3444        next();
3445
3446        if (type == PERIOD && isES6()) {
3447            next();
3448            if (type == IDENT && "target".equals(getValue())) {
3449                if (lc.getCurrentFunction().isProgram()) {
3450                    throw error(AbstractParser.message("new.target.in.function"), token);
3451                }
3452                next();
3453                markNewTarget(lc);
3454                return new IdentNode(newToken, finish, "new.target");
3455            } else {
3456                throw error(AbstractParser.message("expected.target"), token);
3457            }
3458        }
3459
3460        // Get function base.
3461        final int  callLine    = line;
3462        final Expression constructor = memberExpression();
3463        if (constructor == null) {
3464            return null;
3465        }
3466        // Get arguments.
3467        ArrayList<Expression> arguments;
3468
3469        // Allow for missing arguments.
3470        if (type == LPAREN) {
3471            arguments = argumentList();
3472        } else {
3473            arguments = new ArrayList<>();
3474        }
3475
3476        // Nashorn extension: This is to support the following interface implementation
3477        // syntax:
3478        //
3479        //     var r = new java.lang.Runnable() {
3480        //         run: function() { println("run"); }
3481        //     };
3482        //
3483        // The object literal following the "new Constructor()" expression
3484        // is passed as an additional (last) argument to the constructor.
3485        if (!env._no_syntax_extensions && type == LBRACE) {
3486            arguments.add(objectLiteral());
3487        }
3488
3489        final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true);
3490
3491        return new UnaryNode(newToken, callNode);
3492    }
3493
3494    /**
3495     * MemberExpression :
3496     *      PrimaryExpression
3497     *        FunctionExpression
3498     *        ClassExpression
3499     *        GeneratorExpression
3500     *      MemberExpression [ Expression ]
3501     *      MemberExpression . IdentifierName
3502     *      MemberExpression TemplateLiteral
3503     *      SuperProperty
3504     *      MetaProperty
3505     *      new MemberExpression Arguments
3506     *
3507     * SuperProperty :
3508     *      super [ Expression ]
3509     *      super . IdentifierName
3510     *
3511     * MetaProperty :
3512     *      NewTarget
3513     *
3514     * Parse member expression.
3515     * @return Expression node.
3516     */
3517    @SuppressWarnings("fallthrough")
3518    private Expression memberExpression() {
3519        // Prepare to build operation.
3520        Expression lhs;
3521        boolean isSuper = false;
3522
3523        switch (type) {
3524        case NEW:
3525            // Get new expression.
3526            lhs = newExpression();
3527            break;
3528
3529        case FUNCTION:
3530            // Get function expression.
3531            lhs = functionExpression(false, false);
3532            break;
3533
3534        case CLASS:
3535            if (isES6()) {
3536                lhs = classExpression(false);
3537                break;
3538            } else {
3539                // fall through
3540            }
3541
3542        case SUPER:
3543            if (isES6()) {
3544                final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction();
3545                if (currentFunction.isMethod()) {
3546                    long identToken = Token.recast(token, IDENT);
3547                    next();
3548                    lhs = createIdentNode(identToken, finish, SUPER.getName());
3549
3550                    switch (type) {
3551                        case LBRACKET:
3552                        case PERIOD:
3553                            getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER);
3554                            isSuper = true;
3555                            break;
3556                        case LPAREN:
3557                            if (currentFunction.isSubclassConstructor()) {
3558                                lhs = ((IdentNode)lhs).setIsDirectSuper();
3559                                break;
3560                            } else {
3561                                // fall through to throw error
3562                            }
3563                        default:
3564                            throw error(AbstractParser.message("invalid.super"), identToken);
3565                    }
3566                    break;
3567                } else {
3568                    // fall through
3569                }
3570            } else {
3571                // fall through
3572            }
3573
3574        default:
3575            // Get primary expression.
3576            lhs = primaryExpression();
3577            break;
3578        }
3579
3580        loop:
3581        while (true) {
3582            // Capture token.
3583            final long callToken = token;
3584
3585            switch (type) {
3586            case LBRACKET: {
3587                next();
3588
3589                // Get array index.
3590                final Expression index = expression();
3591
3592                expect(RBRACKET);
3593
3594                // Create indexing node.
3595                lhs = new IndexNode(callToken, finish, lhs, index);
3596
3597                if (isSuper) {
3598                    isSuper = false;
3599                    lhs = ((BaseNode) lhs).setIsSuper();
3600                }
3601
3602                break;
3603            }
3604            case PERIOD: {
3605                if (lhs == null) {
3606                    throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
3607                }
3608
3609                next();
3610
3611                final IdentNode property = getIdentifierName();
3612
3613                // Create property access node.
3614                lhs = new AccessNode(callToken, finish, lhs, property.getName());
3615
3616                if (isSuper) {
3617                    isSuper = false;
3618                    lhs = ((BaseNode) lhs).setIsSuper();
3619                }
3620
3621                break;
3622            }
3623            case TEMPLATE:
3624            case TEMPLATE_HEAD: {
3625                // tagged template literal
3626                final int callLine = line;
3627                final List<Expression> arguments = templateLiteralArgumentList();
3628
3629                lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3630
3631                break;
3632            }
3633            default:
3634                break loop;
3635            }
3636        }
3637
3638        return lhs;
3639    }
3640
3641    /**
3642     * Arguments :
3643     *      ( )
3644     *      ( ArgumentList )
3645     *
3646     * ArgumentList :
3647     *      AssignmentExpression
3648     *      ... AssignmentExpression
3649     *      ArgumentList , AssignmentExpression
3650     *      ArgumentList , ... AssignmentExpression
3651     *
3652     * See 11.2
3653     *
3654     * Parse function call arguments.
3655     * @return Argument list.
3656     */
3657    private ArrayList<Expression> argumentList() {
3658        // Prepare to accumulate list of arguments.
3659        final ArrayList<Expression> nodeList = new ArrayList<>();
3660        // LPAREN tested in caller.
3661        next();
3662
3663        // Track commas.
3664        boolean first = true;
3665
3666        while (type != RPAREN) {
3667            // Comma prior to every argument except the first.
3668            if (!first) {
3669                expect(COMMARIGHT);
3670            } else {
3671                first = false;
3672            }
3673
3674            long spreadToken = 0;
3675            if (type == ELLIPSIS && isES6()) {
3676                spreadToken = token;
3677                next();
3678            }
3679
3680            // Get argument expression.
3681            Expression expression = assignmentExpression(false);
3682            if (spreadToken != 0) {
3683                expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression);
3684            }
3685            nodeList.add(expression);
3686        }
3687
3688        expect(RPAREN);
3689        return nodeList;
3690    }
3691
3692    private static <T> List<T> optimizeList(final ArrayList<T> list) {
3693        switch(list.size()) {
3694            case 0: {
3695                return Collections.emptyList();
3696            }
3697            case 1: {
3698                return Collections.singletonList(list.get(0));
3699            }
3700            default: {
3701                list.trimToSize();
3702                return list;
3703            }
3704        }
3705    }
3706
3707    /**
3708     * FunctionDeclaration :
3709     *      function Identifier ( FormalParameterList? ) { FunctionBody }
3710     *
3711     * FunctionExpression :
3712     *      function Identifier? ( FormalParameterList? ) { FunctionBody }
3713     *
3714     * See 13
3715     *
3716     * Parse function declaration.
3717     * @param isStatement True if for is a statement.
3718     *
3719     * @return Expression node.
3720     */
3721    private Expression functionExpression(final boolean isStatement, final boolean topLevel) {
3722        final long functionToken = token;
3723        final int  functionLine  = line;
3724        // FUNCTION is tested in caller.
3725        assert type == FUNCTION;
3726        next();
3727
3728        boolean generator = false;
3729        if (type == MUL && isES6()) {
3730            generator = true;
3731            next();
3732        }
3733
3734        IdentNode name = null;
3735
3736        if (isBindingIdentifier()) {
3737            if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) {
3738                // 12.1.1 Early SyntaxError if:
3739                // GeneratorExpression with BindingIdentifier yield
3740                // HoistableDeclaration with BindingIdentifier yield in generator function body
3741                expect(IDENT);
3742            }
3743            name = getIdent();
3744            verifyStrictIdent(name, "function name");
3745        } else if (isStatement) {
3746            // Nashorn extension: anonymous function statements.
3747            // Do not allow anonymous function statement if extensions
3748            // are now allowed. But if we are reparsing then anon function
3749            // statement is possible - because it was used as function
3750            // expression in surrounding code.
3751            if (env._no_syntax_extensions && reparsedFunction == null) {
3752                expect(IDENT);
3753            }
3754        }
3755
3756        // name is null, generate anonymous name
3757        boolean isAnonymous = false;
3758        if (name == null) {
3759            final String tmpName = getDefaultValidFunctionName(functionLine, isStatement);
3760            name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
3761            isAnonymous = true;
3762        }
3763
3764        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
3765        List<IdentNode> parameters = Collections.emptyList();
3766        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters);
3767        lc.push(functionNode);
3768
3769        Block functionBody = null;
3770        // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}"
3771        // If we didn't hide the current default name, then the innermost anonymous function would receive "x3".
3772        hideDefaultName();
3773        try {
3774            final ParserContextBlockNode parameterBlock = newBlock();
3775            try {
3776                expect(LPAREN);
3777                parameters = formalParameterList(generator);
3778                functionNode.setParameters(parameters);
3779                expect(RPAREN);
3780            } finally {
3781                restoreBlock(parameterBlock);
3782            }
3783
3784            functionBody = functionBody(functionNode);
3785
3786            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
3787        } finally {
3788            defaultNames.pop();
3789            lc.pop(functionNode);
3790        }
3791
3792        if (isStatement) {
3793            if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) {
3794                functionNode.setFlag(FunctionNode.IS_DECLARED);
3795            } else if (isStrictMode) {
3796                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
3797            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
3798                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
3799            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
3800                warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
3801            }
3802            if (isArguments(name)) {
3803               lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS);
3804            }
3805        }
3806
3807        if (isAnonymous) {
3808            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3809        }
3810
3811        verifyParameterList(parameters, functionNode);
3812
3813        final FunctionNode function = createFunctionNode(
3814                functionNode,
3815                functionToken,
3816                name,
3817                parameters,
3818                functionKind,
3819                functionLine,
3820                functionBody);
3821
3822        if (isStatement) {
3823            if (isAnonymous) {
3824                appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function));
3825                return function;
3826            }
3827
3828            // mark ES6 block functions as lexically scoped
3829            final int     varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
3830            final VarNode varNode  = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
3831            if (topLevel) {
3832                functionDeclarations.add(varNode);
3833            } else if (useBlockScope()) {
3834                prependStatement(varNode); // Hoist to beginning of current block
3835            } else {
3836                appendStatement(varNode);
3837            }
3838        }
3839
3840        return function;
3841    }
3842
3843    private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) {
3844        final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding();
3845        if (duplicateParameter != null) {
3846            if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) {
3847                throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken());
3848            }
3849
3850            final int arity = parameters.size();
3851            final HashSet<String> parametersSet = new HashSet<>(arity);
3852
3853            for (int i = arity - 1; i >= 0; i--) {
3854                final IdentNode parameter = parameters.get(i);
3855                String parameterName = parameter.getName();
3856
3857                if (parametersSet.contains(parameterName)) {
3858                    // redefinition of parameter name, rename in non-strict mode
3859                    parameterName = functionNode.uniqueName(parameterName);
3860                    final long parameterToken = parameter.getToken();
3861                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
3862                }
3863                parametersSet.add(parameterName);
3864            }
3865        }
3866    }
3867
3868    private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) {
3869        assert functionBody.isFunctionBody();
3870        if (!parameterBlock.getStatements().isEmpty()) {
3871            parameterBlock.appendStatement(new BlockStatement(functionBody));
3872            return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements());
3873        }
3874        return functionBody;
3875    }
3876
3877    private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) {
3878        final String defaultFunctionName = getDefaultFunctionName();
3879        if (isValidIdentifier(defaultFunctionName)) {
3880            if (isStatement) {
3881                // The name will be used as the LHS of a symbol assignment. We add the anonymous function
3882                // prefix to ensure that it can't clash with another variable.
3883                return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName;
3884            }
3885            return defaultFunctionName;
3886        }
3887        return ANON_FUNCTION_PREFIX.symbolName() + functionLine;
3888    }
3889
3890    private static boolean isValidIdentifier(final String name) {
3891        if (name == null || name.isEmpty()) {
3892            return false;
3893        }
3894        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
3895            return false;
3896        }
3897        for (int i = 1; i < name.length(); ++i) {
3898            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
3899                return false;
3900            }
3901        }
3902        return true;
3903    }
3904
3905    private String getDefaultFunctionName() {
3906        if (!defaultNames.isEmpty()) {
3907            final Object nameExpr = defaultNames.peek();
3908            if (nameExpr instanceof PropertyKey) {
3909                markDefaultNameUsed();
3910                return ((PropertyKey)nameExpr).getPropertyName();
3911            } else if (nameExpr instanceof AccessNode) {
3912                markDefaultNameUsed();
3913                return ((AccessNode)nameExpr).getProperty();
3914            }
3915        }
3916        return null;
3917    }
3918
3919    private void markDefaultNameUsed() {
3920        defaultNames.pop();
3921        hideDefaultName();
3922    }
3923
3924    private void hideDefaultName() {
3925        // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value
3926        // from. Can't be null
3927        defaultNames.push("");
3928    }
3929
3930    /**
3931     * FormalParameterList :
3932     *      Identifier
3933     *      FormalParameterList , Identifier
3934     *
3935     * See 13
3936     *
3937     * Parse function parameter list.
3938     * @return List of parameter nodes.
3939     */
3940    private List<IdentNode> formalParameterList(final boolean yield) {
3941        return formalParameterList(RPAREN, yield);
3942    }
3943
3944    /**
3945     * Same as the other method of the same name - except that the end
3946     * token type expected is passed as argument to this method.
3947     *
3948     * FormalParameterList :
3949     *      Identifier
3950     *      FormalParameterList , Identifier
3951     *
3952     * See 13
3953     *
3954     * Parse function parameter list.
3955     * @return List of parameter nodes.
3956     */
3957    private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) {
3958        // Prepare to gather parameters.
3959        final ArrayList<IdentNode> parameters = new ArrayList<>();
3960        // Track commas.
3961        boolean first = true;
3962
3963        while (type != endType) {
3964            // Comma prior to every argument except the first.
3965            if (!first) {
3966                expect(COMMARIGHT);
3967            } else {
3968                first = false;
3969            }
3970
3971            boolean restParameter = false;
3972            if (type == ELLIPSIS && isES6()) {
3973                next();
3974                restParameter = true;
3975            }
3976
3977            if (type == YIELD && yield) {
3978                expect(IDENT);
3979            }
3980
3981            final long paramToken = token;
3982            final int paramLine = line;
3983            final String contextString = "function parameter";
3984            IdentNode ident;
3985            if (isBindingIdentifier() || restParameter || !isES6()) {
3986                ident = bindingIdentifier(contextString);
3987
3988                if (restParameter) {
3989                    ident = ident.setIsRestParameter();
3990                    // rest parameter must be last
3991                    expectDontAdvance(endType);
3992                    parameters.add(ident);
3993                    break;
3994                } else if (type == ASSIGN && isES6()) {
3995                    next();
3996                    ident = ident.setIsDefaultParameter();
3997
3998                    if (type == YIELD && yield) {
3999                        // error: yield in default expression
4000                        expect(IDENT);
4001                    }
4002
4003                    // default parameter
4004                    Expression initializer = assignmentExpression(false);
4005
4006                    ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4007                    if (currentFunction != null) {
4008                        // desugar to: param = (param === undefined) ? initializer : param;
4009                        // possible alternative: if (param === undefined) param = initializer;
4010                        BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4011                        TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4012                        BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
4013                        lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4014                    }
4015                }
4016
4017                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4018                if (currentFunction != null) {
4019                    currentFunction.addParameterBinding(ident);
4020                    if (ident.isRestParameter() || ident.isDefaultParameter()) {
4021                        currentFunction.setSimpleParameterList(false);
4022                    }
4023                }
4024            } else {
4025                final Expression pattern = bindingPattern();
4026                // Introduce synthetic temporary parameter to capture the object to be destructured.
4027                ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter();
4028                verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString);
4029
4030                Expression value = ident;
4031                if (type == ASSIGN) {
4032                    next();
4033                    ident = ident.setIsDefaultParameter();
4034
4035                    // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param
4036                    Expression initializer = assignmentExpression(false);
4037                    // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list)
4038                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4039                    value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4040                }
4041
4042                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4043                if (currentFunction != null) {
4044                    // destructuring assignment
4045                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value);
4046                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4047                }
4048            }
4049            parameters.add(ident);
4050        }
4051
4052        parameters.trimToSize();
4053        return parameters;
4054    }
4055
4056    private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) {
4057        verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() {
4058            public void accept(IdentNode identNode) {
4059                verifyIdent(identNode, contextString);
4060
4061                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4062                if (currentFunction != null) {
4063                    // declare function-scope variables for destructuring bindings
4064                    lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null));
4065                    // detect duplicate bounds names in parameter list
4066                    currentFunction.addParameterBinding(identNode);
4067                    currentFunction.setSimpleParameterList(false);
4068                }
4069            }
4070        });
4071    }
4072
4073    /**
4074     * FunctionBody :
4075     *      SourceElements?
4076     *
4077     * See 13
4078     *
4079     * Parse function body.
4080     * @return function node (body.)
4081     */
4082    private Block functionBody(final ParserContextFunctionNode functionNode) {
4083        long lastToken = 0L;
4084        ParserContextBlockNode body = null;
4085        final long bodyToken = token;
4086        Block functionBody;
4087        int bodyFinish = 0;
4088
4089        final boolean parseBody;
4090        Object endParserState = null;
4091        try {
4092            // Create a new function block.
4093            body = newBlock();
4094            if (env._debug_scopes) {
4095                // debug scope options forces everything to be in scope
4096                markEval(lc);
4097            }
4098            assert functionNode != null;
4099            final int functionId = functionNode.getId();
4100            parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
4101            // Nashorn extension: expression closures
4102            if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) {
4103                /*
4104                 * Example:
4105                 *
4106                 * function square(x) x * x;
4107                 * print(square(3));
4108                 */
4109
4110                // just expression as function body
4111                final Expression expr = assignmentExpression(false);
4112                lastToken = previousToken;
4113                functionNode.setLastToken(previousToken);
4114                assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
4115                // EOL uses length field to store the line number
4116                final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
4117                // Only create the return node if we aren't skipping nested functions. Note that we aren't
4118                // skipping parsing of these extended functions; they're considered to be small anyway. Also,
4119                // they don't end with a single well known token, so it'd be very hard to get correctly (see
4120                // the note below for reasoning on skipping happening before instead of after RBRACE for
4121                // details).
4122                if (parseBody) {
4123                    final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
4124                    appendStatement(returnNode);
4125                }
4126                // bodyFinish = finish;
4127            } else {
4128                expectDontAdvance(LBRACE);
4129                if (parseBody || !skipFunctionBody(functionNode)) {
4130                    next();
4131                    // Gather the function elements.
4132                    final List<Statement> prevFunctionDecls = functionDeclarations;
4133                    functionDeclarations = new ArrayList<>();
4134                    try {
4135                        sourceElements(false);
4136                        addFunctionDeclarations(functionNode);
4137                    } finally {
4138                        functionDeclarations = prevFunctionDecls;
4139                    }
4140
4141                    lastToken = token;
4142                    if (parseBody) {
4143                        // Since the lexer can read ahead and lexify some number of tokens in advance and have
4144                        // them buffered in the TokenStream, we need to produce a lexer state as it was just
4145                        // before it lexified RBRACE, and not whatever is its current (quite possibly well read
4146                        // ahead) state.
4147                        endParserState = new ParserState(Token.descPosition(token), line, linePosition);
4148
4149                        // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of
4150                        // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the
4151                        // state after it. The reason is that RBRACE is a well-known token that we can expect and
4152                        // will never involve us getting into a weird lexer state, and as such is a great reparse
4153                        // point. Typical example of a weird lexer state after RBRACE would be:
4154                        //     function this_is_skipped() { ... } "use strict";
4155                        // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead
4156                        // of compensating for the possibility of a string literal (or similar) after RBRACE,
4157                        // we'll rather just restart parsing from this well-known, friendly token instead.
4158                    }
4159                }
4160                bodyFinish = finish;
4161                functionNode.setLastToken(token);
4162                expect(RBRACE);
4163            }
4164        } finally {
4165            restoreBlock(body);
4166        }
4167
4168        // NOTE: we can only do alterations to the function node after restoreFunctionNode.
4169
4170        if (parseBody) {
4171            functionNode.setEndParserState(endParserState);
4172        } else if (!body.getStatements().isEmpty()){
4173            // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
4174            // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
4175            // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
4176            // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
4177            // nested bodies early if we were supposed to skip 'em.
4178            body.setStatements(Collections.<Statement>emptyList());
4179        }
4180
4181        if (reparsedFunction != null) {
4182            // We restore the flags stored in the function's ScriptFunctionData that we got when we first
4183            // eagerly parsed the code. We're doing it because some flags would be set based on the
4184            // content of the function, or even content of its nested functions, most of which are normally
4185            // skipped during an on-demand compilation.
4186            final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
4187            if (data != null) {
4188                // Data can be null if when we originally parsed the file, we removed the function declaration
4189                // as it was dead code.
4190                functionNode.setFlag(data.getFunctionFlags());
4191                // This compensates for missing markEval() in case the function contains an inner function
4192                // that contains eval(), that now we didn't discover since we skipped the inner function.
4193                if (functionNode.hasNestedEval()) {
4194                    assert functionNode.hasScopeBlock();
4195                    body.setFlag(Block.NEEDS_SCOPE);
4196                }
4197            }
4198        }
4199        functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements());
4200        return functionBody;
4201    }
4202
4203    private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) {
4204        if (reparsedFunction == null) {
4205            // Not reparsing, so don't skip any function body.
4206            return false;
4207        }
4208        // Skip to the RBRACE of this function, and continue parsing from there.
4209        final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
4210        if (data == null) {
4211            // Nested function is not known to the reparsed function. This can happen if the FunctionNode was
4212            // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the
4213            // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it.
4214            return false;
4215        }
4216        final ParserState parserState = (ParserState)data.getEndParserState();
4217        assert parserState != null;
4218
4219        if (k < stream.last() && start < parserState.position && parserState.position <= Token.descPosition(stream.get(stream.last()))) {
4220            // RBRACE is already in the token stream, so fast forward to it
4221            for (; k < stream.last(); k++) {
4222                final long nextToken = stream.get(k + 1);
4223                if (Token.descPosition(nextToken) == parserState.position && Token.descType(nextToken) == RBRACE) {
4224                    token = stream.get(k);
4225                    type = Token.descType(token);
4226                    next();
4227                    assert type == RBRACE && start == parserState.position;
4228                    return true;
4229                }
4230            }
4231        }
4232
4233        stream.reset();
4234        lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6);
4235        line = parserState.line;
4236        linePosition = parserState.linePosition;
4237        // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
4238        // the RBRACE.
4239        type = SEMICOLON;
4240        scanFirstToken();
4241
4242        return true;
4243    }
4244
4245    /**
4246     * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer
4247     * for resuming parsing after skipping a function body.
4248     */
4249    private static class ParserState implements Serializable {
4250        private final int position;
4251        private final int line;
4252        private final int linePosition;
4253
4254        private static final long serialVersionUID = -2382565130754093694L;
4255
4256        ParserState(final int position, final int line, final int linePosition) {
4257            this.position = position;
4258            this.line = line;
4259            this.linePosition = linePosition;
4260        }
4261
4262        Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) {
4263            final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true);
4264            newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
4265            return newLexer;
4266        }
4267    }
4268
4269    private void printAST(final FunctionNode functionNode) {
4270        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
4271            env.getErr().println(new ASTWriter(functionNode));
4272        }
4273
4274        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
4275            env.getErr().println(new PrintVisitor(functionNode, true, false));
4276        }
4277    }
4278
4279    private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) {
4280        VarNode lastDecl = null;
4281        for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
4282            Statement decl = functionDeclarations.get(i);
4283            if (lastDecl == null && decl instanceof VarNode) {
4284                decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
4285                functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS);
4286            }
4287            prependStatement(decl);
4288        }
4289    }
4290
4291    private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) {
4292        if (earlyError) {
4293            throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
4294        }
4295        final ArrayList<Expression> args = new ArrayList<>();
4296        args.add(lhs);
4297        if (rhs == null) {
4298            args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
4299        } else {
4300            args.add(rhs);
4301        }
4302        args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
4303        return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
4304    }
4305
4306    /**
4307     * PostfixExpression :
4308     *      LeftHandSideExpression
4309     *      LeftHandSideExpression ++ // [no LineTerminator here]
4310     *      LeftHandSideExpression -- // [no LineTerminator here]
4311     *
4312     * See 11.3
4313     *
4314     * UnaryExpression :
4315     *      PostfixExpression
4316     *      delete UnaryExpression
4317     *      void UnaryExpression
4318     *      typeof UnaryExpression
4319     *      ++ UnaryExpression
4320     *      -- UnaryExpression
4321     *      + UnaryExpression
4322     *      - UnaryExpression
4323     *      ~ UnaryExpression
4324     *      ! UnaryExpression
4325     *
4326     * See 11.4
4327     *
4328     * Parse unary expression.
4329     * @return Expression node.
4330     */
4331    private Expression unaryExpression() {
4332        final int  unaryLine  = line;
4333        final long unaryToken = token;
4334
4335        switch (type) {
4336        case DELETE: {
4337            next();
4338            final Expression expr = unaryExpression();
4339            if (expr instanceof BaseNode || expr instanceof IdentNode) {
4340                return new UnaryNode(unaryToken, expr);
4341            }
4342            appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr));
4343            return LiteralNode.newInstance(unaryToken, finish, true);
4344        }
4345        case VOID:
4346        case TYPEOF:
4347        case ADD:
4348        case SUB:
4349        case BIT_NOT:
4350        case NOT:
4351            next();
4352            final Expression expr = unaryExpression();
4353            return new UnaryNode(unaryToken, expr);
4354
4355        case INCPREFIX:
4356        case DECPREFIX:
4357            final TokenType opType = type;
4358            next();
4359
4360            final Expression lhs = leftHandSideExpression();
4361            // ++, -- without operand..
4362            if (lhs == null) {
4363                throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
4364            }
4365
4366            return verifyIncDecExpression(unaryToken, opType, lhs, false);
4367
4368        default:
4369            break;
4370        }
4371
4372        Expression expression = leftHandSideExpression();
4373
4374        if (last != EOL) {
4375            switch (type) {
4376            case INCPREFIX:
4377            case DECPREFIX:
4378                final long opToken = token;
4379                final TokenType opType = type;
4380                final Expression lhs = expression;
4381                // ++, -- without operand..
4382                if (lhs == null) {
4383                    throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
4384                }
4385                next();
4386
4387                return verifyIncDecExpression(opToken, opType, lhs, true);
4388            default:
4389                break;
4390            }
4391        }
4392
4393        if (expression == null) {
4394            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
4395        }
4396
4397        return expression;
4398    }
4399
4400    private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) {
4401        assert lhs != null;
4402
4403        if (!(lhs instanceof AccessNode ||
4404              lhs instanceof IndexNode ||
4405              lhs instanceof IdentNode)) {
4406            return referenceError(lhs, null, env._early_lvalue_error);
4407        }
4408
4409        if (lhs instanceof IdentNode) {
4410            if (!checkIdentLValue((IdentNode)lhs)) {
4411                return referenceError(lhs, null, false);
4412            }
4413            verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
4414        }
4415
4416        return incDecExpression(unaryToken, opType, lhs, isPostfix);
4417    }
4418
4419    /**
4420     * {@code
4421     * MultiplicativeExpression :
4422     *      UnaryExpression
4423     *      MultiplicativeExpression * UnaryExpression
4424     *      MultiplicativeExpression / UnaryExpression
4425     *      MultiplicativeExpression % UnaryExpression
4426     *
4427     * See 11.5
4428     *
4429     * AdditiveExpression :
4430     *      MultiplicativeExpression
4431     *      AdditiveExpression + MultiplicativeExpression
4432     *      AdditiveExpression - MultiplicativeExpression
4433     *
4434     * See 11.6
4435     *
4436     * ShiftExpression :
4437     *      AdditiveExpression
4438     *      ShiftExpression << AdditiveExpression
4439     *      ShiftExpression >> AdditiveExpression
4440     *      ShiftExpression >>> AdditiveExpression
4441     *
4442     * See 11.7
4443     *
4444     * RelationalExpression :
4445     *      ShiftExpression
4446     *      RelationalExpression < ShiftExpression
4447     *      RelationalExpression > ShiftExpression
4448     *      RelationalExpression <= ShiftExpression
4449     *      RelationalExpression >= ShiftExpression
4450     *      RelationalExpression instanceof ShiftExpression
4451     *      RelationalExpression in ShiftExpression // if !noIf
4452     *
4453     * See 11.8
4454     *
4455     *      RelationalExpression
4456     *      EqualityExpression == RelationalExpression
4457     *      EqualityExpression != RelationalExpression
4458     *      EqualityExpression === RelationalExpression
4459     *      EqualityExpression !== RelationalExpression
4460     *
4461     * See 11.9
4462     *
4463     * BitwiseANDExpression :
4464     *      EqualityExpression
4465     *      BitwiseANDExpression & EqualityExpression
4466     *
4467     * BitwiseXORExpression :
4468     *      BitwiseANDExpression
4469     *      BitwiseXORExpression ^ BitwiseANDExpression
4470     *
4471     * BitwiseORExpression :
4472     *      BitwiseXORExpression
4473     *      BitwiseORExpression | BitwiseXORExpression
4474     *
4475     * See 11.10
4476     *
4477     * LogicalANDExpression :
4478     *      BitwiseORExpression
4479     *      LogicalANDExpression && BitwiseORExpression
4480     *
4481     * LogicalORExpression :
4482     *      LogicalANDExpression
4483     *      LogicalORExpression || LogicalANDExpression
4484     *
4485     * See 11.11
4486     *
4487     * ConditionalExpression :
4488     *      LogicalORExpression
4489     *      LogicalORExpression ? AssignmentExpression : AssignmentExpression
4490     *
4491     * See 11.12
4492     *
4493     * AssignmentExpression :
4494     *      ConditionalExpression
4495     *      LeftHandSideExpression AssignmentOperator AssignmentExpression
4496     *
4497     * AssignmentOperator :
4498     *      = *= /= %= += -= <<= >>= >>>= &= ^= |=
4499     *
4500     * See 11.13
4501     *
4502     * Expression :
4503     *      AssignmentExpression
4504     *      Expression , AssignmentExpression
4505     *
4506     * See 11.14
4507     * }
4508     *
4509     * Parse expression.
4510     * @return Expression node.
4511     */
4512    protected Expression expression() {
4513        // This method is protected so that subclass can get details
4514        // at expression start point!
4515
4516        // Include commas in expression parsing.
4517        return expression(false);
4518    }
4519
4520    private Expression expression(final boolean noIn) {
4521        Expression assignmentExpression = assignmentExpression(noIn);
4522        while (type == COMMARIGHT) {
4523            long commaToken = token;
4524            next();
4525
4526            boolean rhsRestParameter = false;
4527            if (type == ELLIPSIS && isES6()) {
4528                // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error).
4529                // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead.
4530                if (isRestParameterEndOfArrowFunctionParameterList()) {
4531                    next();
4532                    rhsRestParameter = true;
4533                }
4534            }
4535
4536            Expression rhs = assignmentExpression(noIn);
4537
4538            if (rhsRestParameter) {
4539                rhs = ((IdentNode)rhs).setIsRestParameter();
4540                // Our only valid move is to end Expression here and continue with ArrowFunction.
4541                // We've already checked that this is the parameter list of an arrow function (see above).
4542                // RPAREN is next, so we'll finish the binary expression and drop out of the loop.
4543                assert type == RPAREN;
4544            }
4545
4546            assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs);
4547        }
4548        return assignmentExpression;
4549    }
4550
4551    private Expression expression(final int minPrecedence, final boolean noIn) {
4552        return expression(unaryExpression(), minPrecedence, noIn);
4553    }
4554
4555    private JoinPredecessorExpression joinPredecessorExpression() {
4556        return new JoinPredecessorExpression(expression());
4557    }
4558
4559    private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) {
4560        // Get the precedence of the next operator.
4561        int precedence = type.getPrecedence();
4562        Expression lhs = exprLhs;
4563
4564        // While greater precedence.
4565        while (type.isOperator(noIn) && precedence >= minPrecedence) {
4566            // Capture the operator token.
4567            final long op = token;
4568
4569            if (type == TERNARY) {
4570                // Skip operator.
4571                next();
4572
4573                // Pass expression. Middle expression of a conditional expression can be a "in"
4574                // expression - even in the contexts where "in" is not permitted.
4575                final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false);
4576
4577                expect(COLON);
4578
4579                // Fail expression.
4580                final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
4581
4582                // Build up node.
4583                lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
4584            } else {
4585                // Skip operator.
4586                next();
4587
4588                 // Get the next primary expression.
4589                Expression rhs;
4590                final boolean isAssign = Token.descType(op) == ASSIGN;
4591                if(isAssign) {
4592                    defaultNames.push(lhs);
4593                }
4594                try {
4595                    rhs = unaryExpression();
4596                    // Get precedence of next operator.
4597                    int nextPrecedence = type.getPrecedence();
4598
4599                    // Subtask greater precedence.
4600                    while (type.isOperator(noIn) &&
4601                           (nextPrecedence > precedence ||
4602                           nextPrecedence == precedence && !type.isLeftAssociative())) {
4603                        rhs = expression(rhs, nextPrecedence, noIn);
4604                        nextPrecedence = type.getPrecedence();
4605                    }
4606                } finally {
4607                    if(isAssign) {
4608                        defaultNames.pop();
4609                    }
4610                }
4611                lhs = verifyAssignment(op, lhs, rhs);
4612            }
4613
4614            precedence = type.getPrecedence();
4615        }
4616
4617        return lhs;
4618    }
4619
4620    /**
4621     * AssignmentExpression.
4622     *
4623     * AssignmentExpression[In, Yield] :
4624     *   ConditionalExpression[?In, ?Yield]
4625     *   [+Yield] YieldExpression[?In]
4626     *   ArrowFunction[?In, ?Yield]
4627     *   LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield]
4628     *   LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield]
4629     *
4630     * @param noIn {@code true} if IN operator should be ignored.
4631     * @return the assignment expression
4632     */
4633    protected Expression assignmentExpression(final boolean noIn) {
4634        // This method is protected so that subclass can get details
4635        // at assignment expression start point!
4636
4637        if (type == YIELD && inGeneratorFunction() && isES6()) {
4638            return yieldExpression(noIn);
4639        }
4640
4641        final long startToken = token;
4642        final int startLine = line;
4643        final Expression exprLhs = conditionalExpression(noIn);
4644
4645        if (type == ARROW && isES6()) {
4646            if (checkNoLineTerminator()) {
4647                final Expression paramListExpr;
4648                if (exprLhs instanceof ExpressionList) {
4649                    paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0));
4650                } else {
4651                    paramListExpr = exprLhs;
4652                }
4653                return arrowFunction(startToken, startLine, paramListExpr);
4654            }
4655        }
4656        assert !(exprLhs instanceof ExpressionList);
4657
4658        if (isAssignmentOperator(type)) {
4659            final boolean isAssign = type == ASSIGN;
4660            if (isAssign) {
4661                defaultNames.push(exprLhs);
4662            }
4663            try {
4664                final long assignToken = token;
4665                next();
4666                final Expression exprRhs = assignmentExpression(noIn);
4667                return verifyAssignment(assignToken, exprLhs, exprRhs);
4668            } finally {
4669                if (isAssign) {
4670                    defaultNames.pop();
4671                }
4672            }
4673        } else {
4674            return exprLhs;
4675        }
4676    }
4677
4678    /**
4679     * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}?
4680     */
4681    private static boolean isAssignmentOperator(TokenType type) {
4682        switch (type) {
4683        case ASSIGN:
4684        case ASSIGN_ADD:
4685        case ASSIGN_BIT_AND:
4686        case ASSIGN_BIT_OR:
4687        case ASSIGN_BIT_XOR:
4688        case ASSIGN_DIV:
4689        case ASSIGN_MOD:
4690        case ASSIGN_MUL:
4691        case ASSIGN_SAR:
4692        case ASSIGN_SHL:
4693        case ASSIGN_SHR:
4694        case ASSIGN_SUB:
4695            return true;
4696        }
4697        return false;
4698    }
4699
4700    /**
4701     * ConditionalExpression.
4702     */
4703    private Expression conditionalExpression(boolean noIn) {
4704        return expression(TERNARY.getPrecedence(), noIn);
4705    }
4706
4707    /**
4708     * ArrowFunction.
4709     *
4710     * @param startToken start token of the ArrowParameters expression
4711     * @param functionLine start line of the arrow function
4712     * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list)
4713     */
4714    private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) {
4715        // caller needs to check that there's no LineTerminator between parameter list and arrow
4716        assert type != ARROW || checkNoLineTerminator();
4717        expect(ARROW);
4718
4719        final long functionToken = Token.recast(startToken, ARROW);
4720        final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), NameCodec.encode("=>:") + functionLine);
4721        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null);
4722        functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
4723
4724        lc.push(functionNode);
4725        try {
4726            ParserContextBlockNode parameterBlock = newBlock();
4727            final List<IdentNode> parameters;
4728            try {
4729                parameters = convertArrowFunctionParameterList(paramListExpr, functionLine);
4730                functionNode.setParameters(parameters);
4731
4732                if (!functionNode.isSimpleParameterList()) {
4733                    markEvalInArrowParameterList(parameterBlock);
4734                }
4735            } finally {
4736                restoreBlock(parameterBlock);
4737            }
4738            Block functionBody = functionBody(functionNode);
4739
4740            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
4741
4742            verifyParameterList(parameters, functionNode);
4743
4744            final FunctionNode function = createFunctionNode(
4745                            functionNode,
4746                            functionToken,
4747                            name,
4748                            parameters,
4749                            FunctionNode.Kind.ARROW,
4750                            functionLine,
4751                            functionBody);
4752            return function;
4753        } finally {
4754            lc.pop(functionNode);
4755        }
4756    }
4757
4758    private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) {
4759        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
4760        final ParserContextFunctionNode current = iter.next();
4761        final ParserContextFunctionNode parent = iter.next();
4762
4763        if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) {
4764            // we might have flagged has-eval in the parent function during parsing the parameter list,
4765            // if the parameter list contains eval; must tag arrow function as has-eval.
4766            for (final Statement st : parameterBlock.getStatements()) {
4767                st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
4768                    @Override
4769                    public boolean enterCallNode(final CallNode callNode) {
4770                        if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) {
4771                            current.setFlag(FunctionNode.HAS_EVAL);
4772                        }
4773                        return true;
4774                    }
4775                });
4776            }
4777            // TODO: function containing the arrow function should not be flagged has-eval
4778        }
4779    }
4780
4781    private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) {
4782        final List<IdentNode> parameters;
4783        if (paramListExpr == null) {
4784            // empty parameter list, i.e. () =>
4785            parameters = Collections.emptyList();
4786        } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) {
4787            parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine));
4788        } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) {
4789            parameters = new ArrayList<>();
4790            Expression car = paramListExpr;
4791            do {
4792                final Expression cdr = ((BinaryNode) car).rhs();
4793                parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine));
4794                car = ((BinaryNode) car).lhs();
4795            } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT);
4796            parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine));
4797        } else {
4798            throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken());
4799        }
4800        return parameters;
4801    }
4802
4803    private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) {
4804        final String contextString = "function parameter";
4805        if (param instanceof IdentNode) {
4806            IdentNode ident = (IdentNode)param;
4807            verifyStrictIdent(ident, contextString);
4808            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4809            if (currentFunction != null) {
4810                currentFunction.addParameterBinding(ident);
4811            }
4812            return ident;
4813        }
4814
4815        if (param.isTokenType(ASSIGN)) {
4816            Expression lhs = ((BinaryNode) param).lhs();
4817            long paramToken = lhs.getToken();
4818            Expression initializer = ((BinaryNode) param).rhs();
4819            if (lhs instanceof IdentNode) {
4820                // default parameter
4821                IdentNode ident = (IdentNode) lhs;
4822
4823                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4824                if (currentFunction != null) {
4825                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4826                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4827                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
4828                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4829
4830                    currentFunction.addParameterBinding(ident);
4831                    currentFunction.setSimpleParameterList(false);
4832                }
4833                return ident;
4834            } else if (isDestructuringLhs(lhs)) {
4835                // binding pattern with initializer
4836                // Introduce synthetic temporary parameter to capture the object to be destructured.
4837                IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter();
4838                verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
4839
4840                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4841                if (currentFunction != null) {
4842                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4843                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4844                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value);
4845                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4846                }
4847                return ident;
4848            }
4849        } else if (isDestructuringLhs(param)) {
4850            // binding pattern
4851            long paramToken = param.getToken();
4852
4853            // Introduce synthetic temporary parameter to capture the object to be destructured.
4854            IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter();
4855            verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
4856
4857            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4858            if (currentFunction != null) {
4859                BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident);
4860                lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4861            }
4862            return ident;
4863        }
4864        throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken());
4865    }
4866
4867    private boolean checkNoLineTerminator() {
4868        assert type == ARROW;
4869        if (last == RPAREN) {
4870            return true;
4871        } else if (last == IDENT) {
4872            return true;
4873        }
4874        for (int i = k - 1; i >= 0; i--) {
4875            TokenType t = T(i);
4876            switch (t) {
4877            case RPAREN:
4878            case IDENT:
4879                return true;
4880            case EOL:
4881                return false;
4882            case COMMENT:
4883                continue;
4884            default:
4885                if (t.getKind() == TokenKind.FUTURESTRICT) {
4886                    return true;
4887                }
4888                return false;
4889            }
4890        }
4891        return false;
4892    }
4893
4894    /**
4895     * Peek ahead to see if what follows after the ellipsis is a rest parameter
4896     * at the end of an arrow function parameter list.
4897     */
4898    private boolean isRestParameterEndOfArrowFunctionParameterList() {
4899        assert type == ELLIPSIS;
4900        // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT
4901        int i = 1;
4902        for (;;) {
4903            TokenType t = T(k + i++);
4904            if (t == IDENT) {
4905                break;
4906            } else if (t == EOL || t == COMMENT) {
4907                continue;
4908            } else {
4909                return false;
4910            }
4911        }
4912        for (;;) {
4913            TokenType t = T(k + i++);
4914            if (t == RPAREN) {
4915                break;
4916            } else if (t == EOL || t == COMMENT) {
4917                continue;
4918            } else {
4919                return false;
4920            }
4921        }
4922        for (;;) {
4923            TokenType t = T(k + i++);
4924            if (t == ARROW) {
4925                break;
4926            } else if (t == COMMENT) {
4927                continue;
4928            } else {
4929                return false;
4930            }
4931        }
4932        return true;
4933    }
4934
4935    /**
4936     * Parse an end of line.
4937     */
4938    private void endOfLine() {
4939        switch (type) {
4940        case SEMICOLON:
4941        case EOL:
4942            next();
4943            break;
4944        case RPAREN:
4945        case RBRACKET:
4946        case RBRACE:
4947        case EOF:
4948            break;
4949        default:
4950            if (last != EOL) {
4951                expect(SEMICOLON);
4952            }
4953            break;
4954        }
4955    }
4956
4957    /**
4958     * Parse untagged template literal as string concatenation.
4959     */
4960    private Expression templateLiteral() {
4961        assert type == TEMPLATE || type == TEMPLATE_HEAD;
4962        final boolean noSubstitutionTemplate = type == TEMPLATE;
4963        long lastLiteralToken = token;
4964        LiteralNode<?> literal = getLiteral();
4965        if (noSubstitutionTemplate) {
4966            return literal;
4967        }
4968
4969        Expression concat = literal;
4970        TokenType lastLiteralType;
4971        do {
4972            final Expression expression = expression();
4973            if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) {
4974                throw error(AbstractParser.message("unterminated.template.expression"), token);
4975            }
4976            concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, expression);
4977            lastLiteralType = type;
4978            lastLiteralToken = token;
4979            literal = getLiteral();
4980            concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, literal);
4981        } while (lastLiteralType == TEMPLATE_MIDDLE);
4982        return concat;
4983    }
4984
4985    /**
4986     * Parse tagged template literal as argument list.
4987     * @return argument list for a tag function call (template object, ...substitutions)
4988     */
4989    private List<Expression> templateLiteralArgumentList() {
4990        assert type == TEMPLATE || type == TEMPLATE_HEAD;
4991        final ArrayList<Expression> argumentList = new ArrayList<>();
4992        final ArrayList<Expression> rawStrings = new ArrayList<>();
4993        final ArrayList<Expression> cookedStrings = new ArrayList<>();
4994        argumentList.add(null); // filled at the end
4995
4996        final long templateToken = token;
4997        final boolean hasSubstitutions = type == TEMPLATE_HEAD;
4998        addTemplateLiteralString(rawStrings, cookedStrings);
4999
5000        if (hasSubstitutions) {
5001            TokenType lastLiteralType;
5002            do {
5003                final Expression expression = expression();
5004                if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) {
5005                    throw error(AbstractParser.message("unterminated.template.expression"), token);
5006                }
5007                argumentList.add(expression);
5008
5009                lastLiteralType = type;
5010                addTemplateLiteralString(rawStrings, cookedStrings);
5011            } while (lastLiteralType == TEMPLATE_MIDDLE);
5012        }
5013
5014        final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings);
5015        final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings);
5016        final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
5017        argumentList.set(0, templateObject);
5018        return optimizeList(argumentList);
5019    }
5020
5021    private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, final ArrayList<Expression> cookedStrings) {
5022        final long stringToken = token;
5023        final String rawString = lexer.valueOfRawString(stringToken);
5024        final String cookedString = (String) getValue();
5025        next();
5026        rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString));
5027        cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString));
5028    }
5029
5030
5031    /**
5032     * Parse a module.
5033     *
5034     * Module :
5035     *      ModuleBody?
5036     *
5037     * ModuleBody :
5038     *      ModuleItemList
5039     */
5040    private FunctionNode module(final String moduleName) {
5041        boolean oldStrictMode = isStrictMode;
5042        try {
5043            isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1)
5044
5045            // Make a pseudo-token for the script holding its start and length.
5046            int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish);
5047            final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart);
5048            final int  functionLine  = line;
5049
5050            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName);
5051            final ParserContextFunctionNode script = createParserContextFunctionNode(
5052                            ident,
5053                            functionToken,
5054                            FunctionNode.Kind.MODULE,
5055                            functionLine,
5056                            Collections.<IdentNode>emptyList());
5057            lc.push(script);
5058
5059            final ParserContextModuleNode module = new ParserContextModuleNode(moduleName);
5060            lc.push(module);
5061
5062            final ParserContextBlockNode body = newBlock();
5063
5064            functionDeclarations = new ArrayList<>();
5065            moduleBody();
5066            addFunctionDeclarations(script);
5067            functionDeclarations = null;
5068
5069            restoreBlock(body);
5070            body.setFlag(Block.NEEDS_SCOPE);
5071            final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
5072            lc.pop(module);
5073            lc.pop(script);
5074            script.setLastToken(token);
5075
5076            expect(EOF);
5077
5078            script.setModule(module.createModule());
5079            return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody);
5080        } finally {
5081            isStrictMode = oldStrictMode;
5082        }
5083    }
5084
5085    /**
5086     * Parse module body.
5087     *
5088     * ModuleBody :
5089     *      ModuleItemList
5090     *
5091     * ModuleItemList :
5092     *      ModuleItem
5093     *      ModuleItemList ModuleItem
5094     *
5095     * ModuleItem :
5096     *      ImportDeclaration
5097     *      ExportDeclaration
5098     *      StatementListItem
5099     */
5100    private void moduleBody() {
5101        loop:
5102        while (type != EOF) {
5103            switch (type) {
5104            case EOF:
5105                break loop;
5106            case IMPORT:
5107                importDeclaration();
5108                break;
5109            case EXPORT:
5110                exportDeclaration();
5111                break;
5112            default:
5113                // StatementListItem
5114                statement(true, false, false, false);
5115                break;
5116            }
5117        }
5118    }
5119
5120
5121    /**
5122     * Parse import declaration.
5123     *
5124     * ImportDeclaration :
5125     *     import ImportClause FromClause ;
5126     *     import ModuleSpecifier ;
5127     * ImportClause :
5128     *     ImportedDefaultBinding
5129     *     NameSpaceImport
5130     *     NamedImports
5131     *     ImportedDefaultBinding , NameSpaceImport
5132     *     ImportedDefaultBinding , NamedImports
5133     * ImportedDefaultBinding :
5134     *     ImportedBinding
5135     * ModuleSpecifier :
5136     *     StringLiteral
5137     * ImportedBinding :
5138     *     BindingIdentifier
5139     */
5140    private void importDeclaration() {
5141        expect(IMPORT);
5142        final ParserContextModuleNode module = lc.getCurrentModule();
5143        if (type == STRING || type == ESCSTRING) {
5144            // import ModuleSpecifier ;
5145            final String moduleSpecifier = (String) getValue();
5146            next();
5147            module.addModuleRequest(moduleSpecifier);
5148        } else {
5149            // import ImportClause FromClause ;
5150            List<Module.ImportEntry> importEntries;
5151            if (type == MUL) {
5152                importEntries = Collections.singletonList(nameSpaceImport());
5153            } else if (type == LBRACE) {
5154                importEntries = namedImports();
5155            } else if (isBindingIdentifier()) {
5156                // ImportedDefaultBinding
5157                final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding");
5158                Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName());
5159
5160                if (type == COMMARIGHT) {
5161                    next();
5162                    importEntries = new ArrayList<>();
5163                    if (type == MUL) {
5164                        importEntries.add(nameSpaceImport());
5165                    } else if (type == LBRACE) {
5166                        importEntries.addAll(namedImports());
5167                    } else {
5168                        throw error(AbstractParser.message("expected.named.import"));
5169                    }
5170                } else {
5171                    importEntries = Collections.singletonList(defaultImport);
5172                }
5173            } else {
5174                throw error(AbstractParser.message("expected.import"));
5175            }
5176
5177            final String moduleSpecifier = fromClause();
5178            module.addModuleRequest(moduleSpecifier);
5179            for (int i = 0; i < importEntries.size(); i++) {
5180                module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier));
5181            }
5182        }
5183        expect(SEMICOLON);
5184    }
5185
5186    /**
5187     * NameSpaceImport :
5188     *     * as ImportedBinding
5189     *
5190     * @return imported binding identifier
5191     */
5192    private Module.ImportEntry nameSpaceImport() {
5193        assert type == MUL;
5194        next();
5195        final long asToken = token;
5196        final String as = (String) expectValue(IDENT);
5197        if (!"as".equals(as)) {
5198            throw error(AbstractParser.message("expected.as"), asToken);
5199        }
5200        final IdentNode localNameSpace = bindingIdentifier("ImportedBinding");
5201        return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName());
5202    }
5203
5204    /**
5205     * NamedImports :
5206     *     { }
5207     *     { ImportsList }
5208     *     { ImportsList , }
5209     * ImportsList :
5210     *     ImportSpecifier
5211     *     ImportsList , ImportSpecifier
5212     * ImportSpecifier :
5213     *     ImportedBinding
5214     *     IdentifierName as ImportedBinding
5215     * ImportedBinding :
5216     *     BindingIdentifier
5217     */
5218    private List<Module.ImportEntry> namedImports() {
5219        assert type == LBRACE;
5220        next();
5221        List<Module.ImportEntry> importEntries = new ArrayList<>();
5222        while (type != RBRACE) {
5223            final boolean bindingIdentifier = isBindingIdentifier();
5224            final long nameToken = token;
5225            final IdentNode importName = getIdentifierName();
5226            if (type == IDENT && "as".equals(getValue())) {
5227                next();
5228                final IdentNode localName = bindingIdentifier("ImportedBinding");
5229                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName()));
5230            } else if (!bindingIdentifier) {
5231                throw error(AbstractParser.message("expected.binding.identifier"), nameToken);
5232            } else {
5233                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName()));
5234            }
5235            if (type == COMMARIGHT) {
5236                next();
5237            } else {
5238                break;
5239            }
5240        }
5241        expect(RBRACE);
5242        return importEntries;
5243    }
5244
5245    /**
5246     * FromClause :
5247     *     from ModuleSpecifier
5248     */
5249    private String fromClause() {
5250        final long fromToken = token;
5251        final String name = (String) expectValue(IDENT);
5252        if (!"from".equals(name)) {
5253            throw error(AbstractParser.message("expected.from"), fromToken);
5254        }
5255        if (type == STRING || type == ESCSTRING) {
5256            final String moduleSpecifier = (String) getValue();
5257            next();
5258            return moduleSpecifier;
5259        } else {
5260            throw error(expectMessage(STRING));
5261        }
5262    }
5263
5264    /**
5265     * Parse export declaration.
5266     *
5267     * ExportDeclaration :
5268     *     export * FromClause ;
5269     *     export ExportClause FromClause ;
5270     *     export ExportClause ;
5271     *     export VariableStatement
5272     *     export Declaration
5273     *     export default HoistableDeclaration[Default]
5274     *     export default ClassDeclaration[Default]
5275     *     export default [lookahead !in {function, class}] AssignmentExpression[In] ;
5276     */
5277    private void exportDeclaration() {
5278        expect(EXPORT);
5279        final ParserContextModuleNode module = lc.getCurrentModule();
5280        switch (type) {
5281            case MUL: {
5282                next();
5283                final String moduleRequest = fromClause();
5284                expect(SEMICOLON);
5285                module.addModuleRequest(moduleRequest);
5286                module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest));
5287                break;
5288            }
5289            case LBRACE: {
5290                final List<Module.ExportEntry> exportEntries = exportClause();
5291                if (type == IDENT && "from".equals(getValue())) {
5292                    final String moduleRequest = fromClause();
5293                    module.addModuleRequest(moduleRequest);
5294                    for (Module.ExportEntry exportEntry : exportEntries) {
5295                        module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest));
5296                    }
5297                } else {
5298                    for (Module.ExportEntry exportEntry : exportEntries) {
5299                        module.addLocalExportEntry(exportEntry);
5300                    }
5301                }
5302                expect(SEMICOLON);
5303                break;
5304            }
5305            case DEFAULT:
5306                next();
5307                final Expression assignmentExpression;
5308                IdentNode ident;
5309                final int lineNumber = line;
5310                final long rhsToken = token;
5311                final boolean declaration;
5312                switch (type) {
5313                    case FUNCTION:
5314                        assignmentExpression = functionExpression(false, true);
5315                        ident = ((FunctionNode) assignmentExpression).getIdent();
5316                        declaration = true;
5317                        break;
5318                    case CLASS:
5319                        assignmentExpression = classDeclaration(true);
5320                        ident = ((ClassNode) assignmentExpression).getIdent();
5321                        declaration = true;
5322                        break;
5323                    default:
5324                        assignmentExpression = assignmentExpression(false);
5325                        ident = null;
5326                        declaration = false;
5327                        break;
5328                }
5329                if (ident != null) {
5330                    module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName()));
5331                } else {
5332                    ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME);
5333                    lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression));
5334                    if (!declaration) {
5335                        expect(SEMICOLON);
5336                    }
5337                    module.addLocalExportEntry(Module.ExportEntry.exportDefault());
5338                }
5339                break;
5340            case VAR:
5341            case LET:
5342            case CONST:
5343                final List<Statement> statements = lc.getCurrentBlock().getStatements();
5344                final int previousEnd = statements.size();
5345                variableStatement(type);
5346                for (final Statement statement : statements.subList(previousEnd, statements.size())) {
5347                    if (statement instanceof VarNode) {
5348                        module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName()));
5349                    }
5350                }
5351                break;
5352            case CLASS: {
5353                final ClassNode classDeclaration = classDeclaration(false);
5354                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName()));
5355                break;
5356            }
5357            case FUNCTION: {
5358                final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true);
5359                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName()));
5360                break;
5361            }
5362            default:
5363                throw error(AbstractParser.message("invalid.export"), token);
5364        }
5365    }
5366
5367    /**
5368     * ExportClause :
5369     *     { }
5370     *     { ExportsList }
5371     *     { ExportsList , }
5372     * ExportsList :
5373     *     ExportSpecifier
5374     *     ExportsList , ExportSpecifier
5375     * ExportSpecifier :
5376     *     IdentifierName
5377     *     IdentifierName as IdentifierName
5378     *
5379     * @return a list of ExportSpecifiers
5380     */
5381    private List<Module.ExportEntry> exportClause() {
5382        assert type == LBRACE;
5383        next();
5384        List<Module.ExportEntry> exports = new ArrayList<>();
5385        while (type != RBRACE) {
5386            final IdentNode localName = getIdentifierName();
5387            if (type == IDENT && "as".equals(getValue())) {
5388                next();
5389                final IdentNode exportName = getIdentifierName();
5390                exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName()));
5391            } else {
5392                exports.add(Module.ExportEntry.exportSpecifier(localName.getName()));
5393            }
5394            if (type == COMMARIGHT) {
5395                next();
5396            } else {
5397                break;
5398            }
5399        }
5400        expect(RBRACE);
5401        return exports;
5402    }
5403
5404    @Override
5405    public String toString() {
5406        return "'JavaScript Parsing'";
5407    }
5408
5409    private static void markEval(final ParserContext lc) {
5410        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5411        boolean flaggedCurrentFn = false;
5412        while (iter.hasNext()) {
5413            final ParserContextFunctionNode fn = iter.next();
5414            if (!flaggedCurrentFn) {
5415                fn.setFlag(FunctionNode.HAS_EVAL);
5416                flaggedCurrentFn = true;
5417                if (fn.getKind() == FunctionNode.Kind.ARROW) {
5418                    // possible use of this in an eval that's nested in an arrow function, e.g.:
5419                    // function fun(){ return (() => eval("this"))(); };
5420                    markThis(lc);
5421                    markNewTarget(lc);
5422                }
5423            } else {
5424                fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
5425            }
5426            final ParserContextBlockNode body = lc.getFunctionBody(fn);
5427            // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
5428            // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
5429            // this method when the parser skips a nested function.
5430            body.setFlag(Block.NEEDS_SCOPE);
5431            fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK);
5432        }
5433    }
5434
5435    private void prependStatement(final Statement statement) {
5436        lc.prependStatementToCurrentNode(statement);
5437    }
5438
5439    private void appendStatement(final Statement statement) {
5440        lc.appendStatementToCurrentNode(statement);
5441    }
5442
5443    private static void markSuperCall(final ParserContext lc) {
5444        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5445        while (iter.hasNext()) {
5446            final ParserContextFunctionNode fn = iter.next();
5447            if (fn.getKind() != FunctionNode.Kind.ARROW) {
5448                assert fn.isSubclassConstructor();
5449                fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
5450                break;
5451            }
5452        }
5453    }
5454
5455    private ParserContextFunctionNode getCurrentNonArrowFunction() {
5456        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5457        while (iter.hasNext()) {
5458            final ParserContextFunctionNode fn = iter.next();
5459            if (fn.getKind() != FunctionNode.Kind.ARROW) {
5460                return fn;
5461            }
5462        }
5463        return null;
5464    }
5465
5466    private static void markThis(final ParserContext lc) {
5467        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5468        while (iter.hasNext()) {
5469            final ParserContextFunctionNode fn = iter.next();
5470            fn.setFlag(FunctionNode.USES_THIS);
5471            if (fn.getKind() != FunctionNode.Kind.ARROW) {
5472                break;
5473            }
5474        }
5475    }
5476
5477    private static void markNewTarget(final ParserContext lc) {
5478        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5479        while (iter.hasNext()) {
5480            final ParserContextFunctionNode fn = iter.next();
5481            if (fn.getKind() != FunctionNode.Kind.ARROW) {
5482                if (!fn.isProgram()) {
5483                    fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET);
5484                }
5485                break;
5486            }
5487        }
5488    }
5489
5490    private boolean inGeneratorFunction() {
5491        return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR;
5492    }
5493}
5494