Parser.java revision 953:221a84ef44c0
1/*
2 * Copyright (c) 2010, 2013, 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.ASSIGN;
32import static jdk.nashorn.internal.parser.TokenType.CASE;
33import static jdk.nashorn.internal.parser.TokenType.CATCH;
34import static jdk.nashorn.internal.parser.TokenType.COLON;
35import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
36import static jdk.nashorn.internal.parser.TokenType.CONST;
37import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
38import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
39import static jdk.nashorn.internal.parser.TokenType.ELSE;
40import static jdk.nashorn.internal.parser.TokenType.EOF;
41import static jdk.nashorn.internal.parser.TokenType.EOL;
42import static jdk.nashorn.internal.parser.TokenType.FINALLY;
43import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
44import static jdk.nashorn.internal.parser.TokenType.IDENT;
45import static jdk.nashorn.internal.parser.TokenType.IF;
46import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
47import static jdk.nashorn.internal.parser.TokenType.LBRACE;
48import static jdk.nashorn.internal.parser.TokenType.LPAREN;
49import static jdk.nashorn.internal.parser.TokenType.RBRACE;
50import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
51import static jdk.nashorn.internal.parser.TokenType.RPAREN;
52import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
53import static jdk.nashorn.internal.parser.TokenType.TERNARY;
54import static jdk.nashorn.internal.parser.TokenType.WHILE;
55
56import java.util.ArrayDeque;
57import java.util.ArrayList;
58import java.util.Collections;
59import java.util.Deque;
60import java.util.HashMap;
61import java.util.HashSet;
62import java.util.Iterator;
63import java.util.List;
64import java.util.Map;
65import jdk.internal.dynalink.support.NameCodec;
66import jdk.nashorn.internal.codegen.CompilerConstants;
67import jdk.nashorn.internal.codegen.Namespace;
68import jdk.nashorn.internal.ir.AccessNode;
69import jdk.nashorn.internal.ir.BaseNode;
70import jdk.nashorn.internal.ir.BinaryNode;
71import jdk.nashorn.internal.ir.Block;
72import jdk.nashorn.internal.ir.BlockLexicalContext;
73import jdk.nashorn.internal.ir.BlockStatement;
74import jdk.nashorn.internal.ir.BreakNode;
75import jdk.nashorn.internal.ir.BreakableNode;
76import jdk.nashorn.internal.ir.CallNode;
77import jdk.nashorn.internal.ir.CaseNode;
78import jdk.nashorn.internal.ir.CatchNode;
79import jdk.nashorn.internal.ir.ContinueNode;
80import jdk.nashorn.internal.ir.EmptyNode;
81import jdk.nashorn.internal.ir.Expression;
82import jdk.nashorn.internal.ir.ExpressionStatement;
83import jdk.nashorn.internal.ir.ForNode;
84import jdk.nashorn.internal.ir.FunctionNode;
85import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
86import jdk.nashorn.internal.ir.IdentNode;
87import jdk.nashorn.internal.ir.IfNode;
88import jdk.nashorn.internal.ir.IndexNode;
89import jdk.nashorn.internal.ir.JoinPredecessorExpression;
90import jdk.nashorn.internal.ir.LabelNode;
91import jdk.nashorn.internal.ir.LexicalContext;
92import jdk.nashorn.internal.ir.LiteralNode;
93import jdk.nashorn.internal.ir.LoopNode;
94import jdk.nashorn.internal.ir.Node;
95import jdk.nashorn.internal.ir.ObjectNode;
96import jdk.nashorn.internal.ir.PropertyKey;
97import jdk.nashorn.internal.ir.PropertyNode;
98import jdk.nashorn.internal.ir.ReturnNode;
99import jdk.nashorn.internal.ir.RuntimeNode;
100import jdk.nashorn.internal.ir.Statement;
101import jdk.nashorn.internal.ir.SwitchNode;
102import jdk.nashorn.internal.ir.TernaryNode;
103import jdk.nashorn.internal.ir.ThrowNode;
104import jdk.nashorn.internal.ir.TryNode;
105import jdk.nashorn.internal.ir.UnaryNode;
106import jdk.nashorn.internal.ir.VarNode;
107import jdk.nashorn.internal.ir.WhileNode;
108import jdk.nashorn.internal.ir.WithNode;
109import jdk.nashorn.internal.runtime.Context;
110import jdk.nashorn.internal.runtime.ErrorManager;
111import jdk.nashorn.internal.runtime.JSErrorType;
112import jdk.nashorn.internal.runtime.ParserException;
113import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
114import jdk.nashorn.internal.runtime.ScriptEnvironment;
115import jdk.nashorn.internal.runtime.ScriptingFunctions;
116import jdk.nashorn.internal.runtime.Source;
117import jdk.nashorn.internal.runtime.logging.DebugLogger;
118import jdk.nashorn.internal.runtime.logging.Loggable;
119import jdk.nashorn.internal.runtime.logging.Logger;
120
121/**
122 * Builds the IR.
123 */
124@Logger(name="parser")
125public class Parser extends AbstractParser implements Loggable {
126    private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName();
127
128    /** Current env. */
129    private final ScriptEnvironment env;
130
131    /** Is scripting mode. */
132    private final boolean scripting;
133
134    private List<Statement> functionDeclarations;
135
136    private final BlockLexicalContext lc = new BlockLexicalContext();
137    private final Deque<Object> defaultNames = new ArrayDeque<>();
138
139    /** Namespace for function names where not explicitly given */
140    private final Namespace namespace;
141
142    private final DebugLogger log;
143
144    /** to receive line information from Lexer when scanning multine literals. */
145    protected final Lexer.LineInfoReceiver lineInfoReceiver;
146
147    private int nextFunctionId;
148
149    /**
150     * Constructor
151     *
152     * @param env     script environment
153     * @param source  source to parse
154     * @param errors  error manager
155     */
156    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) {
157        this(env, source, errors, env._strict, null);
158    }
159
160    /**
161     * Constructor
162     *
163     * @param env     script environment
164     * @param source  source to parse
165     * @param errors  error manager
166     * @param strict  strict
167     * @param log debug logger if one is needed
168     */
169    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) {
170        this(env, source, errors, strict, FunctionNode.FIRST_FUNCTION_ID, 0, log);
171    }
172
173    /**
174     * Construct a parser.
175     *
176     * @param env     script environment
177     * @param source  source to parse
178     * @param errors  error manager
179     * @param strict  parser created with strict mode enabled.
180     * @param nextFunctionId  starting value for assigning new unique ids to function nodes
181     * @param lineOffset line offset to start counting lines from
182     * @param log debug logger if one is needed
183     */
184    public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int nextFunctionId, final int lineOffset, final DebugLogger log) {
185        super(source, errors, strict, lineOffset);
186        this.env = env;
187        this.namespace = new Namespace(env.getNamespace());
188        this.nextFunctionId    = nextFunctionId;
189        this.scripting = env._scripting;
190        if (this.scripting) {
191            this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
192                @Override
193                public void lineInfo(final int receiverLine, final int receiverLinePosition) {
194                    // update the parser maintained line information
195                    Parser.this.line = receiverLine;
196                    Parser.this.linePosition = receiverLinePosition;
197                }
198            };
199        } else {
200            // non-scripting mode script can't have multi-line literals
201            this.lineInfoReceiver = null;
202        }
203
204        this.log = log == null ? DebugLogger.DISABLED_LOGGER : log;
205    }
206
207    @Override
208    public DebugLogger getLogger() {
209        return log;
210    }
211
212    @Override
213    public DebugLogger initLogger(final Context context) {
214        return context.getLogger(this.getClass());
215    }
216
217    /**
218     * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can
219     * preserve their already assigned name, as that name doesn't appear in their source text.
220     * @param name the name for the first parsed function.
221     */
222    public void setFunctionName(final String name) {
223        defaultNames.push(new IdentNode(0, 0, name));
224    }
225
226    /**
227     * Execute parse and return the resulting function node.
228     * Errors will be thrown and the error manager will contain information
229     * if parsing should fail
230     *
231     * This is the default parse call, which will name the function node
232     * {code :program} {@link CompilerConstants#PROGRAM}
233     *
234     * @return function node resulting from successful parse
235     */
236    public FunctionNode parse() {
237        return parse(PROGRAM.symbolName(), 0, source.getLength(), false);
238    }
239
240    /**
241     * Execute parse and return the resulting function node.
242     * Errors will be thrown and the error manager will contain information
243     * if parsing should fail
244     *
245     * This should be used to create one and only one function node
246     *
247     * @param scriptName name for the script, given to the parsed FunctionNode
248     * @param startPos start position in source
249     * @param len length of parse
250     * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by
251     * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a
252     * property getter or setter in an object literal.
253     *
254     * @return function node resulting from successful parse
255     */
256    public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) {
257        final boolean isTimingEnabled = env.isTimingEnabled();
258        final long t0 = isTimingEnabled ? System.currentTimeMillis() : 0L;
259        log.info(this, " begin for '", scriptName, "'");
260
261        try {
262            stream = new TokenStream();
263            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions);
264            lexer.line = lexer.pendingLine = lineOffset + 1;
265            line = lineOffset;
266
267            // Set up first token (skips opening EOL.)
268            k = -1;
269            next();
270            // Begin parse.
271            return program(scriptName, allowPropertyFunction);
272        } catch (final Exception e) {
273            handleParseException(e);
274
275            return null;
276        } finally {
277            final String end = this + " end '" + scriptName + "'";
278            if (isTimingEnabled) {
279                env._timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
280                log.info(end, "' in ", System.currentTimeMillis() - t0, " ms");
281            } else {
282                log.info(end);
283            }
284        }
285    }
286
287    /**
288     * Parse and return the list of function parameter list. A comma
289     * separated list of function parameter identifiers is expected to be parsed.
290     * Errors will be thrown and the error manager will contain information
291     * if parsing should fail. This method is used to check if parameter Strings
292     * passed to "Function" constructor is a valid or not.
293     *
294     * @return the list of IdentNodes representing the formal parameter list
295     */
296    public List<IdentNode> parseFormalParameterList() {
297        try {
298            stream = new TokenStream();
299            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
300
301            // Set up first token (skips opening EOL.)
302            k = -1;
303            next();
304
305            return formalParameterList(TokenType.EOF);
306        } catch (final Exception e) {
307            handleParseException(e);
308            return null;
309        }
310    }
311
312    /**
313     * Execute parse and return the resulting function node.
314     * Errors will be thrown and the error manager will contain information
315     * if parsing should fail. This method is used to check if code String
316     * passed to "Function" constructor is a valid function body or not.
317     *
318     * @return function node resulting from successful parse
319     */
320    public FunctionNode parseFunctionBody() {
321        try {
322            stream = new TokenStream();
323            lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
324            final int functionLine = line;
325
326            // Set up first token (skips opening EOL.)
327            k = -1;
328            next();
329
330            // Make a fake token for the function.
331            final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
332            // Set up the function to append elements.
333
334            FunctionNode function = newFunctionNode(
335                functionToken,
336                new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()),
337                new ArrayList<IdentNode>(),
338                FunctionNode.Kind.NORMAL,
339                functionLine);
340
341            functionDeclarations = new ArrayList<>();
342            sourceElements(false);
343            addFunctionDeclarations(function);
344            functionDeclarations = null;
345
346            expect(EOF);
347
348            function.setFinish(source.getLength() - 1);
349
350            function = restoreFunctionNode(function, token); //commit code
351            function = function.setBody(lc, function.getBody().setNeedsScope(lc));
352            return function;
353        } catch (final Exception e) {
354            handleParseException(e);
355            return null;
356        }
357    }
358
359    private void handleParseException(final Exception e) {
360        // Extract message from exception.  The message will be in error
361        // message format.
362        String message = e.getMessage();
363
364        // If empty message.
365        if (message == null) {
366            message = e.toString();
367        }
368
369        // Issue message.
370        if (e instanceof ParserException) {
371            errors.error((ParserException)e);
372        } else {
373            errors.error(message);
374        }
375
376        if (env._dump_on_error) {
377            e.printStackTrace(env.getErr());
378        }
379    }
380
381    /**
382     * Skip to a good parsing recovery point.
383     */
384    private void recover(final Exception e) {
385        if (e != null) {
386            // Extract message from exception.  The message will be in error
387            // message format.
388            String message = e.getMessage();
389
390            // If empty message.
391            if (message == null) {
392                message = e.toString();
393            }
394
395            // Issue message.
396            if (e instanceof ParserException) {
397                errors.error((ParserException)e);
398            } else {
399                errors.error(message);
400            }
401
402            if (env._dump_on_error) {
403                e.printStackTrace(env.getErr());
404            }
405        }
406
407        // Skip to a recovery point.
408loop:
409        while (true) {
410            switch (type) {
411            case EOF:
412                // Can not go any further.
413                break loop;
414            case EOL:
415            case SEMICOLON:
416            case RBRACE:
417                // Good recovery points.
418                next();
419                break loop;
420            default:
421                // So we can recover after EOL.
422                nextOrEOL();
423                break;
424            }
425        }
426    }
427
428    /**
429     * Set up a new block.
430     *
431     * @return New block.
432     */
433    private Block newBlock() {
434        return lc.push(new Block(token, Token.descPosition(token)));
435    }
436
437    /**
438     * Set up a new function block.
439     *
440     * @param ident Name of function.
441     * @return New block.
442     */
443    private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
444        // Build function name.
445        final StringBuilder sb = new StringBuilder();
446
447        final FunctionNode parentFunction = lc.getCurrentFunction();
448        if (parentFunction != null && !parentFunction.isProgram()) {
449            sb.append(parentFunction.getName()).append('$');
450        }
451
452        assert ident.getName() != null;
453        sb.append(ident.getName());
454
455        final String name = namespace.uniqueName(sb.toString());
456        assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name;
457
458        int flags = 0;
459        if (isStrictMode) {
460            flags |= FunctionNode.IS_STRICT;
461        }
462        if (parentFunction == null) {
463            flags |= FunctionNode.IS_PROGRAM;
464        }
465
466        // Start new block.
467        final FunctionNode functionNode =
468            new FunctionNode(
469                source,
470                nextFunctionId++,
471                functionLine,
472                token,
473                Token.descPosition(token),
474                startToken,
475                namespace,
476                ident,
477                name,
478                parameters,
479                kind,
480                flags,
481                sourceURL);
482
483        lc.push(functionNode);
484        // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
485        // FunctionNode.
486        newBlock();
487
488        return functionNode;
489    }
490
491    /**
492     * Restore the current block.
493     */
494    private Block restoreBlock(final Block block) {
495        return lc.pop(block);
496    }
497
498
499    private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
500        final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
501
502        return lc.pop(functionNode).
503            setBody(lc, newBody).
504            setLastToken(lc, lastToken).
505            setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
506    }
507
508    /**
509     * Get the statements in a block.
510     * @return Block statements.
511     */
512    private Block getBlock(final boolean needsBraces) {
513        // Set up new block. Captures LBRACE.
514        Block newBlock = newBlock();
515        try {
516            // Block opening brace.
517            if (needsBraces) {
518                expect(LBRACE);
519            }
520            // Accumulate block statements.
521            statementList();
522
523        } finally {
524            newBlock = restoreBlock(newBlock);
525        }
526
527        final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
528
529        // Block closing brace.
530        if (needsBraces) {
531            expect(RBRACE);
532        }
533
534        newBlock.setFinish(possibleEnd);
535
536        return newBlock;
537    }
538
539    /**
540     * Get all the statements generated by a single statement.
541     * @return Statements.
542     */
543    private Block getStatement() {
544        if (type == LBRACE) {
545            return getBlock(true);
546        }
547        // Set up new block. Captures first token.
548        Block newBlock = newBlock();
549        try {
550            statement();
551        } finally {
552            newBlock = restoreBlock(newBlock);
553        }
554        return newBlock;
555    }
556
557    /**
558     * Detect calls to special functions.
559     * @param ident Called function.
560     */
561    private void detectSpecialFunction(final IdentNode ident) {
562        final String name = ident.getName();
563
564        if (EVAL.symbolName().equals(name)) {
565            markEval(lc);
566        }
567    }
568
569    /**
570     * Detect use of special properties.
571     * @param ident Referenced property.
572     */
573    private void detectSpecialProperty(final IdentNode ident) {
574        if (isArguments(ident)) {
575            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
576        }
577    }
578
579    private static boolean isArguments(final String name) {
580        return ARGUMENTS_NAME.equals(name);
581    }
582
583    private static boolean isArguments(final IdentNode ident) {
584        return isArguments(ident.getName());
585    }
586
587    /**
588     * Tells whether a IdentNode can be used as L-value of an assignment
589     *
590     * @param ident IdentNode to be checked
591     * @return whether the ident can be used as L-value
592     */
593    private static boolean checkIdentLValue(final IdentNode ident) {
594        return Token.descType(ident.getToken()).getKind() != TokenKind.KEYWORD;
595    }
596
597    /**
598     * Verify an assignment expression.
599     * @param op  Operation token.
600     * @param lhs Left hand side expression.
601     * @param rhs Right hand side expression.
602     * @return Verified expression.
603     */
604    private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) {
605        final TokenType opType = Token.descType(op);
606
607        switch (opType) {
608        case ASSIGN:
609        case ASSIGN_ADD:
610        case ASSIGN_BIT_AND:
611        case ASSIGN_BIT_OR:
612        case ASSIGN_BIT_XOR:
613        case ASSIGN_DIV:
614        case ASSIGN_MOD:
615        case ASSIGN_MUL:
616        case ASSIGN_SAR:
617        case ASSIGN_SHL:
618        case ASSIGN_SHR:
619        case ASSIGN_SUB:
620            if (!(lhs instanceof AccessNode ||
621                  lhs instanceof IndexNode ||
622                  lhs instanceof IdentNode)) {
623                return referenceError(lhs, rhs, env._early_lvalue_error);
624            }
625
626            if (lhs instanceof IdentNode) {
627                if (!checkIdentLValue((IdentNode)lhs)) {
628                    return referenceError(lhs, rhs, false);
629                }
630                verifyStrictIdent((IdentNode)lhs, "assignment");
631            }
632            break;
633
634        default:
635            break;
636        }
637
638        // Build up node.
639        if(BinaryNode.isLogical(opType)) {
640            return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
641        }
642        return new BinaryNode(op, lhs, rhs);
643    }
644
645
646    /**
647     * Reduce increment/decrement to simpler operations.
648     * @param firstToken First token.
649     * @param tokenType  Operation token (INCPREFIX/DEC.)
650     * @param expression Left hand side expression.
651     * @param isPostfix  Prefix or postfix.
652     * @return           Reduced expression.
653     */
654    private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) {
655        if (isPostfix) {
656            return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
657        }
658
659        return new UnaryNode(firstToken, expression);
660    }
661
662    /**
663     * -----------------------------------------------------------------------
664     *
665     * Grammar based on
666     *
667     *      ECMAScript Language Specification
668     *      ECMA-262 5th Edition / December 2009
669     *
670     * -----------------------------------------------------------------------
671     */
672
673    /**
674     * Program :
675     *      SourceElements?
676     *
677     * See 14
678     *
679     * Parse the top level script.
680     */
681    private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) {
682        // Make a pseudo-token for the script holding its start and length.
683        final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
684        final int  functionLine  = line;
685        // Set up the script to append elements.
686
687        FunctionNode script = newFunctionNode(
688            functionToken,
689            new IdentNode(functionToken, Token.descPosition(functionToken), scriptName),
690            new ArrayList<IdentNode>(),
691            FunctionNode.Kind.SCRIPT,
692            functionLine);
693
694        functionDeclarations = new ArrayList<>();
695        sourceElements(allowPropertyFunction);
696        addFunctionDeclarations(script);
697        functionDeclarations = null;
698
699        expect(EOF);
700
701        script.setFinish(source.getLength() - 1);
702
703        script = restoreFunctionNode(script, token); //commit code
704        script = script.setBody(lc, script.getBody().setNeedsScope(lc));
705        // user may have directive comment to set sourceURL
706        if (sourceURL != null) {
707            script = script.setSourceURL(lc, sourceURL);
708        }
709
710        return script;
711    }
712
713    /**
714     * Directive value or null if statement is not a directive.
715     *
716     * @param stmt Statement to be checked
717     * @return Directive value if the given statement is a directive
718     */
719    private String getDirective(final Node stmt) {
720        if (stmt instanceof ExpressionStatement) {
721            final Node expr = ((ExpressionStatement)stmt).getExpression();
722            if (expr instanceof LiteralNode) {
723                final LiteralNode<?> lit = (LiteralNode<?>)expr;
724                final long litToken = lit.getToken();
725                final TokenType tt = Token.descType(litToken);
726                // A directive is either a string or an escape string
727                if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) {
728                    // Make sure that we don't unescape anything. Return as seen in source!
729                    return source.getString(lit.getStart(), Token.descLength(litToken));
730                }
731            }
732        }
733
734        return null;
735    }
736
737    /**
738     * SourceElements :
739     *      SourceElement
740     *      SourceElements SourceElement
741     *
742     * See 14
743     *
744     * Parse the elements of the script or function.
745     */
746    private void sourceElements(final boolean shouldAllowPropertyFunction) {
747        List<Node>    directiveStmts        = null;
748        boolean       checkDirective        = true;
749        boolean       allowPropertyFunction = shouldAllowPropertyFunction;
750        final boolean oldStrictMode         = isStrictMode;
751
752
753        try {
754            // If is a script, then process until the end of the script.
755            while (type != EOF) {
756                // Break if the end of a code block.
757                if (type == RBRACE) {
758                    break;
759                }
760
761                try {
762                    // Get the next element.
763                    statement(true, allowPropertyFunction);
764                    allowPropertyFunction = false;
765
766                    // check for directive prologues
767                    if (checkDirective) {
768                        // skip any debug statement like line number to get actual first line
769                        final Node lastStatement = lc.getLastStatement();
770
771                        // get directive prologue, if any
772                        final String directive = getDirective(lastStatement);
773
774                        // If we have seen first non-directive statement,
775                        // no more directive statements!!
776                        checkDirective = directive != null;
777
778                        if (checkDirective) {
779                            if (!oldStrictMode) {
780                                if (directiveStmts == null) {
781                                    directiveStmts = new ArrayList<>();
782                                }
783                                directiveStmts.add(lastStatement);
784                            }
785
786                            // handle use strict directive
787                            if ("use strict".equals(directive)) {
788                                isStrictMode = true;
789                                final FunctionNode function = lc.getCurrentFunction();
790                                lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
791
792                                // We don't need to check these, if lexical environment is already strict
793                                if (!oldStrictMode && directiveStmts != null) {
794                                    // check that directives preceding this one do not violate strictness
795                                    for (final Node statement : directiveStmts) {
796                                        // the get value will force unescape of preceeding
797                                        // escaped string directives
798                                        getValue(statement.getToken());
799                                    }
800
801                                    // verify that function name as well as parameter names
802                                    // satisfy strict mode restrictions.
803                                    verifyStrictIdent(function.getIdent(), "function name");
804                                    for (final IdentNode param : function.getParameters()) {
805                                        verifyStrictIdent(param, "function parameter");
806                                    }
807                                }
808                            }
809                        }
810                    }
811                } catch (final Exception e) {
812                    //recover parsing
813                    recover(e);
814                }
815
816                // No backtracking from here on.
817                stream.commit(k);
818            }
819        } finally {
820            isStrictMode = oldStrictMode;
821        }
822    }
823
824    /**
825     * Statement :
826     *      Block
827     *      VariableStatement
828     *      EmptyStatement
829     *      ExpressionStatement
830     *      IfStatement
831     *      IterationStatement
832     *      ContinueStatement
833     *      BreakStatement
834     *      ReturnStatement
835     *      WithStatement
836     *      LabelledStatement
837     *      SwitchStatement
838     *      ThrowStatement
839     *      TryStatement
840     *      DebuggerStatement
841     *
842     * see 12
843     *
844     * Parse any of the basic statement types.
845     */
846    private void statement() {
847        statement(false, false);
848    }
849
850    /**
851     * @param topLevel does this statement occur at the "top level" of a script or a function?
852     */
853    private void statement(final boolean topLevel, final boolean allowPropertyFunction) {
854        if (type == FUNCTION) {
855            // As per spec (ECMA section 12), function declarations as arbitrary statement
856            // is not "portable". Implementation can issue a warning or disallow the same.
857            functionExpression(true, topLevel);
858            return;
859        }
860
861        switch (type) {
862        case LBRACE:
863            block();
864            break;
865        case VAR:
866            variableStatement(true);
867            break;
868        case SEMICOLON:
869            emptyStatement();
870            break;
871        case IF:
872            ifStatement();
873            break;
874        case FOR:
875            forStatement();
876            break;
877        case WHILE:
878            whileStatement();
879            break;
880        case DO:
881            doStatement();
882            break;
883        case CONTINUE:
884            continueStatement();
885            break;
886        case BREAK:
887            breakStatement();
888            break;
889        case RETURN:
890            returnStatement();
891            break;
892        case YIELD:
893            yieldStatement();
894            break;
895        case WITH:
896            withStatement();
897            break;
898        case SWITCH:
899            switchStatement();
900            break;
901        case THROW:
902            throwStatement();
903            break;
904        case TRY:
905            tryStatement();
906            break;
907        case DEBUGGER:
908            debuggerStatement();
909            break;
910        case RPAREN:
911        case RBRACKET:
912        case EOF:
913            expect(SEMICOLON);
914            break;
915        default:
916            if (env._const_as_var && type == CONST) {
917                variableStatement(true);
918                break;
919            }
920
921            if (type == IDENT || isNonStrictModeIdent()) {
922                if (T(k + 1) == COLON) {
923                    labelStatement();
924                    return;
925                }
926                if(allowPropertyFunction) {
927                    final String ident = (String)getValue();
928                    final long propertyToken = token;
929                    final int propertyLine = line;
930                    if("get".equals(ident)) {
931                        next();
932                        addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
933                        return;
934                    } else if("set".equals(ident)) {
935                        next();
936                        addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
937                        return;
938                    }
939                }
940            }
941
942            expressionStatement();
943            break;
944        }
945    }
946
947    private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) {
948        final FunctionNode fn = propertyFunction.functionNode;
949        functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn));
950    }
951
952    /**
953     * block :
954     *      { StatementList? }
955     *
956     * see 12.1
957     *
958     * Parse a statement block.
959     */
960    private void block() {
961        appendStatement(new BlockStatement(line, getBlock(true)));
962    }
963
964    /**
965     * StatementList :
966     *      Statement
967     *      StatementList Statement
968     *
969     * See 12.1
970     *
971     * Parse a list of statements.
972     */
973    private void statementList() {
974        // Accumulate statements until end of list. */
975loop:
976        while (type != EOF) {
977            switch (type) {
978            case EOF:
979            case CASE:
980            case DEFAULT:
981            case RBRACE:
982                break loop;
983            default:
984                break;
985            }
986
987            // Get next statement.
988            statement();
989        }
990    }
991
992    /**
993     * Make sure that in strict mode, the identifier name used is allowed.
994     *
995     * @param ident         Identifier that is verified
996     * @param contextString String used in error message to give context to the user
997     */
998    private void verifyStrictIdent(final IdentNode ident, final String contextString) {
999        if (isStrictMode) {
1000            switch (ident.getName()) {
1001            case "eval":
1002            case "arguments":
1003                throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1004            default:
1005                break;
1006            }
1007
1008            if (ident.isFutureStrictName()) {
1009                throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1010            }
1011        }
1012    }
1013
1014    /**
1015     * VariableStatement :
1016     *      var VariableDeclarationList ;
1017     *
1018     * VariableDeclarationList :
1019     *      VariableDeclaration
1020     *      VariableDeclarationList , VariableDeclaration
1021     *
1022     * VariableDeclaration :
1023     *      Identifier Initializer?
1024     *
1025     * Initializer :
1026     *      = AssignmentExpression
1027     *
1028     * See 12.2
1029     *
1030     * Parse a VAR statement.
1031     * @param isStatement True if a statement (not used in a FOR.)
1032     */
1033    private List<VarNode> variableStatement(final boolean isStatement) {
1034        // VAR tested in caller.
1035        next();
1036
1037        final List<VarNode> vars = new ArrayList<>();
1038
1039        while (true) {
1040            // Get starting token.
1041            final int  varLine  = line;
1042            final long varToken = token;
1043            // Get name of var.
1044            final IdentNode name = getIdent();
1045            verifyStrictIdent(name, "variable name");
1046
1047            // Assume no init.
1048            Expression init = null;
1049
1050            // Look for initializer assignment.
1051            if (type == ASSIGN) {
1052                next();
1053
1054                // Get initializer expression. Suppress IN if not statement.
1055                defaultNames.push(name);
1056                try {
1057                    init = assignmentExpression(!isStatement);
1058                } finally {
1059                    defaultNames.pop();
1060                }
1061            }
1062
1063            // Allocate var node.
1064            final VarNode var = new VarNode(varLine, varToken, finish, name, init);
1065            vars.add(var);
1066            appendStatement(var);
1067
1068            if (type != COMMARIGHT) {
1069                break;
1070            }
1071            next();
1072        }
1073
1074        // If is a statement then handle end of line.
1075        if (isStatement) {
1076            final boolean semicolon = type == SEMICOLON;
1077            endOfLine();
1078            if (semicolon) {
1079                lc.getCurrentBlock().setFinish(finish);
1080            }
1081        }
1082
1083        return vars;
1084    }
1085
1086    /**
1087     * EmptyStatement :
1088     *      ;
1089     *
1090     * See 12.3
1091     *
1092     * Parse an empty statement.
1093     */
1094    private void emptyStatement() {
1095        if (env._empty_statements) {
1096            appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
1097        }
1098
1099        // SEMICOLON checked in caller.
1100        next();
1101    }
1102
1103    /**
1104     * ExpressionStatement :
1105     *      Expression ; // [lookahead ~( or  function )]
1106     *
1107     * See 12.4
1108     *
1109     * Parse an expression used in a statement block.
1110     */
1111    private void expressionStatement() {
1112        // Lookahead checked in caller.
1113        final int  expressionLine  = line;
1114        final long expressionToken = token;
1115
1116        // Get expression and add as statement.
1117        final Expression expression = expression();
1118
1119        ExpressionStatement expressionStatement = null;
1120        if (expression != null) {
1121            expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression);
1122            appendStatement(expressionStatement);
1123        } else {
1124            expect(null);
1125        }
1126
1127        endOfLine();
1128
1129        if (expressionStatement != null) {
1130            expressionStatement.setFinish(finish);
1131            lc.getCurrentBlock().setFinish(finish);
1132        }
1133    }
1134
1135    /**
1136     * IfStatement :
1137     *      if ( Expression ) Statement else Statement
1138     *      if ( Expression ) Statement
1139     *
1140     * See 12.5
1141     *
1142     * Parse an IF statement.
1143     */
1144    private void ifStatement() {
1145        // Capture IF token.
1146        final int  ifLine  = line;
1147        final long ifToken = token;
1148         // IF tested in caller.
1149        next();
1150
1151        expect(LPAREN);
1152        final Expression test = expression();
1153        expect(RPAREN);
1154        final Block pass = getStatement();
1155
1156        Block fail = null;
1157        if (type == ELSE) {
1158            next();
1159            fail = getStatement();
1160        }
1161
1162        appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1163    }
1164
1165    /**
1166     * ... IterationStatement:
1167     *           ...
1168     *           for ( Expression[NoIn]?; Expression? ; Expression? ) Statement
1169     *           for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement
1170     *           for ( LeftHandSideExpression in Expression ) Statement
1171     *           for ( var VariableDeclaration[NoIn] in Expression ) Statement
1172     *
1173     * See 12.6
1174     *
1175     * Parse a FOR statement.
1176     */
1177    private void forStatement() {
1178        // Create FOR node, capturing FOR token.
1179        ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, ForNode.IS_FOR);
1180
1181        lc.push(forNode);
1182
1183        try {
1184            // FOR tested in caller.
1185            next();
1186
1187            // Nashorn extension: for each expression.
1188            // iterate property values rather than property names.
1189            if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1190                forNode = forNode.setIsForEach(lc);
1191                next();
1192            }
1193
1194            expect(LPAREN);
1195
1196            List<VarNode> vars = null;
1197
1198            switch (type) {
1199            case VAR:
1200                // Var statements captured in for outer block.
1201                vars = variableStatement(false);
1202                break;
1203            case SEMICOLON:
1204                break;
1205            default:
1206                if (env._const_as_var && type == CONST) {
1207                    // Var statements captured in for outer block.
1208                    vars = variableStatement(false);
1209                    break;
1210                }
1211
1212                final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
1213                forNode = forNode.setInit(lc, expression);
1214                break;
1215            }
1216
1217            switch (type) {
1218            case SEMICOLON:
1219                // for (init; test; modify)
1220
1221                // for each (init; test; modify) is invalid
1222                if (forNode.isForEach()) {
1223                    throw error(AbstractParser.message("for.each.without.in"), token);
1224                }
1225
1226                expect(SEMICOLON);
1227                if (type != SEMICOLON) {
1228                    forNode = forNode.setTest(lc, joinPredecessorExpression());
1229                }
1230                expect(SEMICOLON);
1231                if (type != RPAREN) {
1232                    forNode = forNode.setModify(lc, joinPredecessorExpression());
1233                }
1234                break;
1235
1236            case IN:
1237                forNode = forNode.setIsForIn(lc).setTest(lc, new JoinPredecessorExpression());
1238                if (vars != null) {
1239                    // for (var i in obj)
1240                    if (vars.size() == 1) {
1241                        forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
1242                    } else {
1243                        // for (var i, j in obj) is invalid
1244                        throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
1245                    }
1246
1247                } else {
1248                    // for (expr in obj)
1249                    final Node init = forNode.getInit();
1250                    assert init != null : "for..in init expression can not be null here";
1251
1252                    // check if initial expression is a valid L-value
1253                    if (!(init instanceof AccessNode ||
1254                          init instanceof IndexNode ||
1255                          init instanceof IdentNode)) {
1256                        throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1257                    }
1258
1259                    if (init instanceof IdentNode) {
1260                        if (!checkIdentLValue((IdentNode)init)) {
1261                            throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1262                        }
1263                        verifyStrictIdent((IdentNode)init, "for-in iterator");
1264                    }
1265                }
1266
1267                next();
1268
1269                // Get the collection expression.
1270                forNode = forNode.setModify(lc, joinPredecessorExpression());
1271                break;
1272
1273            default:
1274                expect(SEMICOLON);
1275                break;
1276            }
1277
1278            expect(RPAREN);
1279
1280            // Set the for body.
1281            final Block body = getStatement();
1282            forNode = forNode.setBody(lc, body);
1283            forNode.setFinish(body.getFinish());
1284
1285            appendStatement(forNode);
1286        } finally {
1287            lc.pop(forNode);
1288        }
1289     }
1290
1291    /**
1292     * ... IterationStatement :
1293     *           ...
1294     *           Expression[NoIn]?; Expression? ; Expression?
1295     *           var VariableDeclarationList[NoIn]; Expression? ; Expression?
1296     *           LeftHandSideExpression in Expression
1297     *           var VariableDeclaration[NoIn] in Expression
1298     *
1299     * See 12.6
1300     *
1301     * Parse the control section of a FOR statement.  Also used for
1302     * comprehensions.
1303     * @param forNode Owning FOR.
1304     */
1305
1306
1307    /**
1308     * ...IterationStatement :
1309     *           ...
1310     *           while ( Expression ) Statement
1311     *           ...
1312     *
1313     * See 12.6
1314     *
1315     * Parse while statement.
1316     */
1317    private void whileStatement() {
1318        // Capture WHILE token.
1319        final long whileToken = token;
1320        // WHILE tested in caller.
1321        next();
1322
1323        // Construct WHILE node.
1324        WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false);
1325        lc.push(whileNode);
1326
1327        try {
1328            expect(LPAREN);
1329            final int whileLine = line;
1330            final JoinPredecessorExpression test = joinPredecessorExpression();
1331            expect(RPAREN);
1332            final Block body = getStatement();
1333            appendStatement(whileNode =
1334                new WhileNode(whileLine, whileToken, finish, false).
1335                    setTest(lc, test).
1336                    setBody(lc, body));
1337        } finally {
1338            lc.pop(whileNode);
1339        }
1340    }
1341
1342    /**
1343     * ...IterationStatement :
1344     *           ...
1345     *           do Statement while( Expression ) ;
1346     *           ...
1347     *
1348     * See 12.6
1349     *
1350     * Parse DO WHILE statement.
1351     */
1352    private void doStatement() {
1353        // Capture DO token.
1354        final long doToken = token;
1355        // DO tested in the caller.
1356        next();
1357
1358        WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true);
1359        lc.push(doWhileNode);
1360
1361        try {
1362           // Get DO body.
1363            final Block body = getStatement();
1364
1365            expect(WHILE);
1366            expect(LPAREN);
1367            final int doLine = line;
1368            final JoinPredecessorExpression test = joinPredecessorExpression();
1369            expect(RPAREN);
1370
1371            if (type == SEMICOLON) {
1372                endOfLine();
1373            }
1374            doWhileNode.setFinish(finish);
1375
1376            //line number is last
1377            appendStatement(doWhileNode =
1378                new WhileNode(doLine, doToken, finish, true).
1379                    setBody(lc, body).
1380                    setTest(lc, test));
1381        } finally {
1382            lc.pop(doWhileNode);
1383        }
1384    }
1385
1386    /**
1387     * ContinueStatement :
1388     *      continue Identifier? ; // [no LineTerminator here]
1389     *
1390     * See 12.7
1391     *
1392     * Parse CONTINUE statement.
1393     */
1394    private void continueStatement() {
1395        // Capture CONTINUE token.
1396        final int  continueLine  = line;
1397        final long continueToken = token;
1398        // CONTINUE tested in caller.
1399        nextOrEOL();
1400
1401        LabelNode labelNode = null;
1402
1403        // SEMICOLON or label.
1404        switch (type) {
1405        case RBRACE:
1406        case SEMICOLON:
1407        case EOL:
1408        case EOF:
1409            break;
1410
1411        default:
1412            final IdentNode ident = getIdent();
1413            labelNode = lc.findLabel(ident.getName());
1414
1415            if (labelNode == null) {
1416                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
1417            }
1418
1419            break;
1420        }
1421
1422        final String labelName = labelNode == null ? null : labelNode.getLabelName();
1423        final LoopNode targetNode = lc.getContinueTo(labelName);
1424
1425        if (targetNode == null) {
1426            throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
1427        }
1428
1429        endOfLine();
1430
1431        // Construct and add CONTINUE node.
1432        appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName));
1433    }
1434
1435    /**
1436     * BreakStatement :
1437     *      break Identifier? ; // [no LineTerminator here]
1438     *
1439     * See 12.8
1440     *
1441     */
1442    private void breakStatement() {
1443        // Capture BREAK token.
1444        final int  breakLine  = line;
1445        final long breakToken = token;
1446        // BREAK tested in caller.
1447        nextOrEOL();
1448
1449        LabelNode labelNode = null;
1450
1451        // SEMICOLON or label.
1452        switch (type) {
1453        case RBRACE:
1454        case SEMICOLON:
1455        case EOL:
1456        case EOF:
1457            break;
1458
1459        default:
1460            final IdentNode ident = getIdent();
1461            labelNode = lc.findLabel(ident.getName());
1462
1463            if (labelNode == null) {
1464                throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
1465            }
1466
1467            break;
1468        }
1469
1470        //either an explicit label - then get its node or just a "break" - get first breakable
1471        //targetNode is what we are breaking out from.
1472        final String labelName = labelNode == null ? null : labelNode.getLabelName();
1473        final BreakableNode targetNode = lc.getBreakable(labelName);
1474        if (targetNode == null) {
1475            throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
1476        }
1477
1478        endOfLine();
1479
1480        // Construct and add BREAK node.
1481        appendStatement(new BreakNode(breakLine, breakToken, finish, labelName));
1482    }
1483
1484    /**
1485     * ReturnStatement :
1486     *      return Expression? ; // [no LineTerminator here]
1487     *
1488     * See 12.9
1489     *
1490     * Parse RETURN statement.
1491     */
1492    private void returnStatement() {
1493        // check for return outside function
1494        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
1495            throw error(AbstractParser.message("invalid.return"));
1496        }
1497
1498        // Capture RETURN token.
1499        final int  returnLine  = line;
1500        final long returnToken = token;
1501        // RETURN tested in caller.
1502        nextOrEOL();
1503
1504        Expression expression = null;
1505
1506        // SEMICOLON or expression.
1507        switch (type) {
1508        case RBRACE:
1509        case SEMICOLON:
1510        case EOL:
1511        case EOF:
1512            break;
1513
1514        default:
1515            expression = expression();
1516            break;
1517        }
1518
1519        endOfLine();
1520
1521        // Construct and add RETURN node.
1522        appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
1523    }
1524
1525    /**
1526     * YieldStatement :
1527     *      yield Expression? ; // [no LineTerminator here]
1528     *
1529     * JavaScript 1.8
1530     *
1531     * Parse YIELD statement.
1532     */
1533    private void yieldStatement() {
1534        // Capture YIELD token.
1535        final int  yieldLine  = line;
1536        final long yieldToken = token;
1537        // YIELD tested in caller.
1538        nextOrEOL();
1539
1540        Expression expression = null;
1541
1542        // SEMICOLON or expression.
1543        switch (type) {
1544        case RBRACE:
1545        case SEMICOLON:
1546        case EOL:
1547        case EOF:
1548            break;
1549
1550        default:
1551            expression = expression();
1552            break;
1553        }
1554
1555        endOfLine();
1556
1557        // Construct and add YIELD node.
1558        appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
1559    }
1560
1561    /**
1562     * WithStatement :
1563     *      with ( Expression ) Statement
1564     *
1565     * See 12.10
1566     *
1567     * Parse WITH statement.
1568     */
1569    private void withStatement() {
1570        // Capture WITH token.
1571        final int  withLine  = line;
1572        final long withToken = token;
1573        // WITH tested in caller.
1574        next();
1575
1576        // ECMA 12.10.1 strict mode restrictions
1577        if (isStrictMode) {
1578            throw error(AbstractParser.message("strict.no.with"), withToken);
1579        }
1580
1581        // Get WITH expression.
1582        WithNode withNode = new WithNode(withLine, withToken, finish);
1583
1584        try {
1585            lc.push(withNode);
1586            expect(LPAREN);
1587            withNode = withNode.setExpression(lc, expression());
1588            expect(RPAREN);
1589            withNode = withNode.setBody(lc, getStatement());
1590        } finally {
1591            lc.pop(withNode);
1592        }
1593
1594        appendStatement(withNode);
1595    }
1596
1597    /**
1598     * SwitchStatement :
1599     *      switch ( Expression ) CaseBlock
1600     *
1601     * CaseBlock :
1602     *      { CaseClauses? }
1603     *      { CaseClauses? DefaultClause CaseClauses }
1604     *
1605     * CaseClauses :
1606     *      CaseClause
1607     *      CaseClauses CaseClause
1608     *
1609     * CaseClause :
1610     *      case Expression : StatementList?
1611     *
1612     * DefaultClause :
1613     *      default : StatementList?
1614     *
1615     * See 12.11
1616     *
1617     * Parse SWITCH statement.
1618     */
1619    private void switchStatement() {
1620        final int  switchLine  = line;
1621        final long switchToken = token;
1622        // SWITCH tested in caller.
1623        next();
1624
1625        // Create and add switch statement.
1626        SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
1627        lc.push(switchNode);
1628
1629        try {
1630            expect(LPAREN);
1631            switchNode = switchNode.setExpression(lc, expression());
1632            expect(RPAREN);
1633
1634            expect(LBRACE);
1635
1636            // Prepare to accumulate cases.
1637            final List<CaseNode> cases = new ArrayList<>();
1638            CaseNode defaultCase = null;
1639
1640            while (type != RBRACE) {
1641                // Prepare for next case.
1642                Expression caseExpression = null;
1643                final long caseToken = token;
1644
1645                switch (type) {
1646                case CASE:
1647                    next();
1648                    caseExpression = expression();
1649                    break;
1650
1651                case DEFAULT:
1652                    if (defaultCase != null) {
1653                        throw error(AbstractParser.message("duplicate.default.in.switch"));
1654                    }
1655                    next();
1656                    break;
1657
1658                default:
1659                    // Force an error.
1660                    expect(CASE);
1661                    break;
1662                }
1663
1664                expect(COLON);
1665
1666                // Get CASE body.
1667                final Block statements = getBlock(false);
1668                final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
1669                statements.setFinish(finish);
1670
1671                if (caseExpression == null) {
1672                    defaultCase = caseNode;
1673                }
1674
1675                cases.add(caseNode);
1676            }
1677
1678            switchNode = switchNode.setCases(lc, cases, defaultCase);
1679            next();
1680            switchNode.setFinish(finish);
1681
1682            appendStatement(switchNode);
1683        } finally {
1684            lc.pop(switchNode);
1685        }
1686    }
1687
1688    /**
1689     * LabelledStatement :
1690     *      Identifier : Statement
1691     *
1692     * See 12.12
1693     *
1694     * Parse label statement.
1695     */
1696    private void labelStatement() {
1697        // Capture label token.
1698        final long labelToken = token;
1699        // Get label ident.
1700        final IdentNode ident = getIdent();
1701
1702        expect(COLON);
1703
1704        if (lc.findLabel(ident.getName()) != null) {
1705            throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
1706        }
1707
1708        LabelNode labelNode = new LabelNode(line, labelToken, finish, ident.getName(), null);
1709        try {
1710            lc.push(labelNode);
1711            labelNode = labelNode.setBody(lc, getStatement());
1712            labelNode.setFinish(finish);
1713            appendStatement(labelNode);
1714        } finally {
1715            assert lc.peek() instanceof LabelNode;
1716            lc.pop(labelNode);
1717        }
1718    }
1719
1720   /**
1721     * ThrowStatement :
1722     *      throw Expression ; // [no LineTerminator here]
1723     *
1724     * See 12.13
1725     *
1726     * Parse throw statement.
1727     */
1728    private void throwStatement() {
1729        // Capture THROW token.
1730        final int  throwLine  = line;
1731        final long throwToken = token;
1732        // THROW tested in caller.
1733        nextOrEOL();
1734
1735        Expression expression = null;
1736
1737        // SEMICOLON or expression.
1738        switch (type) {
1739        case RBRACE:
1740        case SEMICOLON:
1741        case EOL:
1742            break;
1743
1744        default:
1745            expression = expression();
1746            break;
1747        }
1748
1749        if (expression == null) {
1750            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
1751        }
1752
1753        endOfLine();
1754
1755        appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false));
1756    }
1757
1758    /**
1759     * TryStatement :
1760     *      try Block Catch
1761     *      try Block Finally
1762     *      try Block Catch Finally
1763     *
1764     * Catch :
1765     *      catch( Identifier if Expression ) Block
1766     *      catch( Identifier ) Block
1767     *
1768     * Finally :
1769     *      finally Block
1770     *
1771     * See 12.14
1772     *
1773     * Parse TRY statement.
1774     */
1775    private void tryStatement() {
1776        // Capture TRY token.
1777        final int  tryLine  = line;
1778        final long tryToken = token;
1779        // TRY tested in caller.
1780        next();
1781
1782        // Container block needed to act as target for labeled break statements
1783        final int startLine = line;
1784        Block outer = newBlock();
1785
1786        // Create try.
1787
1788        try {
1789            final Block       tryBody     = getBlock(true);
1790            final List<Block> catchBlocks = new ArrayList<>();
1791
1792            while (type == CATCH) {
1793                final int  catchLine  = line;
1794                final long catchToken = token;
1795                next();
1796                expect(LPAREN);
1797                final IdentNode exception = getIdent();
1798
1799                // ECMA 12.4.1 strict mode restrictions
1800                verifyStrictIdent(exception, "catch argument");
1801
1802                // Nashorn extension: catch clause can have optional
1803                // condition. So, a single try can have more than one
1804                // catch clause each with it's own condition.
1805                final Expression ifExpression;
1806                if (!env._no_syntax_extensions && type == IF) {
1807                    next();
1808                    // Get the exception condition.
1809                    ifExpression = expression();
1810                } else {
1811                    ifExpression = null;
1812                }
1813
1814                expect(RPAREN);
1815
1816                Block catchBlock = newBlock();
1817                try {
1818                    // Get CATCH body.
1819                    final Block catchBody = getBlock(true);
1820                    final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
1821                    appendStatement(catchNode);
1822                } finally {
1823                    catchBlock = restoreBlock(catchBlock);
1824                    catchBlocks.add(catchBlock);
1825                }
1826
1827                // If unconditional catch then should to be the end.
1828                if (ifExpression == null) {
1829                    break;
1830                }
1831            }
1832
1833            // Prepare to capture finally statement.
1834            Block finallyStatements = null;
1835
1836            if (type == FINALLY) {
1837                next();
1838                finallyStatements = getBlock(true);
1839            }
1840
1841            // Need at least one catch or a finally.
1842            if (catchBlocks.isEmpty() && finallyStatements == null) {
1843                throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
1844            }
1845
1846            final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
1847            // Add try.
1848            assert lc.peek() == outer;
1849            appendStatement(tryNode);
1850
1851            tryNode.setFinish(finish);
1852            outer.setFinish(finish);
1853
1854        } finally {
1855            outer = restoreBlock(outer);
1856        }
1857
1858        appendStatement(new BlockStatement(startLine, outer));
1859    }
1860
1861    /**
1862     * DebuggerStatement :
1863     *      debugger ;
1864     *
1865     * See 12.15
1866     *
1867     * Parse debugger statement.
1868     */
1869    private void  debuggerStatement() {
1870        // Capture DEBUGGER token.
1871        final int  debuggerLine  = line;
1872        final long debuggerToken = token;
1873        // DEBUGGER tested in caller.
1874        next();
1875        endOfLine();
1876        appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>())));
1877    }
1878
1879    /**
1880     * PrimaryExpression :
1881     *      this
1882     *      Identifier
1883     *      Literal
1884     *      ArrayLiteral
1885     *      ObjectLiteral
1886     *      ( Expression )
1887     *
1888     *  See 11.1
1889     *
1890     * Parse primary expression.
1891     * @return Expression node.
1892     */
1893    @SuppressWarnings("fallthrough")
1894    private Expression primaryExpression() {
1895        // Capture first token.
1896        final int  primaryLine  = line;
1897        final long primaryToken = token;
1898
1899        switch (type) {
1900        case THIS:
1901            final String name = type.getName();
1902            next();
1903            lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS);
1904            return new IdentNode(primaryToken, finish, name);
1905        case IDENT:
1906            final IdentNode ident = getIdent();
1907            if (ident == null) {
1908                break;
1909            }
1910            detectSpecialProperty(ident);
1911            return ident;
1912        case OCTAL:
1913            if (isStrictMode) {
1914               throw error(AbstractParser.message("strict.no.octal"), token);
1915            }
1916        case STRING:
1917        case ESCSTRING:
1918        case DECIMAL:
1919        case HEXADECIMAL:
1920        case FLOATING:
1921        case REGEX:
1922        case XML:
1923            return getLiteral();
1924        case EXECSTRING:
1925            return execString(primaryLine, primaryToken);
1926        case FALSE:
1927            next();
1928            return LiteralNode.newInstance(primaryToken, finish, false);
1929        case TRUE:
1930            next();
1931            return LiteralNode.newInstance(primaryToken, finish, true);
1932        case NULL:
1933            next();
1934            return LiteralNode.newInstance(primaryToken, finish);
1935        case LBRACKET:
1936            return arrayLiteral();
1937        case LBRACE:
1938            return objectLiteral();
1939        case LPAREN:
1940            next();
1941
1942            final Expression expression = expression();
1943
1944            expect(RPAREN);
1945
1946            return expression;
1947
1948        default:
1949            // In this context some operator tokens mark the start of a literal.
1950            if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) {
1951                next();
1952                return getLiteral();
1953            }
1954            if (isNonStrictModeIdent()) {
1955                return getIdent();
1956            }
1957            break;
1958        }
1959
1960        return null;
1961    }
1962
1963    /**
1964     * Convert execString to a call to $EXEC.
1965     *
1966     * @param primaryToken Original string token.
1967     * @return callNode to $EXEC.
1968     */
1969    CallNode execString(final int primaryLine, final long primaryToken) {
1970        // Synthesize an ident to call $EXEC.
1971        final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
1972        // Skip over EXECSTRING.
1973        next();
1974        // Set up argument list for call.
1975        // Skip beginning of edit string expression.
1976        expect(LBRACE);
1977        // Add the following expression to arguments.
1978        final List<Expression> arguments = Collections.singletonList(expression());
1979        // Skip ending of edit string expression.
1980        expect(RBRACE);
1981
1982        return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false);
1983    }
1984
1985    /**
1986     * ArrayLiteral :
1987     *      [ Elision? ]
1988     *      [ ElementList ]
1989     *      [ ElementList , Elision? ]
1990     *      [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ]
1991     *
1992     * ElementList : Elision? AssignmentExpression
1993     *      ElementList , Elision? AssignmentExpression
1994     *
1995     * Elision :
1996     *      ,
1997     *      Elision ,
1998     *
1999     * See 12.1.4
2000     * JavaScript 1.8
2001     *
2002     * Parse array literal.
2003     * @return Expression node.
2004     */
2005    private LiteralNode<Expression[]> arrayLiteral() {
2006        // Capture LBRACKET token.
2007        final long arrayToken = token;
2008        // LBRACKET tested in caller.
2009        next();
2010
2011        // Prepare to accummulating elements.
2012        final List<Expression> elements = new ArrayList<>();
2013        // Track elisions.
2014        boolean elision = true;
2015loop:
2016        while (true) {
2017             switch (type) {
2018            case RBRACKET:
2019                next();
2020
2021                break loop;
2022
2023            case COMMARIGHT:
2024                next();
2025
2026                // If no prior expression
2027                if (elision) {
2028                    elements.add(null);
2029                }
2030
2031                elision = true;
2032
2033                break;
2034
2035            default:
2036                if (!elision) {
2037                    throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2038                }
2039                // Add expression element.
2040                final Expression expression = assignmentExpression(false);
2041
2042                if (expression != null) {
2043                    elements.add(expression);
2044                } else {
2045                    expect(RBRACKET);
2046                }
2047
2048                elision = false;
2049                break;
2050            }
2051        }
2052
2053        return LiteralNode.newInstance(arrayToken, finish, elements);
2054    }
2055
2056    /**
2057     * ObjectLiteral :
2058     *      { }
2059     *      { PropertyNameAndValueList } { PropertyNameAndValueList , }
2060     *
2061     * PropertyNameAndValueList :
2062     *      PropertyAssignment
2063     *      PropertyNameAndValueList , PropertyAssignment
2064     *
2065     * See 11.1.5
2066     *
2067     * Parse an object literal.
2068     * @return Expression node.
2069     */
2070    private ObjectNode objectLiteral() {
2071        // Capture LBRACE token.
2072        final long objectToken = token;
2073        // LBRACE tested in caller.
2074        next();
2075
2076        // Object context.
2077        // Prepare to accumulate elements.
2078        final List<PropertyNode> elements = new ArrayList<>();
2079        final Map<String, Integer> map = new HashMap<>();
2080
2081        // Create a block for the object literal.
2082        boolean commaSeen = true;
2083loop:
2084        while (true) {
2085            switch (type) {
2086                case RBRACE:
2087                    next();
2088                    break loop;
2089
2090                case COMMARIGHT:
2091                    if (commaSeen) {
2092                        throw error(AbstractParser.message("expected.property.id", type.getNameOrType()));
2093                    }
2094                    next();
2095                    commaSeen = true;
2096                    break;
2097
2098                default:
2099                    if (!commaSeen) {
2100                        throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2101                    }
2102
2103                    commaSeen = false;
2104                    // Get and add the next property.
2105                    final PropertyNode property = propertyAssignment();
2106                    final String key = property.getKeyName();
2107                    final Integer existing = map.get(key);
2108
2109                    if (existing == null) {
2110                        map.put(key, elements.size());
2111                        elements.add(property);
2112                        break;
2113                    }
2114
2115                    final PropertyNode existingProperty = elements.get(existing);
2116
2117                    // ECMA section 11.1.5 Object Initialiser
2118                    // point # 4 on property assignment production
2119                    final Expression   value  = property.getValue();
2120                    final FunctionNode getter = property.getGetter();
2121                    final FunctionNode setter = property.getSetter();
2122
2123                    final Expression   prevValue  = existingProperty.getValue();
2124                    final FunctionNode prevGetter = existingProperty.getGetter();
2125                    final FunctionNode prevSetter = existingProperty.getSetter();
2126
2127                    // ECMA 11.1.5 strict mode restrictions
2128                    if (isStrictMode && value != null && prevValue != null) {
2129                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
2130                    }
2131
2132                    final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
2133                    final boolean isAccessor     = getter != null     || setter != null;
2134
2135                    // data property redefined as accessor property
2136                    if (prevValue != null && isAccessor) {
2137                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
2138                    }
2139
2140                    // accessor property redefined as data
2141                    if (isPrevAccessor && value != null) {
2142                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
2143                    }
2144
2145                    if (isAccessor && isPrevAccessor) {
2146                        if (getter != null && prevGetter != null ||
2147                                setter != null && prevSetter != null) {
2148                            throw error(AbstractParser.message("property.redefinition", key), property.getToken());
2149                        }
2150                    }
2151
2152                    if (value != null) {
2153                        elements.add(property);
2154                    } else if (getter != null) {
2155                        elements.set(existing, existingProperty.setGetter(getter));
2156                    } else if (setter != null) {
2157                        elements.set(existing, existingProperty.setSetter(setter));
2158                    }
2159                    break;
2160            }
2161        }
2162
2163        return new ObjectNode(objectToken, finish, elements);
2164    }
2165
2166    /**
2167     * PropertyName :
2168     *      IdentifierName
2169     *      StringLiteral
2170     *      NumericLiteral
2171     *
2172     * See 11.1.5
2173     *
2174     * @return PropertyName node
2175     */
2176    @SuppressWarnings("fallthrough")
2177    private PropertyKey propertyName() {
2178        switch (type) {
2179        case IDENT:
2180            return getIdent().setIsPropertyName();
2181        case OCTAL:
2182            if (isStrictMode) {
2183                throw error(AbstractParser.message("strict.no.octal"), token);
2184            }
2185        case STRING:
2186        case ESCSTRING:
2187        case DECIMAL:
2188        case HEXADECIMAL:
2189        case FLOATING:
2190            return getLiteral();
2191        default:
2192            return getIdentifierName().setIsPropertyName();
2193        }
2194    }
2195
2196    /**
2197     * PropertyAssignment :
2198     *      PropertyName : AssignmentExpression
2199     *      get PropertyName ( ) { FunctionBody }
2200     *      set PropertyName ( PropertySetParameterList ) { FunctionBody }
2201     *
2202     * PropertySetParameterList :
2203     *      Identifier
2204     *
2205     * PropertyName :
2206     *      IdentifierName
2207     *      StringLiteral
2208     *      NumericLiteral
2209     *
2210     * See 11.1.5
2211     *
2212     * Parse an object literal property.
2213     * @return Property or reference node.
2214     */
2215    private PropertyNode propertyAssignment() {
2216        // Capture firstToken.
2217        final long propertyToken = token;
2218        final int  functionLine  = line;
2219
2220        PropertyKey propertyName;
2221
2222        if (type == IDENT) {
2223            // Get IDENT.
2224            final String ident = (String)expectValue(IDENT);
2225
2226            if (type != COLON) {
2227                final long getSetToken = propertyToken;
2228
2229                switch (ident) {
2230                case "get":
2231                    final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine);
2232                    return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null);
2233
2234                case "set":
2235                    final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine);
2236                    return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode);
2237                default:
2238                    break;
2239                }
2240            }
2241
2242            propertyName =  new IdentNode(propertyToken, finish, ident).setIsPropertyName();
2243        } else {
2244            propertyName = propertyName();
2245        }
2246
2247        expect(COLON);
2248
2249        defaultNames.push(propertyName);
2250        try {
2251            return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
2252        } finally {
2253            defaultNames.pop();
2254        }
2255    }
2256
2257    private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) {
2258        final PropertyKey getIdent = propertyName();
2259        final String getterName = getIdent.getPropertyName();
2260        final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
2261        expect(LPAREN);
2262        expect(RPAREN);
2263        final FunctionNode functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER, functionLine);
2264
2265        return new PropertyFunction(getIdent, functionNode);
2266    }
2267
2268    private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
2269        final PropertyKey setIdent = propertyName();
2270        final String setterName = setIdent.getPropertyName();
2271        final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
2272        expect(LPAREN);
2273        // be sloppy and allow missing setter parameter even though
2274        // spec does not permit it!
2275        final IdentNode argIdent;
2276        if (type == IDENT || isNonStrictModeIdent()) {
2277            argIdent = getIdent();
2278            verifyStrictIdent(argIdent, "setter argument");
2279        } else {
2280            argIdent = null;
2281        }
2282        expect(RPAREN);
2283        final List<IdentNode> parameters = new ArrayList<>();
2284        if (argIdent != null) {
2285            parameters.add(argIdent);
2286        }
2287        final FunctionNode functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER, functionLine);
2288
2289        return new PropertyFunction(setIdent, functionNode);
2290    }
2291
2292    private static class PropertyFunction {
2293        final PropertyKey ident;
2294        final FunctionNode functionNode;
2295
2296        PropertyFunction(final PropertyKey ident, final FunctionNode function) {
2297            this.ident = ident;
2298            this.functionNode = function;
2299        }
2300    }
2301
2302    /**
2303     * LeftHandSideExpression :
2304     *      NewExpression
2305     *      CallExpression
2306     *
2307     * CallExpression :
2308     *      MemberExpression Arguments
2309     *      CallExpression Arguments
2310     *      CallExpression [ Expression ]
2311     *      CallExpression . IdentifierName
2312     *
2313     * See 11.2
2314     *
2315     * Parse left hand side expression.
2316     * @return Expression node.
2317     */
2318    private Expression leftHandSideExpression() {
2319        int  callLine  = line;
2320        long callToken = token;
2321
2322        Expression lhs = memberExpression();
2323
2324        if (type == LPAREN) {
2325            final List<Expression> arguments = optimizeList(argumentList());
2326
2327            // Catch special functions.
2328            if (lhs instanceof IdentNode) {
2329                detectSpecialFunction((IdentNode)lhs);
2330            }
2331
2332            lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
2333        }
2334
2335loop:
2336        while (true) {
2337            // Capture token.
2338            callLine  = line;
2339            callToken = token;
2340
2341            switch (type) {
2342            case LPAREN:
2343                // Get NEW or FUNCTION arguments.
2344                final List<Expression> arguments = optimizeList(argumentList());
2345
2346                // Create call node.
2347                lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
2348
2349                break;
2350
2351            case LBRACKET:
2352                next();
2353
2354                // Get array index.
2355                final Expression rhs = expression();
2356
2357                expect(RBRACKET);
2358
2359                // Create indexing node.
2360                lhs = new IndexNode(callToken, finish, lhs, rhs);
2361
2362                break;
2363
2364            case PERIOD:
2365                next();
2366
2367                final IdentNode property = getIdentifierName();
2368
2369                // Create property access node.
2370                lhs = new AccessNode(callToken, finish, lhs, property.getName());
2371
2372                break;
2373
2374            default:
2375                break loop;
2376            }
2377        }
2378
2379        return lhs;
2380    }
2381
2382    /**
2383     * NewExpression :
2384     *      MemberExpression
2385     *      new NewExpression
2386     *
2387     * See 11.2
2388     *
2389     * Parse new expression.
2390     * @return Expression node.
2391     */
2392    private Expression newExpression() {
2393        final long newToken = token;
2394        // NEW is tested in caller.
2395        next();
2396
2397        // Get function base.
2398        final int  callLine    = line;
2399        final Expression constructor = memberExpression();
2400        if (constructor == null) {
2401            return null;
2402        }
2403        // Get arguments.
2404        ArrayList<Expression> arguments;
2405
2406        // Allow for missing arguments.
2407        if (type == LPAREN) {
2408            arguments = argumentList();
2409        } else {
2410            arguments = new ArrayList<>();
2411        }
2412
2413        // Nashorn extension: This is to support the following interface implementation
2414        // syntax:
2415        //
2416        //     var r = new java.lang.Runnable() {
2417        //         run: function() { println("run"); }
2418        //     };
2419        //
2420        // The object literal following the "new Constructor()" expresssion
2421        // is passed as an additional (last) argument to the constructor.
2422        if (!env._no_syntax_extensions && type == LBRACE) {
2423            arguments.add(objectLiteral());
2424        }
2425
2426        final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true);
2427
2428        return new UnaryNode(newToken, callNode);
2429    }
2430
2431    /**
2432     * MemberExpression :
2433     *      PrimaryExpression
2434     *      FunctionExpression
2435     *      MemberExpression [ Expression ]
2436     *      MemberExpression . IdentifierName
2437     *      new MemberExpression Arguments
2438     *
2439     * See 11.2
2440     *
2441     * Parse member expression.
2442     * @return Expression node.
2443     */
2444    private Expression memberExpression() {
2445        // Prepare to build operation.
2446        Expression lhs;
2447
2448        switch (type) {
2449        case NEW:
2450            // Get new expression.
2451            lhs = newExpression();
2452            break;
2453
2454        case FUNCTION:
2455            // Get function expression.
2456            lhs = functionExpression(false, false);
2457            break;
2458
2459        default:
2460            // Get primary expression.
2461            lhs = primaryExpression();
2462            break;
2463        }
2464
2465loop:
2466        while (true) {
2467            // Capture token.
2468            final long callToken = token;
2469
2470            switch (type) {
2471            case LBRACKET:
2472                next();
2473
2474                // Get array index.
2475                final Expression index = expression();
2476
2477                expect(RBRACKET);
2478
2479                // Create indexing node.
2480                lhs = new IndexNode(callToken, finish, lhs, index);
2481
2482                break;
2483
2484            case PERIOD:
2485                if (lhs == null) {
2486                    throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2487                }
2488
2489                next();
2490
2491                final IdentNode property = getIdentifierName();
2492
2493                // Create property access node.
2494                lhs = new AccessNode(callToken, finish, lhs, property.getName());
2495
2496                break;
2497
2498            default:
2499                break loop;
2500            }
2501        }
2502
2503        return lhs;
2504    }
2505
2506    /**
2507     * Arguments :
2508     *      ( )
2509     *      ( ArgumentList )
2510     *
2511     * ArgumentList :
2512     *      AssignmentExpression
2513     *      ArgumentList , AssignmentExpression
2514     *
2515     * See 11.2
2516     *
2517     * Parse function call arguments.
2518     * @return Argument list.
2519     */
2520    private ArrayList<Expression> argumentList() {
2521        // Prepare to accumulate list of arguments.
2522        final ArrayList<Expression> nodeList = new ArrayList<>();
2523        // LPAREN tested in caller.
2524        next();
2525
2526        // Track commas.
2527        boolean first = true;
2528
2529        while (type != RPAREN) {
2530            // Comma prior to every argument except the first.
2531            if (!first) {
2532                expect(COMMARIGHT);
2533            } else {
2534                first = false;
2535            }
2536
2537            // Get argument expression.
2538            nodeList.add(assignmentExpression(false));
2539        }
2540
2541        expect(RPAREN);
2542        return nodeList;
2543    }
2544
2545    private static <T> List<T> optimizeList(final ArrayList<T> list) {
2546        switch(list.size()) {
2547            case 0: {
2548                return Collections.emptyList();
2549            }
2550            case 1: {
2551                return Collections.singletonList(list.get(0));
2552            }
2553            default: {
2554                list.trimToSize();
2555                return list;
2556            }
2557        }
2558    }
2559
2560    /**
2561     * FunctionDeclaration :
2562     *      function Identifier ( FormalParameterList? ) { FunctionBody }
2563     *
2564     * FunctionExpression :
2565     *      function Identifier? ( FormalParameterList? ) { FunctionBody }
2566     *
2567     * See 13
2568     *
2569     * Parse function declaration.
2570     * @param isStatement True if for is a statement.
2571     *
2572     * @return Expression node.
2573     */
2574    private Expression functionExpression(final boolean isStatement, final boolean topLevel) {
2575        final long functionToken = token;
2576        final int  functionLine  = line;
2577        // FUNCTION is tested in caller.
2578        next();
2579
2580        IdentNode name = null;
2581
2582        if (type == IDENT || isNonStrictModeIdent()) {
2583            name = getIdent();
2584            verifyStrictIdent(name, "function name");
2585        } else if (isStatement) {
2586            // Nashorn extension: anonymous function statements
2587            if (env._no_syntax_extensions) {
2588                expect(IDENT);
2589            }
2590        }
2591
2592        // name is null, generate anonymous name
2593        boolean isAnonymous = false;
2594        if (name == null) {
2595            final String tmpName = getDefaultValidFunctionName(functionLine);
2596            name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
2597            isAnonymous = true;
2598        }
2599
2600        expect(LPAREN);
2601        final List<IdentNode> parameters = formalParameterList();
2602        expect(RPAREN);
2603
2604        FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine);
2605
2606        if (isStatement) {
2607            if (topLevel) {
2608                functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
2609            } else if (isStrictMode) {
2610                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
2611            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
2612                throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
2613            } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
2614                warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
2615            }
2616            if (isArguments(name)) {
2617                lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS);
2618            }
2619        }
2620
2621        if (isAnonymous) {
2622            functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
2623        }
2624
2625        final int arity = parameters.size();
2626
2627        final boolean strict = functionNode.isStrict();
2628        if (arity > 1) {
2629            final HashSet<String> parametersSet = new HashSet<>(arity);
2630
2631            for (int i = arity - 1; i >= 0; i--) {
2632                final IdentNode parameter = parameters.get(i);
2633                String parameterName = parameter.getName();
2634
2635                if (isArguments(parameterName)) {
2636                    functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
2637                }
2638
2639                if (parametersSet.contains(parameterName)) {
2640                    // redefinition of parameter name
2641                    if (strict) {
2642                        throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
2643                    }
2644                    // rename in non-strict mode
2645                    parameterName = functionNode.uniqueName(parameterName);
2646                    final long parameterToken = parameter.getToken();
2647                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
2648                }
2649
2650                parametersSet.add(parameterName);
2651            }
2652        } else if (arity == 1) {
2653            if (isArguments(parameters.get(0))) {
2654                functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
2655            }
2656        }
2657
2658        if (isStatement) {
2659            final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
2660            if (topLevel) {
2661                functionDeclarations.add(varNode);
2662            } else {
2663                appendStatement(varNode);
2664            }
2665        }
2666
2667        return functionNode;
2668    }
2669
2670    private String getDefaultValidFunctionName(final int functionLine) {
2671        final String defaultFunctionName = getDefaultFunctionName();
2672        return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine;
2673    }
2674
2675    private static boolean isValidIdentifier(final String name) {
2676        if(name == null || name.isEmpty()) {
2677            return false;
2678        }
2679        if(!Character.isJavaIdentifierStart(name.charAt(0))) {
2680            return false;
2681        }
2682        for(int i = 1; i < name.length(); ++i) {
2683            if(!Character.isJavaIdentifierPart(name.charAt(i))) {
2684                return false;
2685            }
2686        }
2687        return true;
2688    }
2689
2690    private String getDefaultFunctionName() {
2691        if(!defaultNames.isEmpty()) {
2692            final Object nameExpr = defaultNames.peek();
2693            if(nameExpr instanceof PropertyKey) {
2694                markDefaultNameUsed();
2695                return ((PropertyKey)nameExpr).getPropertyName();
2696            } else if(nameExpr instanceof AccessNode) {
2697                markDefaultNameUsed();
2698                return ((AccessNode)nameExpr).getProperty();
2699            }
2700        }
2701        return null;
2702    }
2703
2704    private void markDefaultNameUsed() {
2705        defaultNames.pop();
2706        // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value
2707        // from. Can't be null
2708        defaultNames.push("");
2709    }
2710
2711    /**
2712     * FormalParameterList :
2713     *      Identifier
2714     *      FormalParameterList , Identifier
2715     *
2716     * See 13
2717     *
2718     * Parse function parameter list.
2719     * @return List of parameter nodes.
2720     */
2721    private List<IdentNode> formalParameterList() {
2722        return formalParameterList(RPAREN);
2723    }
2724
2725    /**
2726     * Same as the other method of the same name - except that the end
2727     * token type expected is passed as argument to this method.
2728     *
2729     * FormalParameterList :
2730     *      Identifier
2731     *      FormalParameterList , Identifier
2732     *
2733     * See 13
2734     *
2735     * Parse function parameter list.
2736     * @return List of parameter nodes.
2737     */
2738    private List<IdentNode> formalParameterList(final TokenType endType) {
2739        // Prepare to gather parameters.
2740        final ArrayList<IdentNode> parameters = new ArrayList<>();
2741        // Track commas.
2742        boolean first = true;
2743
2744        while (type != endType) {
2745            // Comma prior to every argument except the first.
2746            if (!first) {
2747                expect(COMMARIGHT);
2748            } else {
2749                first = false;
2750            }
2751
2752            // Get and add parameter.
2753            final IdentNode ident = getIdent();
2754
2755            // ECMA 13.1 strict mode restrictions
2756            verifyStrictIdent(ident, "function parameter");
2757
2758            parameters.add(ident);
2759        }
2760
2761        parameters.trimToSize();
2762        return parameters;
2763    }
2764
2765    /**
2766     * FunctionBody :
2767     *      SourceElements?
2768     *
2769     * See 13
2770     *
2771     * Parse function body.
2772     * @return function node (body.)
2773     */
2774    private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) {
2775        FunctionNode functionNode = null;
2776        long lastToken = 0L;
2777
2778        try {
2779            // Create a new function block.
2780            functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine);
2781
2782            // Nashorn extension: expression closures
2783            if (!env._no_syntax_extensions && type != LBRACE) {
2784                /*
2785                 * Example:
2786                 *
2787                 * function square(x) x * x;
2788                 * print(square(3));
2789                 */
2790
2791                // just expression as function body
2792                final Expression expr = assignmentExpression(true);
2793                lastToken = previousToken;
2794                assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
2795                // EOL uses length field to store the line number
2796                final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
2797                final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
2798                appendStatement(returnNode);
2799                functionNode.setFinish(lastFinish);
2800
2801            } else {
2802                expect(LBRACE);
2803
2804                // Gather the function elements.
2805                final List<Statement> prevFunctionDecls = functionDeclarations;
2806                functionDeclarations = new ArrayList<>();
2807                try {
2808                    sourceElements(false);
2809                    addFunctionDeclarations(functionNode);
2810                } finally {
2811                    functionDeclarations = prevFunctionDecls;
2812                }
2813
2814                lastToken = token;
2815                expect(RBRACE);
2816                functionNode.setFinish(finish);
2817
2818            }
2819        } finally {
2820            functionNode = restoreFunctionNode(functionNode, lastToken);
2821        }
2822        return functionNode;
2823    }
2824
2825    private void addFunctionDeclarations(final FunctionNode functionNode) {
2826        assert lc.peek() == lc.getFunctionBody(functionNode);
2827        VarNode lastDecl = null;
2828        for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
2829            Statement decl = functionDeclarations.get(i);
2830            if (lastDecl == null && decl instanceof VarNode) {
2831                decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
2832                lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
2833            }
2834            prependStatement(decl);
2835        }
2836    }
2837
2838    private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) {
2839        if (earlyError) {
2840            throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
2841        }
2842        final ArrayList<Expression> args = new ArrayList<>();
2843        args.add(lhs);
2844        if (rhs == null) {
2845            args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
2846        } else {
2847            args.add(rhs);
2848        }
2849        args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
2850        return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
2851    }
2852
2853    /*
2854     * parse LHS [a, b, ..., c].
2855     *
2856     * JavaScript 1.8.
2857     */
2858    //private Node destructureExpression() {
2859    //    return null;
2860    //}
2861
2862    /**
2863     * PostfixExpression :
2864     *      LeftHandSideExpression
2865     *      LeftHandSideExpression ++ // [no LineTerminator here]
2866     *      LeftHandSideExpression -- // [no LineTerminator here]
2867     *
2868     * See 11.3
2869     *
2870     * UnaryExpression :
2871     *      PostfixExpression
2872     *      delete UnaryExpression
2873     *      Node UnaryExpression
2874     *      typeof UnaryExpression
2875     *      ++ UnaryExpression
2876     *      -- UnaryExpression
2877     *      + UnaryExpression
2878     *      - UnaryExpression
2879     *      ~ UnaryExpression
2880     *      ! UnaryExpression
2881     *
2882     * See 11.4
2883     *
2884     * Parse unary expression.
2885     * @return Expression node.
2886     */
2887    private Expression unaryExpression() {
2888        final int  unaryLine  = line;
2889        final long unaryToken = token;
2890
2891        switch (type) {
2892        case DELETE: {
2893            next();
2894            final Expression expr = unaryExpression();
2895            if (expr instanceof BaseNode || expr instanceof IdentNode) {
2896                return new UnaryNode(unaryToken, expr);
2897            }
2898            appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr));
2899            return LiteralNode.newInstance(unaryToken, finish, true);
2900        }
2901        case VOID:
2902        case TYPEOF:
2903        case ADD:
2904        case SUB:
2905        case BIT_NOT:
2906        case NOT:
2907            next();
2908            final Expression expr = unaryExpression();
2909            return new UnaryNode(unaryToken, expr);
2910
2911        case INCPREFIX:
2912        case DECPREFIX:
2913            final TokenType opType = type;
2914            next();
2915
2916            final Expression lhs = leftHandSideExpression();
2917            // ++, -- without operand..
2918            if (lhs == null) {
2919                throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
2920            }
2921
2922            if (!(lhs instanceof AccessNode ||
2923                  lhs instanceof IndexNode ||
2924                  lhs instanceof IdentNode)) {
2925                return referenceError(lhs, null, env._early_lvalue_error);
2926            }
2927
2928            if (lhs instanceof IdentNode) {
2929                if (!checkIdentLValue((IdentNode)lhs)) {
2930                    return referenceError(lhs, null, false);
2931                }
2932                verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
2933            }
2934
2935            return incDecExpression(unaryToken, opType, lhs, false);
2936
2937        default:
2938            break;
2939        }
2940
2941        Expression expression = leftHandSideExpression();
2942
2943        if (last != EOL) {
2944            switch (type) {
2945            case INCPREFIX:
2946            case DECPREFIX:
2947                final TokenType opType = type;
2948                final Expression lhs = expression;
2949                // ++, -- without operand..
2950                if (lhs == null) {
2951                    throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
2952                }
2953
2954                if (!(lhs instanceof AccessNode ||
2955                   lhs instanceof IndexNode ||
2956                   lhs instanceof IdentNode)) {
2957                    next();
2958                    return referenceError(lhs, null, env._early_lvalue_error);
2959                }
2960                if (lhs instanceof IdentNode) {
2961                    if (!checkIdentLValue((IdentNode)lhs)) {
2962                        next();
2963                        return referenceError(lhs, null, false);
2964                    }
2965                    verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
2966                }
2967                expression = incDecExpression(token, type, expression, true);
2968                next();
2969                break;
2970            default:
2971                break;
2972            }
2973        }
2974
2975        if (expression == null) {
2976            throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2977        }
2978
2979        return expression;
2980    }
2981
2982    /**
2983     * MultiplicativeExpression :
2984     *      UnaryExpression
2985     *      MultiplicativeExpression * UnaryExpression
2986     *      MultiplicativeExpression / UnaryExpression
2987     *      MultiplicativeExpression % UnaryExpression
2988     *
2989     * See 11.5
2990     *
2991     * AdditiveExpression :
2992     *      MultiplicativeExpression
2993     *      AdditiveExpression + MultiplicativeExpression
2994     *      AdditiveExpression - MultiplicativeExpression
2995     *
2996     * See 11.6
2997     *
2998     * ShiftExpression :
2999     *      AdditiveExpression
3000     *      ShiftExpression << AdditiveExpression
3001     *      ShiftExpression >> AdditiveExpression
3002     *      ShiftExpression >>> AdditiveExpression
3003     *
3004     * See 11.7
3005     *
3006     * RelationalExpression :
3007     *      ShiftExpression
3008     *      RelationalExpression < ShiftExpression
3009     *      RelationalExpression > ShiftExpression
3010     *      RelationalExpression <= ShiftExpression
3011     *      RelationalExpression >= ShiftExpression
3012     *      RelationalExpression instanceof ShiftExpression
3013     *      RelationalExpression in ShiftExpression // if !noIf
3014     *
3015     * See 11.8
3016     *
3017     *      RelationalExpression
3018     *      EqualityExpression == RelationalExpression
3019     *      EqualityExpression != RelationalExpression
3020     *      EqualityExpression === RelationalExpression
3021     *      EqualityExpression !== RelationalExpression
3022     *
3023     * See 11.9
3024     *
3025     * BitwiseANDExpression :
3026     *      EqualityExpression
3027     *      BitwiseANDExpression & EqualityExpression
3028     *
3029     * BitwiseXORExpression :
3030     *      BitwiseANDExpression
3031     *      BitwiseXORExpression ^ BitwiseANDExpression
3032     *
3033     * BitwiseORExpression :
3034     *      BitwiseXORExpression
3035     *      BitwiseORExpression | BitwiseXORExpression
3036     *
3037     * See 11.10
3038     *
3039     * LogicalANDExpression :
3040     *      BitwiseORExpression
3041     *      LogicalANDExpression && BitwiseORExpression
3042     *
3043     * LogicalORExpression :
3044     *      LogicalANDExpression
3045     *      LogicalORExpression || LogicalANDExpression
3046     *
3047     * See 11.11
3048     *
3049     * ConditionalExpression :
3050     *      LogicalORExpression
3051     *      LogicalORExpression ? AssignmentExpression : AssignmentExpression
3052     *
3053     * See 11.12
3054     *
3055     * AssignmentExpression :
3056     *      ConditionalExpression
3057     *      LeftHandSideExpression AssignmentOperator AssignmentExpression
3058     *
3059     * AssignmentOperator :
3060     *      = *= /= %= += -= <<= >>= >>>= &= ^= |=
3061     *
3062     * See 11.13
3063     *
3064     * Expression :
3065     *      AssignmentExpression
3066     *      Expression , AssignmentExpression
3067     *
3068     * See 11.14
3069     *
3070     * Parse expression.
3071     * @return Expression node.
3072     */
3073    private Expression expression() {
3074        // TODO - Destructuring array.
3075        // Include commas in expression parsing.
3076        return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
3077    }
3078
3079    private JoinPredecessorExpression joinPredecessorExpression() {
3080        return new JoinPredecessorExpression(expression());
3081    }
3082
3083    private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) {
3084        // Get the precedence of the next operator.
3085        int precedence = type.getPrecedence();
3086        Expression lhs = exprLhs;
3087
3088        // While greater precedence.
3089        while (type.isOperator(noIn) && precedence >= minPrecedence) {
3090            // Capture the operator token.
3091            final long op = token;
3092
3093            if (type == TERNARY) {
3094                // Skip operator.
3095                next();
3096
3097                // Pass expression. Middle expression of a conditional expression can be a "in"
3098                // expression - even in the contexts where "in" is not permitted.
3099                final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false);
3100
3101                expect(COLON);
3102
3103                // Fail expression.
3104                final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
3105
3106                // Build up node.
3107                lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
3108            } else {
3109                // Skip operator.
3110                next();
3111
3112                 // Get the next primary expression.
3113                Expression rhs;
3114                final boolean isAssign = Token.descType(op) == ASSIGN;
3115                if(isAssign) {
3116                    defaultNames.push(lhs);
3117                }
3118                try {
3119                    rhs = unaryExpression();
3120                    // Get precedence of next operator.
3121                    int nextPrecedence = type.getPrecedence();
3122
3123                    // Subtask greater precedence.
3124                    while (type.isOperator(noIn) &&
3125                           (nextPrecedence > precedence ||
3126                           nextPrecedence == precedence && !type.isLeftAssociative())) {
3127                        rhs = expression(rhs, nextPrecedence, noIn);
3128                        nextPrecedence = type.getPrecedence();
3129                    }
3130                } finally {
3131                    if(isAssign) {
3132                        defaultNames.pop();
3133                    }
3134                }
3135                lhs = verifyAssignment(op, lhs, rhs);
3136            }
3137
3138            precedence = type.getPrecedence();
3139        }
3140
3141        return lhs;
3142    }
3143
3144    private Expression assignmentExpression(final boolean noIn) {
3145        // TODO - Handle decompose.
3146        // Exclude commas in expression parsing.
3147        return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
3148    }
3149
3150    /**
3151     * Parse an end of line.
3152     */
3153    private void endOfLine() {
3154        switch (type) {
3155        case SEMICOLON:
3156        case EOL:
3157            next();
3158            break;
3159        case RPAREN:
3160        case RBRACKET:
3161        case RBRACE:
3162        case EOF:
3163            break;
3164        default:
3165            if (last != EOL) {
3166                expect(SEMICOLON);
3167            }
3168            break;
3169        }
3170    }
3171
3172    @Override
3173    public String toString() {
3174        return "'JavaScript Parsing'";
3175    }
3176
3177    private static void markEval(final LexicalContext lc) {
3178        final Iterator<FunctionNode> iter = lc.getFunctions();
3179        boolean flaggedCurrentFn = false;
3180        while (iter.hasNext()) {
3181            final FunctionNode fn = iter.next();
3182            if (!flaggedCurrentFn) {
3183                lc.setFlag(fn, FunctionNode.HAS_EVAL);
3184                flaggedCurrentFn = true;
3185            } else {
3186                lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL);
3187            }
3188            lc.setBlockNeedsScope(lc.getFunctionBody(fn));
3189        }
3190    }
3191
3192    private void prependStatement(final Statement statement) {
3193        lc.prependStatement(statement);
3194    }
3195
3196    private void appendStatement(final Statement statement) {
3197        lc.appendStatement(statement);
3198    }
3199}
3200