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