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