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