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