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