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