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