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