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