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 return new IdentNode(primaryToken, finish, name); 1803 case IDENT: 1804 final IdentNode ident = getIdent(); 1805 if (ident == null) { 1806 break; 1807 } 1808 detectSpecialProperty(ident); 1809 return ident; 1810 case OCTAL: 1811 if (isStrictMode) { 1812 throw error(AbstractParser.message("strict.no.octal"), token); 1813 } 1814 case STRING: 1815 case ESCSTRING: 1816 case DECIMAL: 1817 case HEXADECIMAL: 1818 case FLOATING: 1819 case REGEX: 1820 case XML: 1821 return getLiteral(); 1822 case EXECSTRING: 1823 return execString(primaryLine, primaryToken); 1824 case FALSE: 1825 next(); 1826 return LiteralNode.newInstance(primaryToken, finish, false); 1827 case TRUE: 1828 next(); 1829 return LiteralNode.newInstance(primaryToken, finish, true); 1830 case NULL: 1831 next(); 1832 return LiteralNode.newInstance(primaryToken, finish); 1833 case LBRACKET: 1834 return arrayLiteral(); 1835 case LBRACE: 1836 return objectLiteral(); 1837 case LPAREN: 1838 next(); 1839 1840 final Expression expression = expression(); 1841 1842 expect(RPAREN); 1843 1844 return expression; 1845 1846 default: 1847 // In this context some operator tokens mark the start of a literal. 1848 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 1849 next(); 1850 return getLiteral(); 1851 } 1852 if (isNonStrictModeIdent()) { 1853 return getIdent(); 1854 } 1855 break; 1856 } 1857 1858 return null; 1859 } 1860 1861 /** 1862 * Convert execString to a call to $EXEC. 1863 * 1864 * @param primaryToken Original string token. 1865 * @return callNode to $EXEC. 1866 */ 1867 CallNode execString(final int primaryLine, final long primaryToken) { 1868 // Synthesize an ident to call $EXEC. 1869 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 1870 // Skip over EXECSTRING. 1871 next(); 1872 // Set up argument list for call. 1873 // Skip beginning of edit string expression. 1874 expect(LBRACE); 1875 // Add the following expression to arguments. 1876 final List<Expression> arguments = Collections.singletonList(expression()); 1877 // Skip ending of edit string expression. 1878 expect(RBRACE); 1879 1880 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments); 1881 } 1882 1883 /** 1884 * ArrayLiteral : 1885 * [ Elision? ] 1886 * [ ElementList ] 1887 * [ ElementList , Elision? ] 1888 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 1889 * 1890 * ElementList : Elision? AssignmentExpression 1891 * ElementList , Elision? AssignmentExpression 1892 * 1893 * Elision : 1894 * , 1895 * Elision , 1896 * 1897 * See 12.1.4 1898 * JavaScript 1.8 1899 * 1900 * Parse array literal. 1901 * @return Expression node. 1902 */ 1903 private LiteralNode<Expression[]> arrayLiteral() { 1904 // Capture LBRACKET token. 1905 final long arrayToken = token; 1906 // LBRACKET tested in caller. 1907 next(); 1908 1909 // Prepare to accummulating elements. 1910 final List<Expression> elements = new ArrayList<>(); 1911 // Track elisions. 1912 boolean elision = true; 1913 loop: 1914 while (true) { 1915 switch (type) { 1916 case RBRACKET: 1917 next(); 1918 1919 break loop; 1920 1921 case COMMARIGHT: 1922 next(); 1923 1924 // If no prior expression 1925 if (elision) { 1926 elements.add(null); 1927 } 1928 1929 elision = true; 1930 1931 break; 1932 1933 default: 1934 if (!elision) { 1935 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 1936 } 1937 // Add expression element. 1938 final Expression expression = assignmentExpression(false); 1939 1940 if (expression != null) { 1941 elements.add(expression); 1942 } else { 1943 expect(RBRACKET); 1944 } 1945 1946 elision = false; 1947 break; 1948 } 1949 } 1950 1951 return LiteralNode.newInstance(arrayToken, finish, elements); 1952 } 1953 1954 /** 1955 * ObjectLiteral : 1956 * { } 1957 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 1958 * 1959 * PropertyNameAndValueList : 1960 * PropertyAssignment 1961 * PropertyNameAndValueList , PropertyAssignment 1962 * 1963 * See 11.1.5 1964 * 1965 * Parse an object literal. 1966 * @return Expression node. 1967 */ 1968 private ObjectNode objectLiteral() { 1969 // Capture LBRACE token. 1970 final long objectToken = token; 1971 // LBRACE tested in caller. 1972 next(); 1973 1974 // Object context. 1975 // Prepare to accumulate elements. 1976 final List<PropertyNode> elements = new ArrayList<>(); 1977 final Map<String, Integer> map = new HashMap<>(); 1978 1979 // Create a block for the object literal. 1980 boolean commaSeen = true; 1981 loop: 1982 while (true) { 1983 switch (type) { 1984 case RBRACE: 1985 next(); 1986 break loop; 1987 1988 case COMMARIGHT: 1989 if (commaSeen) { 1990 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 1991 } 1992 next(); 1993 commaSeen = true; 1994 break; 1995 1996 default: 1997 if (!commaSeen) { 1998 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 1999 } 2000 2001 commaSeen = false; 2002 // Get and add the next property. 2003 final PropertyNode property = propertyAssignment(); 2004 final String key = property.getKeyName(); 2005 final Integer existing = map.get(key); 2006 2007 if (existing == null) { 2008 map.put(key, elements.size()); 2009 elements.add(property); 2010 break; 2011 } 2012 2013 final PropertyNode existingProperty = elements.get(existing); 2014 2015 // ECMA section 11.1.5 Object Initialiser 2016 // point # 4 on property assignment production 2017 final Expression value = property.getValue(); 2018 final FunctionNode getter = property.getGetter(); 2019 final FunctionNode setter = property.getSetter(); 2020 2021 final Expression prevValue = existingProperty.getValue(); 2022 final FunctionNode prevGetter = existingProperty.getGetter(); 2023 final FunctionNode prevSetter = existingProperty.getSetter(); 2024 2025 // ECMA 11.1.5 strict mode restrictions 2026 if (isStrictMode && value != null && prevValue != null) { 2027 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2028 } 2029 2030 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2031 final boolean isAccessor = getter != null || setter != null; 2032 2033 // data property redefined as accessor property 2034 if (prevValue != null && isAccessor) { 2035 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2036 } 2037 2038 // accessor property redefined as data 2039 if (isPrevAccessor && value != null) { 2040 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2041 } 2042 2043 if (isAccessor && isPrevAccessor) { 2044 if (getter != null && prevGetter != null || 2045 setter != null && prevSetter != null) { 2046 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2047 } 2048 } 2049 2050 if (value != null) { 2051 elements.add(property); 2052 } else if (getter != null) { 2053 elements.set(existing, existingProperty.setGetter(getter)); 2054 } else if (setter != null) { 2055 elements.set(existing, existingProperty.setSetter(setter)); 2056 } 2057 break; 2058 } 2059 } 2060 2061 return new ObjectNode(objectToken, finish, elements); 2062 } 2063 2064 /** 2065 * PropertyName : 2066 * IdentifierName 2067 * StringLiteral 2068 * NumericLiteral 2069 * 2070 * See 11.1.5 2071 * 2072 * @return PropertyName node 2073 */ 2074 @SuppressWarnings("fallthrough") 2075 private PropertyKey propertyName() { 2076 switch (type) { 2077 case IDENT: 2078 return getIdent().setIsPropertyName(); 2079 case OCTAL: 2080 if (isStrictMode) { 2081 throw error(AbstractParser.message("strict.no.octal"), token); 2082 } 2083 case STRING: 2084 case ESCSTRING: 2085 case DECIMAL: 2086 case HEXADECIMAL: 2087 case FLOATING: 2088 return getLiteral(); 2089 default: 2090 return getIdentifierName().setIsPropertyName(); 2091 } 2092 } 2093 2094 /** 2095 * PropertyAssignment : 2096 * PropertyName : AssignmentExpression 2097 * get PropertyName ( ) { FunctionBody } 2098 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2099 * 2100 * PropertySetParameterList : 2101 * Identifier 2102 * 2103 * PropertyName : 2104 * IdentifierName 2105 * StringLiteral 2106 * NumericLiteral 2107 * 2108 * See 11.1.5 2109 * 2110 * Parse an object literal property. 2111 * @return Property or reference node. 2112 */ 2113 private PropertyNode propertyAssignment() { 2114 // Capture firstToken. 2115 final long propertyToken = token; 2116 2117 FunctionNode functionNode; 2118 PropertyKey propertyName; 2119 2120 if (type == IDENT) { 2121 // Get IDENT. 2122 final String ident = (String)expectValue(IDENT); 2123 2124 if (type != COLON) { 2125 final long getSetToken = propertyToken; 2126 2127 switch (ident) { 2128 case "get": 2129 final PropertyKey getIdent = propertyName(); 2130 final String getterName = getIdent.getPropertyName(); 2131 final IdentNode getNameNode = new IdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2132 expect(LPAREN); 2133 expect(RPAREN); 2134 functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); 2135 return new PropertyNode(propertyToken, finish, getIdent, null, functionNode, null); 2136 2137 case "set": 2138 final PropertyKey setIdent = propertyName(); 2139 final String setterName = setIdent.getPropertyName(); 2140 final IdentNode setNameNode = new IdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2141 expect(LPAREN); 2142 // be sloppy and allow missing setter parameter even though 2143 // spec does not permit it! 2144 final IdentNode argIdent; 2145 if (type == IDENT || isNonStrictModeIdent()) { 2146 argIdent = getIdent(); 2147 verifyStrictIdent(argIdent, "setter argument"); 2148 } else { 2149 argIdent = null; 2150 } 2151 expect(RPAREN); 2152 List<IdentNode> parameters = new ArrayList<>(); 2153 if (argIdent != null) { 2154 parameters.add(argIdent); 2155 } 2156 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); 2157 return new PropertyNode(propertyToken, finish, setIdent, null, null, functionNode); 2158 2159 default: 2160 break; 2161 } 2162 } 2163 2164 propertyName = new IdentNode(propertyToken, finish, ident).setIsPropertyName(); 2165 } else { 2166 propertyName = propertyName(); 2167 } 2168 2169 expect(COLON); 2170 2171 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2172 } 2173 2174 /** 2175 * LeftHandSideExpression : 2176 * NewExpression 2177 * CallExpression 2178 * 2179 * CallExpression : 2180 * MemberExpression Arguments 2181 * CallExpression Arguments 2182 * CallExpression [ Expression ] 2183 * CallExpression . IdentifierName 2184 * 2185 * See 11.2 2186 * 2187 * Parse left hand side expression. 2188 * @return Expression node. 2189 */ 2190 private Expression leftHandSideExpression() { 2191 int callLine = line; 2192 long callToken = token; 2193 2194 Expression lhs = memberExpression(); 2195 2196 if (type == LPAREN) { 2197 final List<Expression> arguments = optimizeList(argumentList()); 2198 2199 // Catch special functions. 2200 if (lhs instanceof IdentNode) { 2201 detectSpecialFunction((IdentNode)lhs); 2202 } 2203 2204 lhs = new CallNode(callLine, callToken, finish, lhs, arguments); 2205 } 2206 2207 loop: 2208 while (true) { 2209 // Capture token. 2210 callLine = line; 2211 callToken = token; 2212 2213 switch (type) { 2214 case LPAREN: 2215 // Get NEW or FUNCTION arguments. 2216 final List<Expression> arguments = optimizeList(argumentList()); 2217 2218 // Create call node. 2219 lhs = new CallNode(callLine, callToken, finish, lhs, arguments); 2220 2221 break; 2222 2223 case LBRACKET: 2224 next(); 2225 2226 // Get array index. 2227 final Expression rhs = expression(); 2228 2229 expect(RBRACKET); 2230 2231 // Create indexing node. 2232 lhs = new IndexNode(callToken, finish, lhs, rhs); 2233 2234 break; 2235 2236 case PERIOD: 2237 next(); 2238 2239 final IdentNode property = getIdentifierName(); 2240 2241 // Create property access node. 2242 lhs = new AccessNode(callToken, finish, lhs, property); 2243 2244 break; 2245 2246 default: 2247 break loop; 2248 } 2249 } 2250 2251 return lhs; 2252 } 2253 2254 /** 2255 * NewExpression : 2256 * MemberExpression 2257 * new NewExpression 2258 * 2259 * See 11.2 2260 * 2261 * Parse new expression. 2262 * @return Expression node. 2263 */ 2264 private Expression newExpression() { 2265 final long newToken = token; 2266 // NEW is tested in caller. 2267 next(); 2268 2269 // Get function base. 2270 final int callLine = line; 2271 final Expression constructor = memberExpression(); 2272 if (constructor == null) { 2273 return null; 2274 } 2275 // Get arguments. 2276 ArrayList<Expression> arguments; 2277 2278 // Allow for missing arguments. 2279 if (type == LPAREN) { 2280 arguments = argumentList(); 2281 } else { 2282 arguments = new ArrayList<>(); 2283 } 2284 2285 // Nashorn extension: This is to support the following interface implementation 2286 // syntax: 2287 // 2288 // var r = new java.lang.Runnable() { 2289 // run: function() { println("run"); } 2290 // }; 2291 // 2292 // The object literal following the "new Constructor()" expresssion 2293 // is passed as an additional (last) argument to the constructor. 2294 if (!env._no_syntax_extensions && type == LBRACE) { 2295 arguments.add(objectLiteral()); 2296 } 2297 2298 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments)); 2299 2300 return new UnaryNode(newToken, callNode); 2301 } 2302 2303 /** 2304 * MemberExpression : 2305 * PrimaryExpression 2306 * FunctionExpression 2307 * MemberExpression [ Expression ] 2308 * MemberExpression . IdentifierName 2309 * new MemberExpression Arguments 2310 * 2311 * See 11.2 2312 * 2313 * Parse member expression. 2314 * @return Expression node. 2315 */ 2316 private Expression memberExpression() { 2317 // Prepare to build operation. 2318 Expression lhs; 2319 2320 switch (type) { 2321 case NEW: 2322 // Get new exppression. 2323 lhs = newExpression(); 2324 break; 2325 2326 case FUNCTION: 2327 // Get function expression. 2328 lhs = functionExpression(false, false); 2329 break; 2330 2331 default: 2332 // Get primary expression. 2333 lhs = primaryExpression(); 2334 break; 2335 } 2336 2337 loop: 2338 while (true) { 2339 // Capture token. 2340 final long callToken = token; 2341 2342 switch (type) { 2343 case LBRACKET: 2344 next(); 2345 2346 // Get array index. 2347 final Expression index = expression(); 2348 2349 expect(RBRACKET); 2350 2351 // Create indexing node. 2352 lhs = new IndexNode(callToken, finish, lhs, index); 2353 2354 break; 2355 2356 case PERIOD: 2357 if (lhs == null) { 2358 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2359 } 2360 2361 next(); 2362 2363 final IdentNode property = getIdentifierName(); 2364 2365 // Create property access node. 2366 lhs = new AccessNode(callToken, finish, lhs, property); 2367 2368 break; 2369 2370 default: 2371 break loop; 2372 } 2373 } 2374 2375 return lhs; 2376 } 2377 2378 /** 2379 * Arguments : 2380 * ( ) 2381 * ( ArgumentList ) 2382 * 2383 * ArgumentList : 2384 * AssignmentExpression 2385 * ArgumentList , AssignmentExpression 2386 * 2387 * See 11.2 2388 * 2389 * Parse function call arguments. 2390 * @return Argument list. 2391 */ 2392 private ArrayList<Expression> argumentList() { 2393 // Prepare to accumulate list of arguments. 2394 final ArrayList<Expression> nodeList = new ArrayList<>(); 2395 // LPAREN tested in caller. 2396 next(); 2397 2398 // Track commas. 2399 boolean first = true; 2400 2401 while (type != RPAREN) { 2402 // Comma prior to every argument except the first. 2403 if (!first) { 2404 expect(COMMARIGHT); 2405 } else { 2406 first = false; 2407 } 2408 2409 // Get argument expression. 2410 nodeList.add(assignmentExpression(false)); 2411 } 2412 2413 expect(RPAREN); 2414 return nodeList; 2415 } 2416 2417 private static <T> List<T> optimizeList(ArrayList<T> list) { 2418 switch(list.size()) { 2419 case 0: { 2420 return Collections.emptyList(); 2421 } 2422 case 1: { 2423 return Collections.singletonList(list.get(0)); 2424 } 2425 default: { 2426 list.trimToSize(); 2427 return list; 2428 } 2429 } 2430 } 2431 2432 /** 2433 * FunctionDeclaration : 2434 * function Identifier ( FormalParameterList? ) { FunctionBody } 2435 * 2436 * FunctionExpression : 2437 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2438 * 2439 * See 13 2440 * 2441 * Parse function declaration. 2442 * @param isStatement True if for is a statement. 2443 * 2444 * @return Expression node. 2445 */ 2446 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2447 final long functionToken = token; 2448 final int functionLine = line; 2449 // FUNCTION is tested in caller. 2450 next(); 2451 2452 IdentNode name = null; 2453 2454 if (type == IDENT || isNonStrictModeIdent()) { 2455 name = getIdent(); 2456 verifyStrictIdent(name, "function name"); 2457 } else if (isStatement) { 2458 // Nashorn extension: anonymous function statements 2459 if (env._no_syntax_extensions) { 2460 expect(IDENT); 2461 } 2462 } 2463 2464 // name is null, generate anonymous name 2465 boolean isAnonymous = false; 2466 if (name == null) { 2467 final String tmpName = ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2468 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2469 isAnonymous = true; 2470 } 2471 2472 expect(LPAREN); 2473 final List<IdentNode> parameters = formalParameterList(); 2474 expect(RPAREN); 2475 2476 FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); 2477 2478 if (isStatement) { 2479 if (topLevel) { 2480 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED); 2481 } else if (isStrictMode) { 2482 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2483 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2484 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2485 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2486 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2487 } 2488 if (isArguments(name)) { 2489 lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS); 2490 } 2491 } 2492 2493 if (isAnonymous) { 2494 functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS); 2495 } 2496 2497 final int arity = parameters.size(); 2498 2499 final boolean strict = functionNode.isStrict(); 2500 if (arity > 1) { 2501 final HashSet<String> parametersSet = new HashSet<>(arity); 2502 2503 for (int i = arity - 1; i >= 0; i--) { 2504 final IdentNode parameter = parameters.get(i); 2505 String parameterName = parameter.getName(); 2506 2507 if (isArguments(parameterName)) { 2508 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 2509 } 2510 2511 if (parametersSet.contains(parameterName)) { 2512 // redefinition of parameter name 2513 if (strict) { 2514 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2515 } 2516 // rename in non-strict mode 2517 parameterName = functionNode.uniqueName(parameterName); 2518 final long parameterToken = parameter.getToken(); 2519 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2520 } 2521 2522 parametersSet.add(parameterName); 2523 } 2524 } else if (arity == 1) { 2525 if (isArguments(parameters.get(0))) { 2526 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 2527 } 2528 } 2529 2530 if (isStatement) { 2531 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT); 2532 if (topLevel) { 2533 functionDeclarations.add(varNode); 2534 } else { 2535 appendStatement(varNode); 2536 } 2537 } 2538 2539 return functionNode; 2540 } 2541 2542 /** 2543 * FormalParameterList : 2544 * Identifier 2545 * FormalParameterList , Identifier 2546 * 2547 * See 13 2548 * 2549 * Parse function parameter list. 2550 * @return List of parameter nodes. 2551 */ 2552 private List<IdentNode> formalParameterList() { 2553 return formalParameterList(RPAREN); 2554 } 2555 2556 /** 2557 * Same as the other method of the same name - except that the end 2558 * token type expected is passed as argument to this method. 2559 * 2560 * FormalParameterList : 2561 * Identifier 2562 * FormalParameterList , Identifier 2563 * 2564 * See 13 2565 * 2566 * Parse function parameter list. 2567 * @return List of parameter nodes. 2568 */ 2569 private List<IdentNode> formalParameterList(final TokenType endType) { 2570 // Prepare to gather parameters. 2571 final List<IdentNode> parameters = new ArrayList<>(); 2572 // Track commas. 2573 boolean first = true; 2574 2575 while (type != endType) { 2576 // Comma prior to every argument except the first. 2577 if (!first) { 2578 expect(COMMARIGHT); 2579 } else { 2580 first = false; 2581 } 2582 2583 // Get and add parameter. 2584 final IdentNode ident = getIdent(); 2585 2586 // ECMA 13.1 strict mode restrictions 2587 verifyStrictIdent(ident, "function parameter"); 2588 2589 parameters.add(ident); 2590 } 2591 2592 return parameters; 2593 } 2594 2595 /** 2596 * FunctionBody : 2597 * SourceElements? 2598 * 2599 * See 13 2600 * 2601 * Parse function body. 2602 * @return function node (body.) 2603 */ 2604 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { 2605 FunctionNode functionNode = null; 2606 long lastToken = 0L; 2607 2608 try { 2609 // Create a new function block. 2610 functionNode = newFunctionNode(firstToken, ident, parameters, kind); 2611 2612 // Nashorn extension: expression closures 2613 if (!env._no_syntax_extensions && type != LBRACE) { 2614 /* 2615 * Example: 2616 * 2617 * function square(x) x * x; 2618 * print(square(3)); 2619 */ 2620 2621 // just expression as function body 2622 final Expression expr = assignmentExpression(true); 2623 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2624 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), finish, expr); 2625 appendStatement(returnNode); 2626 lastToken = token; 2627 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); 2628 2629 } else { 2630 expect(LBRACE); 2631 2632 // Gather the function elements. 2633 final List<Statement> prevFunctionDecls = functionDeclarations; 2634 functionDeclarations = new ArrayList<>(); 2635 try { 2636 sourceElements(); 2637 addFunctionDeclarations(functionNode); 2638 } finally { 2639 functionDeclarations = prevFunctionDecls; 2640 } 2641 2642 lastToken = token; 2643 expect(RBRACE); 2644 functionNode.setFinish(finish); 2645 2646 } 2647 } finally { 2648 functionNode = restoreFunctionNode(functionNode, lastToken); 2649 } 2650 return functionNode; 2651 } 2652 2653 private void addFunctionDeclarations(final FunctionNode functionNode) { 2654 assert lc.peek() == lc.getFunctionBody(functionNode); 2655 VarNode lastDecl = null; 2656 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 2657 Statement decl = functionDeclarations.get(i); 2658 if (lastDecl == null && decl instanceof VarNode) { 2659 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 2660 lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS); 2661 } 2662 prependStatement(decl); 2663 } 2664 } 2665 2666 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 2667 if (earlyError) { 2668 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 2669 } 2670 final ArrayList<Expression> args = new ArrayList<>(); 2671 args.add(lhs); 2672 if (rhs == null) { 2673 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 2674 } else { 2675 args.add(rhs); 2676 } 2677 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 2678 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 2679 } 2680 2681 /* 2682 * parse LHS [a, b, ..., c]. 2683 * 2684 * JavaScript 1.8. 2685 */ 2686 //private Node destructureExpression() { 2687 // return null; 2688 //} 2689 2690 /** 2691 * PostfixExpression : 2692 * LeftHandSideExpression 2693 * LeftHandSideExpression ++ // [no LineTerminator here] 2694 * LeftHandSideExpression -- // [no LineTerminator here] 2695 * 2696 * See 11.3 2697 * 2698 * UnaryExpression : 2699 * PostfixExpression 2700 * delete UnaryExpression 2701 * Node UnaryExpression 2702 * typeof UnaryExpression 2703 * ++ UnaryExpression 2704 * -- UnaryExpression 2705 * + UnaryExpression 2706 * - UnaryExpression 2707 * ~ UnaryExpression 2708 * ! UnaryExpression 2709 * 2710 * See 11.4 2711 * 2712 * Parse unary expression. 2713 * @return Expression node. 2714 */ 2715 private Expression unaryExpression() { 2716 final int unaryLine = line; 2717 final long unaryToken = token; 2718 2719 switch (type) { 2720 case DELETE: { 2721 next(); 2722 final Expression expr = unaryExpression(); 2723 if (expr instanceof BaseNode || expr instanceof IdentNode) { 2724 return new UnaryNode(unaryToken, expr); 2725 } 2726 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 2727 return LiteralNode.newInstance(unaryToken, finish, true); 2728 } 2729 case VOID: 2730 case TYPEOF: 2731 case ADD: 2732 case SUB: 2733 case BIT_NOT: 2734 case NOT: 2735 next(); 2736 final Expression expr = unaryExpression(); 2737 return new UnaryNode(unaryToken, expr); 2738 2739 case INCPREFIX: 2740 case DECPREFIX: 2741 final TokenType opType = type; 2742 next(); 2743 2744 final Expression lhs = leftHandSideExpression(); 2745 // ++, -- without operand.. 2746 if (lhs == null) { 2747 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 2748 } 2749 2750 if (!(lhs instanceof AccessNode || 2751 lhs instanceof IndexNode || 2752 lhs instanceof IdentNode)) { 2753 return referenceError(lhs, null, env._early_lvalue_error); 2754 } 2755 2756 if (lhs instanceof IdentNode) { 2757 if (!checkIdentLValue((IdentNode)lhs)) { 2758 return referenceError(lhs, null, false); 2759 } 2760 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 2761 } 2762 2763 return incDecExpression(unaryToken, opType, lhs, false); 2764 2765 default: 2766 break; 2767 } 2768 2769 Expression expression = leftHandSideExpression(); 2770 2771 if (last != EOL) { 2772 switch (type) { 2773 case INCPREFIX: 2774 case DECPREFIX: 2775 final TokenType opType = type; 2776 final Expression lhs = expression; 2777 // ++, -- without operand.. 2778 if (lhs == null) { 2779 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 2780 } 2781 2782 if (!(lhs instanceof AccessNode || 2783 lhs instanceof IndexNode || 2784 lhs instanceof IdentNode)) { 2785 next(); 2786 return referenceError(lhs, null, env._early_lvalue_error); 2787 } 2788 if (lhs instanceof IdentNode) { 2789 if (!checkIdentLValue((IdentNode)lhs)) { 2790 next(); 2791 return referenceError(lhs, null, false); 2792 } 2793 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 2794 } 2795 expression = incDecExpression(token, type, expression, true); 2796 next(); 2797 break; 2798 default: 2799 break; 2800 } 2801 } 2802 2803 if (expression == null) { 2804 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2805 } 2806 2807 return expression; 2808 } 2809 2810 /** 2811 * MultiplicativeExpression : 2812 * UnaryExpression 2813 * MultiplicativeExpression * UnaryExpression 2814 * MultiplicativeExpression / UnaryExpression 2815 * MultiplicativeExpression % UnaryExpression 2816 * 2817 * See 11.5 2818 * 2819 * AdditiveExpression : 2820 * MultiplicativeExpression 2821 * AdditiveExpression + MultiplicativeExpression 2822 * AdditiveExpression - MultiplicativeExpression 2823 * 2824 * See 11.6 2825 * 2826 * ShiftExpression : 2827 * AdditiveExpression 2828 * ShiftExpression << AdditiveExpression 2829 * ShiftExpression >> AdditiveExpression 2830 * ShiftExpression >>> AdditiveExpression 2831 * 2832 * See 11.7 2833 * 2834 * RelationalExpression : 2835 * ShiftExpression 2836 * RelationalExpression < ShiftExpression 2837 * RelationalExpression > ShiftExpression 2838 * RelationalExpression <= ShiftExpression 2839 * RelationalExpression >= ShiftExpression 2840 * RelationalExpression instanceof ShiftExpression 2841 * RelationalExpression in ShiftExpression // if !noIf 2842 * 2843 * See 11.8 2844 * 2845 * RelationalExpression 2846 * EqualityExpression == RelationalExpression 2847 * EqualityExpression != RelationalExpression 2848 * EqualityExpression === RelationalExpression 2849 * EqualityExpression !== RelationalExpression 2850 * 2851 * See 11.9 2852 * 2853 * BitwiseANDExpression : 2854 * EqualityExpression 2855 * BitwiseANDExpression & EqualityExpression 2856 * 2857 * BitwiseXORExpression : 2858 * BitwiseANDExpression 2859 * BitwiseXORExpression ^ BitwiseANDExpression 2860 * 2861 * BitwiseORExpression : 2862 * BitwiseXORExpression 2863 * BitwiseORExpression | BitwiseXORExpression 2864 * 2865 * See 11.10 2866 * 2867 * LogicalANDExpression : 2868 * BitwiseORExpression 2869 * LogicalANDExpression && BitwiseORExpression 2870 * 2871 * LogicalORExpression : 2872 * LogicalANDExpression 2873 * LogicalORExpression || LogicalANDExpression 2874 * 2875 * See 11.11 2876 * 2877 * ConditionalExpression : 2878 * LogicalORExpression 2879 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 2880 * 2881 * See 11.12 2882 * 2883 * AssignmentExpression : 2884 * ConditionalExpression 2885 * LeftHandSideExpression AssignmentOperator AssignmentExpression 2886 * 2887 * AssignmentOperator : 2888 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 2889 * 2890 * See 11.13 2891 * 2892 * Expression : 2893 * AssignmentExpression 2894 * Expression , AssignmentExpression 2895 * 2896 * See 11.14 2897 * 2898 * Parse expression. 2899 * @return Expression node. 2900 */ 2901 private Expression expression() { 2902 // TODO - Destructuring array. 2903 // Include commas in expression parsing. 2904 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 2905 } 2906 2907 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 2908 // Get the precedence of the next operator. 2909 int precedence = type.getPrecedence(); 2910 Expression lhs = exprLhs; 2911 2912 // While greater precedence. 2913 while (type.isOperator(noIn) && precedence >= minPrecedence) { 2914 // Capture the operator token. 2915 final long op = token; 2916 2917 if (type == TERNARY) { 2918 // Skip operator. 2919 next(); 2920 2921 // Pass expression. Middle expression of a conditional expression can be a "in" 2922 // expression - even in the contexts where "in" is not permitted. 2923 final Expression rhs = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 2924 2925 expect(COLON); 2926 2927 // Fail expression. 2928 final Expression third = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 2929 2930 // Build up node. 2931 lhs = new TernaryNode(op, lhs, rhs, third); 2932 } else { 2933 // Skip operator. 2934 next(); 2935 2936 // Get the next primary expression. 2937 Expression rhs = unaryExpression(); 2938 2939 // Get precedence of next operator. 2940 int nextPrecedence = type.getPrecedence(); 2941 2942 // Subtask greater precedence. 2943 while (type.isOperator(noIn) && 2944 (nextPrecedence > precedence || 2945 nextPrecedence == precedence && !type.isLeftAssociative())) { 2946 rhs = expression(rhs, nextPrecedence, noIn); 2947 nextPrecedence = type.getPrecedence(); 2948 } 2949 2950 lhs = verifyAssignment(op, lhs, rhs); 2951 } 2952 2953 precedence = type.getPrecedence(); 2954 } 2955 2956 return lhs; 2957 } 2958 2959 private Expression assignmentExpression(final boolean noIn) { 2960 // TODO - Handle decompose. 2961 // Exclude commas in expression parsing. 2962 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 2963 } 2964 2965 /** 2966 * Parse an end of line. 2967 */ 2968 private void endOfLine() { 2969 switch (type) { 2970 case SEMICOLON: 2971 case EOL: 2972 next(); 2973 break; 2974 case RPAREN: 2975 case RBRACKET: 2976 case RBRACE: 2977 case EOF: 2978 break; 2979 default: 2980 if (last != EOL) { 2981 expect(SEMICOLON); 2982 } 2983 break; 2984 } 2985 } 2986 2987 @Override 2988 public String toString() { 2989 return "[JavaScript Parsing]"; 2990 } 2991 2992 private static void markEval(final LexicalContext lc) { 2993 final Iterator<FunctionNode> iter = lc.getFunctions(); 2994 boolean flaggedCurrentFn = false; 2995 while (iter.hasNext()) { 2996 final FunctionNode fn = iter.next(); 2997 if (!flaggedCurrentFn) { 2998 lc.setFlag(fn, FunctionNode.HAS_EVAL); 2999 flaggedCurrentFn = true; 3000 } else { 3001 lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL); 3002 } 3003 lc.setBlockNeedsScope(lc.getFunctionBody(fn)); 3004 } 3005 } 3006 3007 private void prependStatement(final Statement statement) { 3008 lc.prependStatement(statement); 3009 } 3010 3011 private void appendStatement(final Statement statement) { 3012 lc.appendStatement(statement); 3013 } 3014 }