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