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