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