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(false, false, true); 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, false); 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, false); 866 } 867 868 /** 869 * @param topLevel does this statement occur at the "top level" of a script or a function? 870 * @param allowPropertyFunction allow property "get" and "set" functions? 871 * @param singleStatement are we in a single statement context? 872 */ 873 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { 874 if (type == FUNCTION) { 875 // As per spec (ECMA section 12), function declarations as arbitrary statement 876 // is not "portable". Implementation can issue a warning or disallow the same. 877 functionExpression(true, topLevel); 878 return; 879 } 880 881 switch (type) { 882 case LBRACE: 883 block(); 884 break; 885 case VAR: 886 variableStatement(type, true); 887 break; 888 case SEMICOLON: 889 emptyStatement(); 890 break; 891 case IF: 892 ifStatement(); 893 break; 894 case FOR: 895 forStatement(); 896 break; 897 case WHILE: 898 whileStatement(); 899 break; 900 case DO: 901 doStatement(); 902 break; 903 case CONTINUE: 904 continueStatement(); 905 break; 906 case BREAK: 907 breakStatement(); 908 break; 909 case RETURN: 910 returnStatement(); 911 break; 912 case YIELD: 913 yieldStatement(); 914 break; 915 case WITH: 916 withStatement(); 917 break; 918 case SWITCH: 919 switchStatement(); 920 break; 921 case THROW: 922 throwStatement(); 923 break; 924 case TRY: 925 tryStatement(); 926 break; 927 case DEBUGGER: 928 debuggerStatement(); 929 break; 930 case RPAREN: 931 case RBRACKET: 932 case EOF: 933 expect(SEMICOLON); 934 break; 935 default: 936 if (useBlockScope() && (type == LET || type == CONST)) { 937 if (singleStatement) { 938 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); 939 } 940 variableStatement(type, true); 941 break; 942 } 943 if (env._const_as_var && type == CONST) { 944 variableStatement(TokenType.VAR, true); 945 break; 946 } 947 948 if (type == IDENT || isNonStrictModeIdent()) { 949 if (T(k + 1) == COLON) { 950 labelStatement(); 951 return; 952 } 953 if(allowPropertyFunction) { 954 final String ident = (String)getValue(); 955 final long propertyToken = token; 956 final int propertyLine = line; 957 if("get".equals(ident)) { 958 next(); 959 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); 960 return; 961 } else if("set".equals(ident)) { 962 next(); 963 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); 964 return; 965 } 966 } 967 } 968 969 expressionStatement(); 970 break; 971 } 972 } 973 974 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { 975 final FunctionNode fn = propertyFunction.functionNode; 976 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); 977 } 978 979 /** 980 * block : 981 * { StatementList? } 982 * 983 * see 12.1 984 * 985 * Parse a statement block. 986 */ 987 private void block() { 988 appendStatement(new BlockStatement(line, getBlock(true))); 989 } 990 991 /** 992 * StatementList : 993 * Statement 994 * StatementList Statement 995 * 996 * See 12.1 997 * 998 * Parse a list of statements. 999 */ 1000 private void statementList() { 1001 // Accumulate statements until end of list. */ 1002 loop: 1003 while (type != EOF) { 1004 switch (type) { 1005 case EOF: 1006 case CASE: 1007 case DEFAULT: 1008 case RBRACE: 1009 break loop; 1010 default: 1011 break; 1012 } 1013 1014 // Get next statement. 1015 statement(); 1016 } 1017 } 1018 1019 /** 1020 * Make sure that in strict mode, the identifier name used is allowed. 1021 * 1022 * @param ident Identifier that is verified 1023 * @param contextString String used in error message to give context to the user 1024 */ 1025 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 1026 if (isStrictMode) { 1027 switch (ident.getName()) { 1028 case "eval": 1029 case "arguments": 1030 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1031 default: 1032 break; 1033 } 1034 1035 if (ident.isFutureStrictName()) { 1036 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1037 } 1038 } 1039 } 1040 1041 /** 1042 * VariableStatement : 1043 * var VariableDeclarationList ; 1044 * 1045 * VariableDeclarationList : 1046 * VariableDeclaration 1047 * VariableDeclarationList , VariableDeclaration 1048 * 1049 * VariableDeclaration : 1050 * Identifier Initializer? 1051 * 1052 * Initializer : 1053 * = AssignmentExpression 1054 * 1055 * See 12.2 1056 * 1057 * Parse a VAR statement. 1058 * @param isStatement True if a statement (not used in a FOR.) 1059 */ 1060 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) { 1061 // VAR tested in caller. 1062 next(); 1063 1064 final List<VarNode> vars = new ArrayList<>(); 1065 int varFlags = 0; 1066 if (varType == LET) { 1067 varFlags |= VarNode.IS_LET; 1068 } else if (varType == CONST) { 1069 varFlags |= VarNode.IS_CONST; 1070 } 1071 1072 while (true) { 1073 // Get starting token. 1074 final int varLine = line; 1075 final long varToken = token; 1076 // Get name of var. 1077 final IdentNode name = getIdent(); 1078 verifyStrictIdent(name, "variable name"); 1079 1080 // Assume no init. 1081 Expression init = null; 1082 1083 // Look for initializer assignment. 1084 if (type == ASSIGN) { 1085 next(); 1086 1087 // Get initializer expression. Suppress IN if not statement. 1088 defaultNames.push(name); 1089 try { 1090 init = assignmentExpression(!isStatement); 1091 } finally { 1092 defaultNames.pop(); 1093 } 1094 } else if (varType == CONST) { 1095 throw error(AbstractParser.message("missing.const.assignment", name.getName())); 1096 } 1097 1098 // Allocate var node. 1099 final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags); 1100 vars.add(var); 1101 appendStatement(var); 1102 1103 if (type != COMMARIGHT) { 1104 break; 1105 } 1106 next(); 1107 } 1108 1109 // If is a statement then handle end of line. 1110 if (isStatement) { 1111 final boolean semicolon = type == SEMICOLON; 1112 endOfLine(); 1113 if (semicolon) { 1114 lc.getCurrentBlock().setFinish(finish); 1115 } 1116 } 1117 1118 return vars; 1119 } 1120 1121 /** 1122 * EmptyStatement : 1123 * ; 1124 * 1125 * See 12.3 1126 * 1127 * Parse an empty statement. 1128 */ 1129 private void emptyStatement() { 1130 if (env._empty_statements) { 1131 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); 1132 } 1133 1134 // SEMICOLON checked in caller. 1135 next(); 1136 } 1137 1138 /** 1139 * ExpressionStatement : 1140 * Expression ; // [lookahead ~( or function )] 1141 * 1142 * See 12.4 1143 * 1144 * Parse an expression used in a statement block. 1145 */ 1146 private void expressionStatement() { 1147 // Lookahead checked in caller. 1148 final int expressionLine = line; 1149 final long expressionToken = token; 1150 1151 // Get expression and add as statement. 1152 final Expression expression = expression(); 1153 1154 ExpressionStatement expressionStatement = null; 1155 if (expression != null) { 1156 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); 1157 appendStatement(expressionStatement); 1158 } else { 1159 expect(null); 1160 } 1161 1162 endOfLine(); 1163 1164 if (expressionStatement != null) { 1165 expressionStatement.setFinish(finish); 1166 lc.getCurrentBlock().setFinish(finish); 1167 } 1168 } 1169 1170 /** 1171 * IfStatement : 1172 * if ( Expression ) Statement else Statement 1173 * if ( Expression ) Statement 1174 * 1175 * See 12.5 1176 * 1177 * Parse an IF statement. 1178 */ 1179 private void ifStatement() { 1180 // Capture IF token. 1181 final int ifLine = line; 1182 final long ifToken = token; 1183 // IF tested in caller. 1184 next(); 1185 1186 expect(LPAREN); 1187 final Expression test = expression(); 1188 expect(RPAREN); 1189 final Block pass = getStatement(); 1190 1191 Block fail = null; 1192 if (type == ELSE) { 1193 next(); 1194 fail = getStatement(); 1195 } 1196 1197 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 1198 } 1199 1200 /** 1201 * ... IterationStatement: 1202 * ... 1203 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement 1204 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement 1205 * for ( LeftHandSideExpression in Expression ) Statement 1206 * for ( var VariableDeclaration[NoIn] in Expression ) Statement 1207 * 1208 * See 12.6 1209 * 1210 * Parse a FOR statement. 1211 */ 1212 private void forStatement() { 1213 // When ES6 for-let is enabled we create a container block to capture the LET. 1214 final int startLine = start; 1215 Block outer = useBlockScope() ? newBlock() : null; 1216 1217 // Create FOR node, capturing FOR token. 1218 ForNode forNode = new ForNode(line, token, Token.descPosition(token), null, 0); 1219 lc.push(forNode); 1220 1221 try { 1222 // FOR tested in caller. 1223 next(); 1224 1225 // Nashorn extension: for each expression. 1226 // iterate property values rather than property names. 1227 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 1228 forNode = forNode.setIsForEach(lc); 1229 next(); 1230 } 1231 1232 expect(LPAREN); 1233 1234 List<VarNode> vars = null; 1235 1236 switch (type) { 1237 case VAR: 1238 // Var declaration captured in for outer block. 1239 vars = variableStatement(type, false); 1240 break; 1241 case SEMICOLON: 1242 break; 1243 default: 1244 if (useBlockScope() && (type == LET || type == CONST)) { 1245 if (type == LET) { 1246 forNode = forNode.setPerIterationScope(lc); 1247 } 1248 // LET/CONST declaration captured in container block created above. 1249 vars = variableStatement(type, false); 1250 break; 1251 } 1252 if (env._const_as_var && type == CONST) { 1253 // Var declaration captured in for outer block. 1254 vars = variableStatement(TokenType.VAR, false); 1255 break; 1256 } 1257 1258 final Expression expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 1259 forNode = forNode.setInit(lc, expression); 1260 break; 1261 } 1262 1263 switch (type) { 1264 case SEMICOLON: 1265 // for (init; test; modify) 1266 1267 // for each (init; test; modify) is invalid 1268 if (forNode.isForEach()) { 1269 throw error(AbstractParser.message("for.each.without.in"), token); 1270 } 1271 1272 expect(SEMICOLON); 1273 if (type != SEMICOLON) { 1274 forNode = forNode.setTest(lc, joinPredecessorExpression()); 1275 } 1276 expect(SEMICOLON); 1277 if (type != RPAREN) { 1278 forNode = forNode.setModify(lc, joinPredecessorExpression()); 1279 } 1280 break; 1281 1282 case IN: 1283 forNode = forNode.setIsForIn(lc).setTest(lc, new JoinPredecessorExpression()); 1284 if (vars != null) { 1285 // for (var i in obj) 1286 if (vars.size() == 1) { 1287 forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName())); 1288 } else { 1289 // for (var i, j in obj) is invalid 1290 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 1291 } 1292 1293 } else { 1294 // for (expr in obj) 1295 final Node init = forNode.getInit(); 1296 assert init != null : "for..in init expression can not be null here"; 1297 1298 // check if initial expression is a valid L-value 1299 if (!(init instanceof AccessNode || 1300 init instanceof IndexNode || 1301 init instanceof IdentNode)) { 1302 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1303 } 1304 1305 if (init instanceof IdentNode) { 1306 if (!checkIdentLValue((IdentNode)init)) { 1307 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1308 } 1309 verifyStrictIdent((IdentNode)init, "for-in iterator"); 1310 } 1311 } 1312 1313 next(); 1314 1315 // Get the collection expression. 1316 forNode = forNode.setModify(lc, joinPredecessorExpression()); 1317 break; 1318 1319 default: 1320 expect(SEMICOLON); 1321 break; 1322 } 1323 1324 expect(RPAREN); 1325 1326 // Set the for body. 1327 final Block body = getStatement(); 1328 forNode = forNode.setBody(lc, body); 1329 forNode.setFinish(body.getFinish()); 1330 1331 appendStatement(forNode); 1332 } finally { 1333 lc.pop(forNode); 1334 } 1335 1336 if (outer != null) { 1337 outer.setFinish(forNode.getFinish()); 1338 outer = restoreBlock(outer); 1339 appendStatement(new BlockStatement(startLine, outer)); 1340 } 1341 } 1342 1343 /** 1344 * ... IterationStatement : 1345 * ... 1346 * Expression[NoIn]?; Expression? ; Expression? 1347 * var VariableDeclarationList[NoIn]; Expression? ; Expression? 1348 * LeftHandSideExpression in Expression 1349 * var VariableDeclaration[NoIn] in Expression 1350 * 1351 * See 12.6 1352 * 1353 * Parse the control section of a FOR statement. Also used for 1354 * comprehensions. 1355 * @param forNode Owning FOR. 1356 */ 1357 1358 1359 /** 1360 * ...IterationStatement : 1361 * ... 1362 * while ( Expression ) Statement 1363 * ... 1364 * 1365 * See 12.6 1366 * 1367 * Parse while statement. 1368 */ 1369 private void whileStatement() { 1370 // Capture WHILE token. 1371 final long whileToken = token; 1372 // WHILE tested in caller. 1373 next(); 1374 1375 // Construct WHILE node. 1376 WhileNode whileNode = new WhileNode(line, whileToken, Token.descPosition(whileToken), false); 1377 lc.push(whileNode); 1378 1379 try { 1380 expect(LPAREN); 1381 final int whileLine = line; 1382 final JoinPredecessorExpression test = joinPredecessorExpression(); 1383 expect(RPAREN); 1384 final Block body = getStatement(); 1385 appendStatement(whileNode = 1386 new WhileNode(whileLine, whileToken, finish, false). 1387 setTest(lc, test). 1388 setBody(lc, body)); 1389 } finally { 1390 lc.pop(whileNode); 1391 } 1392 } 1393 1394 /** 1395 * ...IterationStatement : 1396 * ... 1397 * do Statement while( Expression ) ; 1398 * ... 1399 * 1400 * See 12.6 1401 * 1402 * Parse DO WHILE statement. 1403 */ 1404 private void doStatement() { 1405 // Capture DO token. 1406 final long doToken = token; 1407 // DO tested in the caller. 1408 next(); 1409 1410 WhileNode doWhileNode = new WhileNode(-1, doToken, Token.descPosition(doToken), true); 1411 lc.push(doWhileNode); 1412 1413 try { 1414 // Get DO body. 1415 final Block body = getStatement(); 1416 1417 expect(WHILE); 1418 expect(LPAREN); 1419 final int doLine = line; 1420 final JoinPredecessorExpression test = joinPredecessorExpression(); 1421 expect(RPAREN); 1422 1423 if (type == SEMICOLON) { 1424 endOfLine(); 1425 } 1426 doWhileNode.setFinish(finish); 1427 1428 //line number is last 1429 appendStatement(doWhileNode = 1430 new WhileNode(doLine, doToken, finish, true). 1431 setBody(lc, body). 1432 setTest(lc, test)); 1433 } finally { 1434 lc.pop(doWhileNode); 1435 } 1436 } 1437 1438 /** 1439 * ContinueStatement : 1440 * continue Identifier? ; // [no LineTerminator here] 1441 * 1442 * See 12.7 1443 * 1444 * Parse CONTINUE statement. 1445 */ 1446 private void continueStatement() { 1447 // Capture CONTINUE token. 1448 final int continueLine = line; 1449 final long continueToken = token; 1450 // CONTINUE tested in caller. 1451 nextOrEOL(); 1452 1453 LabelNode labelNode = null; 1454 1455 // SEMICOLON or label. 1456 switch (type) { 1457 case RBRACE: 1458 case SEMICOLON: 1459 case EOL: 1460 case EOF: 1461 break; 1462 1463 default: 1464 final IdentNode ident = getIdent(); 1465 labelNode = lc.findLabel(ident.getName()); 1466 1467 if (labelNode == null) { 1468 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1469 } 1470 1471 break; 1472 } 1473 1474 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1475 final LoopNode targetNode = lc.getContinueTo(labelName); 1476 1477 if (targetNode == null) { 1478 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 1479 } 1480 1481 endOfLine(); 1482 1483 // Construct and add CONTINUE node. 1484 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); 1485 } 1486 1487 /** 1488 * BreakStatement : 1489 * break Identifier? ; // [no LineTerminator here] 1490 * 1491 * See 12.8 1492 * 1493 */ 1494 private void breakStatement() { 1495 // Capture BREAK token. 1496 final int breakLine = line; 1497 final long breakToken = token; 1498 // BREAK tested in caller. 1499 nextOrEOL(); 1500 1501 LabelNode labelNode = null; 1502 1503 // SEMICOLON or label. 1504 switch (type) { 1505 case RBRACE: 1506 case SEMICOLON: 1507 case EOL: 1508 case EOF: 1509 break; 1510 1511 default: 1512 final IdentNode ident = getIdent(); 1513 labelNode = lc.findLabel(ident.getName()); 1514 1515 if (labelNode == null) { 1516 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1517 } 1518 1519 break; 1520 } 1521 1522 //either an explicit label - then get its node or just a "break" - get first breakable 1523 //targetNode is what we are breaking out from. 1524 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1525 final BreakableNode targetNode = lc.getBreakable(labelName); 1526 if (targetNode == null) { 1527 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 1528 } 1529 1530 endOfLine(); 1531 1532 // Construct and add BREAK node. 1533 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); 1534 } 1535 1536 /** 1537 * ReturnStatement : 1538 * return Expression? ; // [no LineTerminator here] 1539 * 1540 * See 12.9 1541 * 1542 * Parse RETURN statement. 1543 */ 1544 private void returnStatement() { 1545 // check for return outside function 1546 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { 1547 throw error(AbstractParser.message("invalid.return")); 1548 } 1549 1550 // Capture RETURN token. 1551 final int returnLine = line; 1552 final long returnToken = token; 1553 // RETURN tested in caller. 1554 nextOrEOL(); 1555 1556 Expression expression = null; 1557 1558 // SEMICOLON or expression. 1559 switch (type) { 1560 case RBRACE: 1561 case SEMICOLON: 1562 case EOL: 1563 case EOF: 1564 break; 1565 1566 default: 1567 expression = expression(); 1568 break; 1569 } 1570 1571 endOfLine(); 1572 1573 // Construct and add RETURN node. 1574 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); 1575 } 1576 1577 /** 1578 * YieldStatement : 1579 * yield Expression? ; // [no LineTerminator here] 1580 * 1581 * JavaScript 1.8 1582 * 1583 * Parse YIELD statement. 1584 */ 1585 private void yieldStatement() { 1586 // Capture YIELD token. 1587 final int yieldLine = line; 1588 final long yieldToken = token; 1589 // YIELD tested in caller. 1590 nextOrEOL(); 1591 1592 Expression expression = null; 1593 1594 // SEMICOLON or expression. 1595 switch (type) { 1596 case RBRACE: 1597 case SEMICOLON: 1598 case EOL: 1599 case EOF: 1600 break; 1601 1602 default: 1603 expression = expression(); 1604 break; 1605 } 1606 1607 endOfLine(); 1608 1609 // Construct and add YIELD node. 1610 appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); 1611 } 1612 1613 /** 1614 * WithStatement : 1615 * with ( Expression ) Statement 1616 * 1617 * See 12.10 1618 * 1619 * Parse WITH statement. 1620 */ 1621 private void withStatement() { 1622 // Capture WITH token. 1623 final int withLine = line; 1624 final long withToken = token; 1625 // WITH tested in caller. 1626 next(); 1627 1628 // ECMA 12.10.1 strict mode restrictions 1629 if (isStrictMode) { 1630 throw error(AbstractParser.message("strict.no.with"), withToken); 1631 } 1632 1633 // Get WITH expression. 1634 WithNode withNode = new WithNode(withLine, withToken, finish); 1635 1636 try { 1637 lc.push(withNode); 1638 expect(LPAREN); 1639 withNode = withNode.setExpression(lc, expression()); 1640 expect(RPAREN); 1641 withNode = withNode.setBody(lc, getStatement()); 1642 } finally { 1643 lc.pop(withNode); 1644 } 1645 1646 appendStatement(withNode); 1647 } 1648 1649 /** 1650 * SwitchStatement : 1651 * switch ( Expression ) CaseBlock 1652 * 1653 * CaseBlock : 1654 * { CaseClauses? } 1655 * { CaseClauses? DefaultClause CaseClauses } 1656 * 1657 * CaseClauses : 1658 * CaseClause 1659 * CaseClauses CaseClause 1660 * 1661 * CaseClause : 1662 * case Expression : StatementList? 1663 * 1664 * DefaultClause : 1665 * default : StatementList? 1666 * 1667 * See 12.11 1668 * 1669 * Parse SWITCH statement. 1670 */ 1671 private void switchStatement() { 1672 final int switchLine = line; 1673 final long switchToken = token; 1674 // SWITCH tested in caller. 1675 next(); 1676 1677 // Create and add switch statement. 1678 SwitchNode switchNode = new SwitchNode(switchLine, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null); 1679 lc.push(switchNode); 1680 1681 try { 1682 expect(LPAREN); 1683 switchNode = switchNode.setExpression(lc, expression()); 1684 expect(RPAREN); 1685 1686 expect(LBRACE); 1687 1688 // Prepare to accumulate cases. 1689 final List<CaseNode> cases = new ArrayList<>(); 1690 CaseNode defaultCase = null; 1691 1692 while (type != RBRACE) { 1693 // Prepare for next case. 1694 Expression caseExpression = null; 1695 final long caseToken = token; 1696 1697 switch (type) { 1698 case CASE: 1699 next(); 1700 caseExpression = expression(); 1701 break; 1702 1703 case DEFAULT: 1704 if (defaultCase != null) { 1705 throw error(AbstractParser.message("duplicate.default.in.switch")); 1706 } 1707 next(); 1708 break; 1709 1710 default: 1711 // Force an error. 1712 expect(CASE); 1713 break; 1714 } 1715 1716 expect(COLON); 1717 1718 // Get CASE body. 1719 final Block statements = getBlock(false); 1720 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); 1721 statements.setFinish(finish); 1722 1723 if (caseExpression == null) { 1724 defaultCase = caseNode; 1725 } 1726 1727 cases.add(caseNode); 1728 } 1729 1730 switchNode = switchNode.setCases(lc, cases, defaultCase); 1731 next(); 1732 switchNode.setFinish(finish); 1733 1734 appendStatement(switchNode); 1735 } finally { 1736 lc.pop(switchNode); 1737 } 1738 } 1739 1740 /** 1741 * LabelledStatement : 1742 * Identifier : Statement 1743 * 1744 * See 12.12 1745 * 1746 * Parse label statement. 1747 */ 1748 private void labelStatement() { 1749 // Capture label token. 1750 final long labelToken = token; 1751 // Get label ident. 1752 final IdentNode ident = getIdent(); 1753 1754 expect(COLON); 1755 1756 if (lc.findLabel(ident.getName()) != null) { 1757 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 1758 } 1759 1760 LabelNode labelNode = new LabelNode(line, labelToken, finish, ident.getName(), null); 1761 try { 1762 lc.push(labelNode); 1763 labelNode = labelNode.setBody(lc, getStatement()); 1764 labelNode.setFinish(finish); 1765 appendStatement(labelNode); 1766 } finally { 1767 assert lc.peek() instanceof LabelNode; 1768 lc.pop(labelNode); 1769 } 1770 } 1771 1772 /** 1773 * ThrowStatement : 1774 * throw Expression ; // [no LineTerminator here] 1775 * 1776 * See 12.13 1777 * 1778 * Parse throw statement. 1779 */ 1780 private void throwStatement() { 1781 // Capture THROW token. 1782 final int throwLine = line; 1783 final long throwToken = token; 1784 // THROW tested in caller. 1785 nextOrEOL(); 1786 1787 Expression expression = null; 1788 1789 // SEMICOLON or expression. 1790 switch (type) { 1791 case RBRACE: 1792 case SEMICOLON: 1793 case EOL: 1794 break; 1795 1796 default: 1797 expression = expression(); 1798 break; 1799 } 1800 1801 if (expression == null) { 1802 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 1803 } 1804 1805 endOfLine(); 1806 1807 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); 1808 } 1809 1810 /** 1811 * TryStatement : 1812 * try Block Catch 1813 * try Block Finally 1814 * try Block Catch Finally 1815 * 1816 * Catch : 1817 * catch( Identifier if Expression ) Block 1818 * catch( Identifier ) Block 1819 * 1820 * Finally : 1821 * finally Block 1822 * 1823 * See 12.14 1824 * 1825 * Parse TRY statement. 1826 */ 1827 private void tryStatement() { 1828 // Capture TRY token. 1829 final int tryLine = line; 1830 final long tryToken = token; 1831 // TRY tested in caller. 1832 next(); 1833 1834 // Container block needed to act as target for labeled break statements 1835 final int startLine = line; 1836 Block outer = newBlock(); 1837 1838 // Create try. 1839 1840 try { 1841 final Block tryBody = getBlock(true); 1842 final List<Block> catchBlocks = new ArrayList<>(); 1843 1844 while (type == CATCH) { 1845 final int catchLine = line; 1846 final long catchToken = token; 1847 next(); 1848 expect(LPAREN); 1849 final IdentNode exception = getIdent(); 1850 1851 // ECMA 12.4.1 strict mode restrictions 1852 verifyStrictIdent(exception, "catch argument"); 1853 1854 // Nashorn extension: catch clause can have optional 1855 // condition. So, a single try can have more than one 1856 // catch clause each with it's own condition. 1857 final Expression ifExpression; 1858 if (!env._no_syntax_extensions && type == IF) { 1859 next(); 1860 // Get the exception condition. 1861 ifExpression = expression(); 1862 } else { 1863 ifExpression = null; 1864 } 1865 1866 expect(RPAREN); 1867 1868 Block catchBlock = newBlock(); 1869 try { 1870 // Get CATCH body. 1871 final Block catchBody = getBlock(true); 1872 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); 1873 appendStatement(catchNode); 1874 } finally { 1875 catchBlock = restoreBlock(catchBlock); 1876 catchBlocks.add(catchBlock); 1877 } 1878 1879 // If unconditional catch then should to be the end. 1880 if (ifExpression == null) { 1881 break; 1882 } 1883 } 1884 1885 // Prepare to capture finally statement. 1886 Block finallyStatements = null; 1887 1888 if (type == FINALLY) { 1889 next(); 1890 finallyStatements = getBlock(true); 1891 } 1892 1893 // Need at least one catch or a finally. 1894 if (catchBlocks.isEmpty() && finallyStatements == null) { 1895 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 1896 } 1897 1898 final TryNode tryNode = new TryNode(tryLine, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements); 1899 // Add try. 1900 assert lc.peek() == outer; 1901 appendStatement(tryNode); 1902 1903 tryNode.setFinish(finish); 1904 outer.setFinish(finish); 1905 1906 } finally { 1907 outer = restoreBlock(outer); 1908 } 1909 1910 appendStatement(new BlockStatement(startLine, outer)); 1911 } 1912 1913 /** 1914 * DebuggerStatement : 1915 * debugger ; 1916 * 1917 * See 12.15 1918 * 1919 * Parse debugger statement. 1920 */ 1921 private void debuggerStatement() { 1922 // Capture DEBUGGER token. 1923 final int debuggerLine = line; 1924 final long debuggerToken = token; 1925 // DEBUGGER tested in caller. 1926 next(); 1927 endOfLine(); 1928 appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Expression>()))); 1929 } 1930 1931 /** 1932 * PrimaryExpression : 1933 * this 1934 * Identifier 1935 * Literal 1936 * ArrayLiteral 1937 * ObjectLiteral 1938 * ( Expression ) 1939 * 1940 * See 11.1 1941 * 1942 * Parse primary expression. 1943 * @return Expression node. 1944 */ 1945 @SuppressWarnings("fallthrough") 1946 private Expression primaryExpression() { 1947 // Capture first token. 1948 final int primaryLine = line; 1949 final long primaryToken = token; 1950 1951 switch (type) { 1952 case THIS: 1953 final String name = type.getName(); 1954 next(); 1955 lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_THIS); 1956 return new IdentNode(primaryToken, finish, name); 1957 case IDENT: 1958 final IdentNode ident = getIdent(); 1959 if (ident == null) { 1960 break; 1961 } 1962 detectSpecialProperty(ident); 1963 return ident; 1964 case OCTAL: 1965 if (isStrictMode) { 1966 throw error(AbstractParser.message("strict.no.octal"), token); 1967 } 1968 case STRING: 1969 case ESCSTRING: 1970 case DECIMAL: 1971 case HEXADECIMAL: 1972 case FLOATING: 1973 case REGEX: 1974 case XML: 1975 return getLiteral(); 1976 case EXECSTRING: 1977 return execString(primaryLine, primaryToken); 1978 case FALSE: 1979 next(); 1980 return LiteralNode.newInstance(primaryToken, finish, false); 1981 case TRUE: 1982 next(); 1983 return LiteralNode.newInstance(primaryToken, finish, true); 1984 case NULL: 1985 next(); 1986 return LiteralNode.newInstance(primaryToken, finish); 1987 case LBRACKET: 1988 return arrayLiteral(); 1989 case LBRACE: 1990 return objectLiteral(); 1991 case LPAREN: 1992 next(); 1993 1994 final Expression expression = expression(); 1995 1996 expect(RPAREN); 1997 1998 return expression; 1999 2000 default: 2001 // In this context some operator tokens mark the start of a literal. 2002 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 2003 next(); 2004 return getLiteral(); 2005 } 2006 if (isNonStrictModeIdent()) { 2007 return getIdent(); 2008 } 2009 break; 2010 } 2011 2012 return null; 2013 } 2014 2015 /** 2016 * Convert execString to a call to $EXEC. 2017 * 2018 * @param primaryToken Original string token. 2019 * @return callNode to $EXEC. 2020 */ 2021 CallNode execString(final int primaryLine, final long primaryToken) { 2022 // Synthesize an ident to call $EXEC. 2023 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 2024 // Skip over EXECSTRING. 2025 next(); 2026 // Set up argument list for call. 2027 // Skip beginning of edit string expression. 2028 expect(LBRACE); 2029 // Add the following expression to arguments. 2030 final List<Expression> arguments = Collections.singletonList(expression()); 2031 // Skip ending of edit string expression. 2032 expect(RBRACE); 2033 2034 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2035 } 2036 2037 /** 2038 * ArrayLiteral : 2039 * [ Elision? ] 2040 * [ ElementList ] 2041 * [ ElementList , Elision? ] 2042 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2043 * 2044 * ElementList : Elision? AssignmentExpression 2045 * ElementList , Elision? AssignmentExpression 2046 * 2047 * Elision : 2048 * , 2049 * Elision , 2050 * 2051 * See 12.1.4 2052 * JavaScript 1.8 2053 * 2054 * Parse array literal. 2055 * @return Expression node. 2056 */ 2057 private LiteralNode<Expression[]> arrayLiteral() { 2058 // Capture LBRACKET token. 2059 final long arrayToken = token; 2060 // LBRACKET tested in caller. 2061 next(); 2062 2063 // Prepare to accummulating elements. 2064 final List<Expression> elements = new ArrayList<>(); 2065 // Track elisions. 2066 boolean elision = true; 2067 loop: 2068 while (true) { 2069 switch (type) { 2070 case RBRACKET: 2071 next(); 2072 2073 break loop; 2074 2075 case COMMARIGHT: 2076 next(); 2077 2078 // If no prior expression 2079 if (elision) { 2080 elements.add(null); 2081 } 2082 2083 elision = true; 2084 2085 break; 2086 2087 default: 2088 if (!elision) { 2089 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2090 } 2091 // Add expression element. 2092 final Expression expression = assignmentExpression(false); 2093 2094 if (expression != null) { 2095 elements.add(expression); 2096 } else { 2097 expect(RBRACKET); 2098 } 2099 2100 elision = false; 2101 break; 2102 } 2103 } 2104 2105 return LiteralNode.newInstance(arrayToken, finish, elements); 2106 } 2107 2108 /** 2109 * ObjectLiteral : 2110 * { } 2111 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2112 * 2113 * PropertyNameAndValueList : 2114 * PropertyAssignment 2115 * PropertyNameAndValueList , PropertyAssignment 2116 * 2117 * See 11.1.5 2118 * 2119 * Parse an object literal. 2120 * @return Expression node. 2121 */ 2122 private ObjectNode objectLiteral() { 2123 // Capture LBRACE token. 2124 final long objectToken = token; 2125 // LBRACE tested in caller. 2126 next(); 2127 2128 // Object context. 2129 // Prepare to accumulate elements. 2130 final List<PropertyNode> elements = new ArrayList<>(); 2131 final Map<String, Integer> map = new HashMap<>(); 2132 2133 // Create a block for the object literal. 2134 boolean commaSeen = true; 2135 loop: 2136 while (true) { 2137 switch (type) { 2138 case RBRACE: 2139 next(); 2140 break loop; 2141 2142 case COMMARIGHT: 2143 if (commaSeen) { 2144 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2145 } 2146 next(); 2147 commaSeen = true; 2148 break; 2149 2150 default: 2151 if (!commaSeen) { 2152 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2153 } 2154 2155 commaSeen = false; 2156 // Get and add the next property. 2157 final PropertyNode property = propertyAssignment(); 2158 final String key = property.getKeyName(); 2159 final Integer existing = map.get(key); 2160 2161 if (existing == null) { 2162 map.put(key, elements.size()); 2163 elements.add(property); 2164 break; 2165 } 2166 2167 final PropertyNode existingProperty = elements.get(existing); 2168 2169 // ECMA section 11.1.5 Object Initialiser 2170 // point # 4 on property assignment production 2171 final Expression value = property.getValue(); 2172 final FunctionNode getter = property.getGetter(); 2173 final FunctionNode setter = property.getSetter(); 2174 2175 final Expression prevValue = existingProperty.getValue(); 2176 final FunctionNode prevGetter = existingProperty.getGetter(); 2177 final FunctionNode prevSetter = existingProperty.getSetter(); 2178 2179 // ECMA 11.1.5 strict mode restrictions 2180 if (isStrictMode && value != null && prevValue != null) { 2181 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2182 } 2183 2184 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2185 final boolean isAccessor = getter != null || setter != null; 2186 2187 // data property redefined as accessor property 2188 if (prevValue != null && isAccessor) { 2189 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2190 } 2191 2192 // accessor property redefined as data 2193 if (isPrevAccessor && value != null) { 2194 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2195 } 2196 2197 if (isAccessor && isPrevAccessor) { 2198 if (getter != null && prevGetter != null || 2199 setter != null && prevSetter != null) { 2200 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2201 } 2202 } 2203 2204 if (value != null) { 2205 elements.add(property); 2206 } else if (getter != null) { 2207 elements.set(existing, existingProperty.setGetter(getter)); 2208 } else if (setter != null) { 2209 elements.set(existing, existingProperty.setSetter(setter)); 2210 } 2211 break; 2212 } 2213 } 2214 2215 return new ObjectNode(objectToken, finish, elements); 2216 } 2217 2218 /** 2219 * PropertyName : 2220 * IdentifierName 2221 * StringLiteral 2222 * NumericLiteral 2223 * 2224 * See 11.1.5 2225 * 2226 * @return PropertyName node 2227 */ 2228 @SuppressWarnings("fallthrough") 2229 private PropertyKey propertyName() { 2230 switch (type) { 2231 case IDENT: 2232 return getIdent().setIsPropertyName(); 2233 case OCTAL: 2234 if (isStrictMode) { 2235 throw error(AbstractParser.message("strict.no.octal"), token); 2236 } 2237 case STRING: 2238 case ESCSTRING: 2239 case DECIMAL: 2240 case HEXADECIMAL: 2241 case FLOATING: 2242 return getLiteral(); 2243 default: 2244 return getIdentifierName().setIsPropertyName(); 2245 } 2246 } 2247 2248 /** 2249 * PropertyAssignment : 2250 * PropertyName : AssignmentExpression 2251 * get PropertyName ( ) { FunctionBody } 2252 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2253 * 2254 * PropertySetParameterList : 2255 * Identifier 2256 * 2257 * PropertyName : 2258 * IdentifierName 2259 * StringLiteral 2260 * NumericLiteral 2261 * 2262 * See 11.1.5 2263 * 2264 * Parse an object literal property. 2265 * @return Property or reference node. 2266 */ 2267 private PropertyNode propertyAssignment() { 2268 // Capture firstToken. 2269 final long propertyToken = token; 2270 final int functionLine = line; 2271 2272 PropertyKey propertyName; 2273 2274 if (type == IDENT) { 2275 // Get IDENT. 2276 final String ident = (String)expectValue(IDENT); 2277 2278 if (type != COLON) { 2279 final long getSetToken = propertyToken; 2280 2281 switch (ident) { 2282 case "get": 2283 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 2284 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); 2285 2286 case "set": 2287 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 2288 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); 2289 default: 2290 break; 2291 } 2292 } 2293 2294 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 2295 } else { 2296 propertyName = propertyName(); 2297 } 2298 2299 expect(COLON); 2300 2301 defaultNames.push(propertyName); 2302 try { 2303 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2304 } finally { 2305 defaultNames.pop(); 2306 } 2307 } 2308 2309 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 2310 final PropertyKey getIdent = propertyName(); 2311 final String getterName = getIdent.getPropertyName(); 2312 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2313 expect(LPAREN); 2314 expect(RPAREN); 2315 final FunctionNode functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER, functionLine); 2316 2317 return new PropertyFunction(getIdent, functionNode); 2318 } 2319 2320 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 2321 final PropertyKey setIdent = propertyName(); 2322 final String setterName = setIdent.getPropertyName(); 2323 final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2324 expect(LPAREN); 2325 // be sloppy and allow missing setter parameter even though 2326 // spec does not permit it! 2327 final IdentNode argIdent; 2328 if (type == IDENT || isNonStrictModeIdent()) { 2329 argIdent = getIdent(); 2330 verifyStrictIdent(argIdent, "setter argument"); 2331 } else { 2332 argIdent = null; 2333 } 2334 expect(RPAREN); 2335 final List<IdentNode> parameters = new ArrayList<>(); 2336 if (argIdent != null) { 2337 parameters.add(argIdent); 2338 } 2339 final FunctionNode functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER, functionLine); 2340 2341 return new PropertyFunction(setIdent, functionNode); 2342 } 2343 2344 private static class PropertyFunction { 2345 final PropertyKey ident; 2346 final FunctionNode functionNode; 2347 2348 PropertyFunction(final PropertyKey ident, final FunctionNode function) { 2349 this.ident = ident; 2350 this.functionNode = function; 2351 } 2352 } 2353 2354 /** 2355 * LeftHandSideExpression : 2356 * NewExpression 2357 * CallExpression 2358 * 2359 * CallExpression : 2360 * MemberExpression Arguments 2361 * CallExpression Arguments 2362 * CallExpression [ Expression ] 2363 * CallExpression . IdentifierName 2364 * 2365 * See 11.2 2366 * 2367 * Parse left hand side expression. 2368 * @return Expression node. 2369 */ 2370 private Expression leftHandSideExpression() { 2371 int callLine = line; 2372 long callToken = token; 2373 2374 Expression lhs = memberExpression(); 2375 2376 if (type == LPAREN) { 2377 final List<Expression> arguments = optimizeList(argumentList()); 2378 2379 // Catch special functions. 2380 if (lhs instanceof IdentNode) { 2381 detectSpecialFunction((IdentNode)lhs); 2382 } 2383 2384 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2385 } 2386 2387 loop: 2388 while (true) { 2389 // Capture token. 2390 callLine = line; 2391 callToken = token; 2392 2393 switch (type) { 2394 case LPAREN: 2395 // Get NEW or FUNCTION arguments. 2396 final List<Expression> arguments = optimizeList(argumentList()); 2397 2398 // Create call node. 2399 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2400 2401 break; 2402 2403 case LBRACKET: 2404 next(); 2405 2406 // Get array index. 2407 final Expression rhs = expression(); 2408 2409 expect(RBRACKET); 2410 2411 // Create indexing node. 2412 lhs = new IndexNode(callToken, finish, lhs, rhs); 2413 2414 break; 2415 2416 case PERIOD: 2417 next(); 2418 2419 final IdentNode property = getIdentifierName(); 2420 2421 // Create property access node. 2422 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2423 2424 break; 2425 2426 default: 2427 break loop; 2428 } 2429 } 2430 2431 return lhs; 2432 } 2433 2434 /** 2435 * NewExpression : 2436 * MemberExpression 2437 * new NewExpression 2438 * 2439 * See 11.2 2440 * 2441 * Parse new expression. 2442 * @return Expression node. 2443 */ 2444 private Expression newExpression() { 2445 final long newToken = token; 2446 // NEW is tested in caller. 2447 next(); 2448 2449 // Get function base. 2450 final int callLine = line; 2451 final Expression constructor = memberExpression(); 2452 if (constructor == null) { 2453 return null; 2454 } 2455 // Get arguments. 2456 ArrayList<Expression> arguments; 2457 2458 // Allow for missing arguments. 2459 if (type == LPAREN) { 2460 arguments = argumentList(); 2461 } else { 2462 arguments = new ArrayList<>(); 2463 } 2464 2465 // Nashorn extension: This is to support the following interface implementation 2466 // syntax: 2467 // 2468 // var r = new java.lang.Runnable() { 2469 // run: function() { println("run"); } 2470 // }; 2471 // 2472 // The object literal following the "new Constructor()" expresssion 2473 // is passed as an additional (last) argument to the constructor. 2474 if (!env._no_syntax_extensions && type == LBRACE) { 2475 arguments.add(objectLiteral()); 2476 } 2477 2478 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 2479 2480 return new UnaryNode(newToken, callNode); 2481 } 2482 2483 /** 2484 * MemberExpression : 2485 * PrimaryExpression 2486 * FunctionExpression 2487 * MemberExpression [ Expression ] 2488 * MemberExpression . IdentifierName 2489 * new MemberExpression Arguments 2490 * 2491 * See 11.2 2492 * 2493 * Parse member expression. 2494 * @return Expression node. 2495 */ 2496 private Expression memberExpression() { 2497 // Prepare to build operation. 2498 Expression lhs; 2499 2500 switch (type) { 2501 case NEW: 2502 // Get new expression. 2503 lhs = newExpression(); 2504 break; 2505 2506 case FUNCTION: 2507 // Get function expression. 2508 lhs = functionExpression(false, false); 2509 break; 2510 2511 default: 2512 // Get primary expression. 2513 lhs = primaryExpression(); 2514 break; 2515 } 2516 2517 loop: 2518 while (true) { 2519 // Capture token. 2520 final long callToken = token; 2521 2522 switch (type) { 2523 case LBRACKET: 2524 next(); 2525 2526 // Get array index. 2527 final Expression index = expression(); 2528 2529 expect(RBRACKET); 2530 2531 // Create indexing node. 2532 lhs = new IndexNode(callToken, finish, lhs, index); 2533 2534 break; 2535 2536 case PERIOD: 2537 if (lhs == null) { 2538 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2539 } 2540 2541 next(); 2542 2543 final IdentNode property = getIdentifierName(); 2544 2545 // Create property access node. 2546 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2547 2548 break; 2549 2550 default: 2551 break loop; 2552 } 2553 } 2554 2555 return lhs; 2556 } 2557 2558 /** 2559 * Arguments : 2560 * ( ) 2561 * ( ArgumentList ) 2562 * 2563 * ArgumentList : 2564 * AssignmentExpression 2565 * ArgumentList , AssignmentExpression 2566 * 2567 * See 11.2 2568 * 2569 * Parse function call arguments. 2570 * @return Argument list. 2571 */ 2572 private ArrayList<Expression> argumentList() { 2573 // Prepare to accumulate list of arguments. 2574 final ArrayList<Expression> nodeList = new ArrayList<>(); 2575 // LPAREN tested in caller. 2576 next(); 2577 2578 // Track commas. 2579 boolean first = true; 2580 2581 while (type != RPAREN) { 2582 // Comma prior to every argument except the first. 2583 if (!first) { 2584 expect(COMMARIGHT); 2585 } else { 2586 first = false; 2587 } 2588 2589 // Get argument expression. 2590 nodeList.add(assignmentExpression(false)); 2591 } 2592 2593 expect(RPAREN); 2594 return nodeList; 2595 } 2596 2597 private static <T> List<T> optimizeList(final ArrayList<T> list) { 2598 switch(list.size()) { 2599 case 0: { 2600 return Collections.emptyList(); 2601 } 2602 case 1: { 2603 return Collections.singletonList(list.get(0)); 2604 } 2605 default: { 2606 list.trimToSize(); 2607 return list; 2608 } 2609 } 2610 } 2611 2612 /** 2613 * FunctionDeclaration : 2614 * function Identifier ( FormalParameterList? ) { FunctionBody } 2615 * 2616 * FunctionExpression : 2617 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2618 * 2619 * See 13 2620 * 2621 * Parse function declaration. 2622 * @param isStatement True if for is a statement. 2623 * 2624 * @return Expression node. 2625 */ 2626 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2627 final long functionToken = token; 2628 final int functionLine = line; 2629 // FUNCTION is tested in caller. 2630 next(); 2631 2632 IdentNode name = null; 2633 2634 if (type == IDENT || isNonStrictModeIdent()) { 2635 name = getIdent(); 2636 verifyStrictIdent(name, "function name"); 2637 } else if (isStatement) { 2638 // Nashorn extension: anonymous function statements 2639 if (env._no_syntax_extensions) { 2640 expect(IDENT); 2641 } 2642 } 2643 2644 // name is null, generate anonymous name 2645 boolean isAnonymous = false; 2646 if (name == null) { 2647 final String tmpName = getDefaultValidFunctionName(functionLine); 2648 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2649 isAnonymous = true; 2650 } 2651 2652 expect(LPAREN); 2653 final List<IdentNode> parameters = formalParameterList(); 2654 expect(RPAREN); 2655 2656 FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine); 2657 2658 if (isStatement) { 2659 if (topLevel || useBlockScope()) { 2660 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED); 2661 } else if (isStrictMode) { 2662 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2663 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2664 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2665 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2666 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2667 } 2668 if (isArguments(name)) { 2669 lc.setFlag(lc.getCurrentFunction(), FunctionNode.DEFINES_ARGUMENTS); 2670 } 2671 } 2672 2673 if (isAnonymous) { 2674 functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS); 2675 } 2676 2677 final int arity = parameters.size(); 2678 2679 final boolean strict = functionNode.isStrict(); 2680 if (arity > 1) { 2681 final HashSet<String> parametersSet = new HashSet<>(arity); 2682 2683 for (int i = arity - 1; i >= 0; i--) { 2684 final IdentNode parameter = parameters.get(i); 2685 String parameterName = parameter.getName(); 2686 2687 if (isArguments(parameterName)) { 2688 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 2689 } 2690 2691 if (parametersSet.contains(parameterName)) { 2692 // redefinition of parameter name 2693 if (strict) { 2694 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2695 } 2696 // rename in non-strict mode 2697 parameterName = functionNode.uniqueName(parameterName); 2698 final long parameterToken = parameter.getToken(); 2699 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2700 } 2701 2702 parametersSet.add(parameterName); 2703 } 2704 } else if (arity == 1) { 2705 if (isArguments(parameters.get(0))) { 2706 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 2707 } 2708 } 2709 2710 if (isStatement) { 2711 final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; 2712 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags); 2713 if (topLevel) { 2714 functionDeclarations.add(varNode); 2715 } else if (useBlockScope()) { 2716 prependStatement(varNode); // Hoist to beginning of current block 2717 } else { 2718 appendStatement(varNode); 2719 } 2720 } 2721 2722 return functionNode; 2723 } 2724 2725 private String getDefaultValidFunctionName(final int functionLine) { 2726 final String defaultFunctionName = getDefaultFunctionName(); 2727 return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2728 } 2729 2730 private static boolean isValidIdentifier(final String name) { 2731 if(name == null || name.isEmpty()) { 2732 return false; 2733 } 2734 if(!Character.isJavaIdentifierStart(name.charAt(0))) { 2735 return false; 2736 } 2737 for(int i = 1; i < name.length(); ++i) { 2738 if(!Character.isJavaIdentifierPart(name.charAt(i))) { 2739 return false; 2740 } 2741 } 2742 return true; 2743 } 2744 2745 private String getDefaultFunctionName() { 2746 if(!defaultNames.isEmpty()) { 2747 final Object nameExpr = defaultNames.peek(); 2748 if(nameExpr instanceof PropertyKey) { 2749 markDefaultNameUsed(); 2750 return ((PropertyKey)nameExpr).getPropertyName(); 2751 } else if(nameExpr instanceof AccessNode) { 2752 markDefaultNameUsed(); 2753 return ((AccessNode)nameExpr).getProperty(); 2754 } 2755 } 2756 return null; 2757 } 2758 2759 private void markDefaultNameUsed() { 2760 defaultNames.pop(); 2761 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 2762 // from. Can't be null 2763 defaultNames.push(""); 2764 } 2765 2766 /** 2767 * FormalParameterList : 2768 * Identifier 2769 * FormalParameterList , Identifier 2770 * 2771 * See 13 2772 * 2773 * Parse function parameter list. 2774 * @return List of parameter nodes. 2775 */ 2776 private List<IdentNode> formalParameterList() { 2777 return formalParameterList(RPAREN); 2778 } 2779 2780 /** 2781 * Same as the other method of the same name - except that the end 2782 * token type expected is passed as argument to this method. 2783 * 2784 * FormalParameterList : 2785 * Identifier 2786 * FormalParameterList , Identifier 2787 * 2788 * See 13 2789 * 2790 * Parse function parameter list. 2791 * @return List of parameter nodes. 2792 */ 2793 private List<IdentNode> formalParameterList(final TokenType endType) { 2794 // Prepare to gather parameters. 2795 final ArrayList<IdentNode> parameters = new ArrayList<>(); 2796 // Track commas. 2797 boolean first = true; 2798 2799 while (type != endType) { 2800 // Comma prior to every argument except the first. 2801 if (!first) { 2802 expect(COMMARIGHT); 2803 } else { 2804 first = false; 2805 } 2806 2807 // Get and add parameter. 2808 final IdentNode ident = getIdent(); 2809 2810 // ECMA 13.1 strict mode restrictions 2811 verifyStrictIdent(ident, "function parameter"); 2812 2813 parameters.add(ident); 2814 } 2815 2816 parameters.trimToSize(); 2817 return parameters; 2818 } 2819 2820 /** 2821 * FunctionBody : 2822 * SourceElements? 2823 * 2824 * See 13 2825 * 2826 * Parse function body. 2827 * @return function node (body.) 2828 */ 2829 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine) { 2830 FunctionNode functionNode = null; 2831 long lastToken = 0L; 2832 2833 final boolean parseBody; 2834 Object endParserState = null; 2835 try { 2836 // Create a new function block. 2837 functionNode = newFunctionNode(firstToken, ident, parameters, kind, functionLine); 2838 assert functionNode != null; 2839 final int functionId = functionNode.getId(); 2840 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 2841 // Nashorn extension: expression closures 2842 if (!env._no_syntax_extensions && type != LBRACE) { 2843 /* 2844 * Example: 2845 * 2846 * function square(x) x * x; 2847 * print(square(3)); 2848 */ 2849 2850 // just expression as function body 2851 final Expression expr = assignmentExpression(true); 2852 lastToken = previousToken; 2853 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2854 // EOL uses length field to store the line number 2855 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 2856 // Only create the return node if we aren't skipping nested functions. Note that we aren't 2857 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 2858 // they don't end with a single well known token, so it'd be very hard to get correctly (see 2859 // the note below for reasoning on skipping happening before instead of after RBRACE for 2860 // details). 2861 if (parseBody) { 2862 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 2863 appendStatement(returnNode); 2864 } 2865 functionNode.setFinish(lastFinish); 2866 } else { 2867 expectDontAdvance(LBRACE); 2868 if (parseBody || !skipFunctionBody(functionNode)) { 2869 next(); 2870 // Gather the function elements. 2871 final List<Statement> prevFunctionDecls = functionDeclarations; 2872 functionDeclarations = new ArrayList<>(); 2873 try { 2874 sourceElements(false); 2875 addFunctionDeclarations(functionNode); 2876 } finally { 2877 functionDeclarations = prevFunctionDecls; 2878 } 2879 2880 lastToken = token; 2881 if (parseBody) { 2882 // Since the lexer can read ahead and lexify some number of tokens in advance and have 2883 // them buffered in the TokenStream, we need to produce a lexer state as it was just 2884 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 2885 // ahead) state. 2886 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 2887 2888 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 2889 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 2890 // state after it. The reason is that RBRACE is a well-known token that we can expect and 2891 // will never involve us getting into a weird lexer state, and as such is a great reparse 2892 // point. Typical example of a weird lexer state after RBRACE would be: 2893 // function this_is_skipped() { ... } "use strict"; 2894 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 2895 // of compensating for the possibility of a string literal (or similar) after RBRACE, 2896 // we'll rather just restart parsing from this well-known, friendly token instead. 2897 } 2898 } 2899 expect(RBRACE); 2900 functionNode.setFinish(finish); 2901 } 2902 } finally { 2903 functionNode = restoreFunctionNode(functionNode, lastToken); 2904 } 2905 2906 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 2907 2908 if (parseBody) { 2909 functionNode = functionNode.setEndParserState(lc, endParserState); 2910 } else if (functionNode.getBody().getStatementCount() > 0){ 2911 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 2912 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 2913 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 2914 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 2915 // nested bodies early if we were supposed to skip 'em. 2916 functionNode = functionNode.setBody(null, functionNode.getBody().setStatements(null, 2917 Collections.<Statement>emptyList())); 2918 } 2919 2920 if (reparsedFunction != null) { 2921 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 2922 // eagerly parsed the code. We're doing it because some flags would be set based on the 2923 // content of the function, or even content of its nested functions, most of which are normally 2924 // skipped during an on-demand compilation. 2925 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2926 if (data != null) { 2927 // Data can be null if when we originally parsed the file, we removed the function declaration 2928 // as it was dead code. 2929 functionNode = functionNode.setFlags(lc, data.getFunctionFlags()); 2930 // This compensates for missing markEval() in case the function contains an inner function 2931 // that contains eval(), that now we didn't discover since we skipped the inner function. 2932 if (functionNode.hasNestedEval()) { 2933 assert functionNode.hasScopeBlock(); 2934 functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(null)); 2935 } 2936 } 2937 } 2938 printAST(functionNode); 2939 return functionNode; 2940 } 2941 2942 private boolean skipFunctionBody(final FunctionNode functionNode) { 2943 if (reparsedFunction == null) { 2944 // Not reparsing, so don't skip any function body. 2945 return false; 2946 } 2947 // Skip to the RBRACE of this function, and continue parsing from there. 2948 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2949 if (data == null) { 2950 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 2951 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 2952 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 2953 return false; 2954 } 2955 final ParserState parserState = (ParserState)data.getEndParserState(); 2956 assert parserState != null; 2957 2958 stream.reset(); 2959 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions); 2960 line = parserState.line; 2961 linePosition = parserState.linePosition; 2962 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 2963 // the RBRACE. 2964 type = SEMICOLON; 2965 k = -1; 2966 next(); 2967 2968 return true; 2969 } 2970 2971 /** 2972 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 2973 * for resuming parsing after skipping a function body. 2974 */ 2975 private static class ParserState implements Serializable { 2976 private final int position; 2977 private final int line; 2978 private final int linePosition; 2979 2980 private static final long serialVersionUID = -2382565130754093694L; 2981 2982 ParserState(final int position, final int line, final int linePosition) { 2983 this.position = position; 2984 this.line = line; 2985 this.linePosition = linePosition; 2986 } 2987 2988 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) { 2989 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true); 2990 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 2991 return newLexer; 2992 } 2993 } 2994 2995 private void printAST(final FunctionNode functionNode) { 2996 if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { 2997 env.getErr().println(new ASTWriter(functionNode)); 2998 } 2999 3000 if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { 3001 env.getErr().println(new PrintVisitor(functionNode, true, false)); 3002 } 3003 } 3004 3005 private void addFunctionDeclarations(final FunctionNode functionNode) { 3006 VarNode lastDecl = null; 3007 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 3008 Statement decl = functionDeclarations.get(i); 3009 if (lastDecl == null && decl instanceof VarNode) { 3010 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 3011 lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS); 3012 } 3013 prependStatement(decl); 3014 } 3015 } 3016 3017 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 3018 if (earlyError) { 3019 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 3020 } 3021 final ArrayList<Expression> args = new ArrayList<>(); 3022 args.add(lhs); 3023 if (rhs == null) { 3024 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 3025 } else { 3026 args.add(rhs); 3027 } 3028 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 3029 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 3030 } 3031 3032 /* 3033 * parse LHS [a, b, ..., c]. 3034 * 3035 * JavaScript 1.8. 3036 */ 3037 //private Node destructureExpression() { 3038 // return null; 3039 //} 3040 3041 /** 3042 * PostfixExpression : 3043 * LeftHandSideExpression 3044 * LeftHandSideExpression ++ // [no LineTerminator here] 3045 * LeftHandSideExpression -- // [no LineTerminator here] 3046 * 3047 * See 11.3 3048 * 3049 * UnaryExpression : 3050 * PostfixExpression 3051 * delete UnaryExpression 3052 * Node UnaryExpression 3053 * typeof UnaryExpression 3054 * ++ UnaryExpression 3055 * -- UnaryExpression 3056 * + UnaryExpression 3057 * - UnaryExpression 3058 * ~ UnaryExpression 3059 * ! UnaryExpression 3060 * 3061 * See 11.4 3062 * 3063 * Parse unary expression. 3064 * @return Expression node. 3065 */ 3066 private Expression unaryExpression() { 3067 final int unaryLine = line; 3068 final long unaryToken = token; 3069 3070 switch (type) { 3071 case DELETE: { 3072 next(); 3073 final Expression expr = unaryExpression(); 3074 if (expr instanceof BaseNode || expr instanceof IdentNode) { 3075 return new UnaryNode(unaryToken, expr); 3076 } 3077 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 3078 return LiteralNode.newInstance(unaryToken, finish, true); 3079 } 3080 case VOID: 3081 case TYPEOF: 3082 case ADD: 3083 case SUB: 3084 case BIT_NOT: 3085 case NOT: 3086 next(); 3087 final Expression expr = unaryExpression(); 3088 return new UnaryNode(unaryToken, expr); 3089 3090 case INCPREFIX: 3091 case DECPREFIX: 3092 final TokenType opType = type; 3093 next(); 3094 3095 final Expression lhs = leftHandSideExpression(); 3096 // ++, -- without operand.. 3097 if (lhs == null) { 3098 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3099 } 3100 3101 if (!(lhs instanceof AccessNode || 3102 lhs instanceof IndexNode || 3103 lhs instanceof IdentNode)) { 3104 return referenceError(lhs, null, env._early_lvalue_error); 3105 } 3106 3107 if (lhs instanceof IdentNode) { 3108 if (!checkIdentLValue((IdentNode)lhs)) { 3109 return referenceError(lhs, null, false); 3110 } 3111 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3112 } 3113 3114 return incDecExpression(unaryToken, opType, lhs, false); 3115 3116 default: 3117 break; 3118 } 3119 3120 Expression expression = leftHandSideExpression(); 3121 3122 if (last != EOL) { 3123 switch (type) { 3124 case INCPREFIX: 3125 case DECPREFIX: 3126 final TokenType opType = type; 3127 final Expression lhs = expression; 3128 // ++, -- without operand.. 3129 if (lhs == null) { 3130 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3131 } 3132 3133 if (!(lhs instanceof AccessNode || 3134 lhs instanceof IndexNode || 3135 lhs instanceof IdentNode)) { 3136 next(); 3137 return referenceError(lhs, null, env._early_lvalue_error); 3138 } 3139 if (lhs instanceof IdentNode) { 3140 if (!checkIdentLValue((IdentNode)lhs)) { 3141 next(); 3142 return referenceError(lhs, null, false); 3143 } 3144 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3145 } 3146 expression = incDecExpression(token, type, expression, true); 3147 next(); 3148 break; 3149 default: 3150 break; 3151 } 3152 } 3153 3154 if (expression == null) { 3155 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3156 } 3157 3158 return expression; 3159 } 3160 3161 /** 3162 * MultiplicativeExpression : 3163 * UnaryExpression 3164 * MultiplicativeExpression * UnaryExpression 3165 * MultiplicativeExpression / UnaryExpression 3166 * MultiplicativeExpression % UnaryExpression 3167 * 3168 * See 11.5 3169 * 3170 * AdditiveExpression : 3171 * MultiplicativeExpression 3172 * AdditiveExpression + MultiplicativeExpression 3173 * AdditiveExpression - MultiplicativeExpression 3174 * 3175 * See 11.6 3176 * 3177 * ShiftExpression : 3178 * AdditiveExpression 3179 * ShiftExpression << AdditiveExpression 3180 * ShiftExpression >> AdditiveExpression 3181 * ShiftExpression >>> AdditiveExpression 3182 * 3183 * See 11.7 3184 * 3185 * RelationalExpression : 3186 * ShiftExpression 3187 * RelationalExpression < ShiftExpression 3188 * RelationalExpression > ShiftExpression 3189 * RelationalExpression <= ShiftExpression 3190 * RelationalExpression >= ShiftExpression 3191 * RelationalExpression instanceof ShiftExpression 3192 * RelationalExpression in ShiftExpression // if !noIf 3193 * 3194 * See 11.8 3195 * 3196 * RelationalExpression 3197 * EqualityExpression == RelationalExpression 3198 * EqualityExpression != RelationalExpression 3199 * EqualityExpression === RelationalExpression 3200 * EqualityExpression !== RelationalExpression 3201 * 3202 * See 11.9 3203 * 3204 * BitwiseANDExpression : 3205 * EqualityExpression 3206 * BitwiseANDExpression & EqualityExpression 3207 * 3208 * BitwiseXORExpression : 3209 * BitwiseANDExpression 3210 * BitwiseXORExpression ^ BitwiseANDExpression 3211 * 3212 * BitwiseORExpression : 3213 * BitwiseXORExpression 3214 * BitwiseORExpression | BitwiseXORExpression 3215 * 3216 * See 11.10 3217 * 3218 * LogicalANDExpression : 3219 * BitwiseORExpression 3220 * LogicalANDExpression && BitwiseORExpression 3221 * 3222 * LogicalORExpression : 3223 * LogicalANDExpression 3224 * LogicalORExpression || LogicalANDExpression 3225 * 3226 * See 11.11 3227 * 3228 * ConditionalExpression : 3229 * LogicalORExpression 3230 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 3231 * 3232 * See 11.12 3233 * 3234 * AssignmentExpression : 3235 * ConditionalExpression 3236 * LeftHandSideExpression AssignmentOperator AssignmentExpression 3237 * 3238 * AssignmentOperator : 3239 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 3240 * 3241 * See 11.13 3242 * 3243 * Expression : 3244 * AssignmentExpression 3245 * Expression , AssignmentExpression 3246 * 3247 * See 11.14 3248 * 3249 * Parse expression. 3250 * @return Expression node. 3251 */ 3252 private Expression expression() { 3253 // TODO - Destructuring array. 3254 // Include commas in expression parsing. 3255 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 3256 } 3257 3258 private JoinPredecessorExpression joinPredecessorExpression() { 3259 return new JoinPredecessorExpression(expression()); 3260 } 3261 3262 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 3263 // Get the precedence of the next operator. 3264 int precedence = type.getPrecedence(); 3265 Expression lhs = exprLhs; 3266 3267 // While greater precedence. 3268 while (type.isOperator(noIn) && precedence >= minPrecedence) { 3269 // Capture the operator token. 3270 final long op = token; 3271 3272 if (type == TERNARY) { 3273 // Skip operator. 3274 next(); 3275 3276 // Pass expression. Middle expression of a conditional expression can be a "in" 3277 // expression - even in the contexts where "in" is not permitted. 3278 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 3279 3280 expect(COLON); 3281 3282 // Fail expression. 3283 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3284 3285 // Build up node. 3286 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 3287 } else { 3288 // Skip operator. 3289 next(); 3290 3291 // Get the next primary expression. 3292 Expression rhs; 3293 final boolean isAssign = Token.descType(op) == ASSIGN; 3294 if(isAssign) { 3295 defaultNames.push(lhs); 3296 } 3297 try { 3298 rhs = unaryExpression(); 3299 // Get precedence of next operator. 3300 int nextPrecedence = type.getPrecedence(); 3301 3302 // Subtask greater precedence. 3303 while (type.isOperator(noIn) && 3304 (nextPrecedence > precedence || 3305 nextPrecedence == precedence && !type.isLeftAssociative())) { 3306 rhs = expression(rhs, nextPrecedence, noIn); 3307 nextPrecedence = type.getPrecedence(); 3308 } 3309 } finally { 3310 if(isAssign) { 3311 defaultNames.pop(); 3312 } 3313 } 3314 lhs = verifyAssignment(op, lhs, rhs); 3315 } 3316 3317 precedence = type.getPrecedence(); 3318 } 3319 3320 return lhs; 3321 } 3322 3323 private Expression assignmentExpression(final boolean noIn) { 3324 // TODO - Handle decompose. 3325 // Exclude commas in expression parsing. 3326 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3327 } 3328 3329 /** 3330 * Parse an end of line. 3331 */ 3332 private void endOfLine() { 3333 switch (type) { 3334 case SEMICOLON: 3335 case EOL: 3336 next(); 3337 break; 3338 case RPAREN: 3339 case RBRACKET: 3340 case RBRACE: 3341 case EOF: 3342 break; 3343 default: 3344 if (last != EOL) { 3345 expect(SEMICOLON); 3346 } 3347 break; 3348 } 3349 } 3350 3351 @Override 3352 public String toString() { 3353 return "'JavaScript Parsing'"; 3354 } 3355 3356 private static void markEval(final LexicalContext lc) { 3357 final Iterator<FunctionNode> iter = lc.getFunctions(); 3358 boolean flaggedCurrentFn = false; 3359 while (iter.hasNext()) { 3360 final FunctionNode fn = iter.next(); 3361 if (!flaggedCurrentFn) { 3362 lc.setFlag(fn, FunctionNode.HAS_EVAL); 3363 flaggedCurrentFn = true; 3364 } else { 3365 lc.setFlag(fn, FunctionNode.HAS_NESTED_EVAL); 3366 } 3367 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 3368 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 3369 // this method when the parser skips a nested function. 3370 lc.setBlockNeedsScope(lc.getFunctionBody(fn)); 3371 } 3372 } 3373 3374 private void prependStatement(final Statement statement) { 3375 lc.prependStatement(statement); 3376 } 3377 3378 private void appendStatement(final Statement statement) { 3379 lc.appendStatement(statement); 3380 } 3381 }