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