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