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