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