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