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