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.ARROW; 32 import static jdk.nashorn.internal.parser.TokenType.ASSIGN; 33 import static jdk.nashorn.internal.parser.TokenType.CASE; 34 import static jdk.nashorn.internal.parser.TokenType.CATCH; 35 import static jdk.nashorn.internal.parser.TokenType.CLASS; 36 import static jdk.nashorn.internal.parser.TokenType.COLON; 37 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; 38 import static jdk.nashorn.internal.parser.TokenType.COMMENT; 39 import static jdk.nashorn.internal.parser.TokenType.CONST; 40 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; 41 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; 42 import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS; 43 import static jdk.nashorn.internal.parser.TokenType.ELSE; 44 import static jdk.nashorn.internal.parser.TokenType.EOF; 45 import static jdk.nashorn.internal.parser.TokenType.EOL; 46 import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT; 47 import static jdk.nashorn.internal.parser.TokenType.ESCSTRING; 48 import static jdk.nashorn.internal.parser.TokenType.EXPORT; 49 import static jdk.nashorn.internal.parser.TokenType.EXTENDS; 50 import static jdk.nashorn.internal.parser.TokenType.FINALLY; 51 import static jdk.nashorn.internal.parser.TokenType.FUNCTION; 52 import static jdk.nashorn.internal.parser.TokenType.IDENT; 53 import static jdk.nashorn.internal.parser.TokenType.IF; 54 import static jdk.nashorn.internal.parser.TokenType.IMPORT; 55 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; 56 import static jdk.nashorn.internal.parser.TokenType.LBRACE; 57 import static jdk.nashorn.internal.parser.TokenType.LBRACKET; 58 import static jdk.nashorn.internal.parser.TokenType.LET; 59 import static jdk.nashorn.internal.parser.TokenType.LPAREN; 60 import static jdk.nashorn.internal.parser.TokenType.MUL; 61 import static jdk.nashorn.internal.parser.TokenType.PERIOD; 62 import static jdk.nashorn.internal.parser.TokenType.RBRACE; 63 import static jdk.nashorn.internal.parser.TokenType.RBRACKET; 64 import static jdk.nashorn.internal.parser.TokenType.RPAREN; 65 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; 66 import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY; 67 import static jdk.nashorn.internal.parser.TokenType.STATIC; 68 import static jdk.nashorn.internal.parser.TokenType.STRING; 69 import static jdk.nashorn.internal.parser.TokenType.SUPER; 70 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE; 71 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD; 72 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE; 73 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL; 74 import static jdk.nashorn.internal.parser.TokenType.TERNARY; 75 import static jdk.nashorn.internal.parser.TokenType.VAR; 76 import static jdk.nashorn.internal.parser.TokenType.VOID; 77 import static jdk.nashorn.internal.parser.TokenType.WHILE; 78 import static jdk.nashorn.internal.parser.TokenType.YIELD; 79 import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR; 80 81 import java.io.Serializable; 82 import java.util.ArrayDeque; 83 import java.util.ArrayList; 84 import java.util.Collections; 85 import java.util.Deque; 86 import java.util.HashMap; 87 import java.util.HashSet; 88 import java.util.Iterator; 89 import java.util.List; 90 import java.util.Map; 91 import java.util.Objects; 92 import java.util.function.Consumer; 93 import jdk.nashorn.internal.codegen.CompilerConstants; 94 import jdk.nashorn.internal.codegen.Namespace; 95 import jdk.nashorn.internal.ir.AccessNode; 96 import jdk.nashorn.internal.ir.BaseNode; 97 import jdk.nashorn.internal.ir.BinaryNode; 98 import jdk.nashorn.internal.ir.Block; 99 import jdk.nashorn.internal.ir.BlockStatement; 100 import jdk.nashorn.internal.ir.BreakNode; 101 import jdk.nashorn.internal.ir.CallNode; 102 import jdk.nashorn.internal.ir.CaseNode; 103 import jdk.nashorn.internal.ir.CatchNode; 104 import jdk.nashorn.internal.ir.ClassNode; 105 import jdk.nashorn.internal.ir.ContinueNode; 106 import jdk.nashorn.internal.ir.DebuggerNode; 107 import jdk.nashorn.internal.ir.EmptyNode; 108 import jdk.nashorn.internal.ir.ErrorNode; 109 import jdk.nashorn.internal.ir.Expression; 110 import jdk.nashorn.internal.ir.ExpressionList; 111 import jdk.nashorn.internal.ir.ExpressionStatement; 112 import jdk.nashorn.internal.ir.ForNode; 113 import jdk.nashorn.internal.ir.FunctionNode; 114 import jdk.nashorn.internal.ir.IdentNode; 115 import jdk.nashorn.internal.ir.IfNode; 116 import jdk.nashorn.internal.ir.IndexNode; 117 import jdk.nashorn.internal.ir.JoinPredecessorExpression; 118 import jdk.nashorn.internal.ir.LabelNode; 119 import jdk.nashorn.internal.ir.LexicalContext; 120 import jdk.nashorn.internal.ir.LiteralNode; 121 import jdk.nashorn.internal.ir.Module; 122 import jdk.nashorn.internal.ir.Node; 123 import jdk.nashorn.internal.ir.ObjectNode; 124 import jdk.nashorn.internal.ir.PropertyKey; 125 import jdk.nashorn.internal.ir.PropertyNode; 126 import jdk.nashorn.internal.ir.ReturnNode; 127 import jdk.nashorn.internal.ir.RuntimeNode; 128 import jdk.nashorn.internal.ir.Statement; 129 import jdk.nashorn.internal.ir.SwitchNode; 130 import jdk.nashorn.internal.ir.TernaryNode; 131 import jdk.nashorn.internal.ir.ThrowNode; 132 import jdk.nashorn.internal.ir.TryNode; 133 import jdk.nashorn.internal.ir.UnaryNode; 134 import jdk.nashorn.internal.ir.VarNode; 135 import jdk.nashorn.internal.ir.WhileNode; 136 import jdk.nashorn.internal.ir.WithNode; 137 import jdk.nashorn.internal.ir.debug.ASTWriter; 138 import jdk.nashorn.internal.ir.debug.PrintVisitor; 139 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 140 import jdk.nashorn.internal.runtime.Context; 141 import jdk.nashorn.internal.runtime.ErrorManager; 142 import jdk.nashorn.internal.runtime.JSErrorType; 143 import jdk.nashorn.internal.runtime.ParserException; 144 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 145 import jdk.nashorn.internal.runtime.ScriptEnvironment; 146 import jdk.nashorn.internal.runtime.ScriptingFunctions; 147 import jdk.nashorn.internal.runtime.Source; 148 import jdk.nashorn.internal.runtime.Timing; 149 import jdk.nashorn.internal.runtime.linker.NameCodec; 150 import jdk.nashorn.internal.runtime.logging.DebugLogger; 151 import jdk.nashorn.internal.runtime.logging.Loggable; 152 import jdk.nashorn.internal.runtime.logging.Logger; 153 154 /** 155 * Builds the IR. 156 */ 157 @Logger(name="parser") 158 public class Parser extends AbstractParser implements Loggable { 159 private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName(); 160 161 /** Current env. */ 162 private final ScriptEnvironment env; 163 164 /** Is scripting mode. */ 165 private final boolean scripting; 166 167 private List<Statement> functionDeclarations; 168 169 private final ParserContext lc; 170 private final Deque<Object> defaultNames; 171 172 /** Namespace for function names where not explicitly given */ 173 private final Namespace namespace; 174 175 private final DebugLogger log; 176 177 /** to receive line information from Lexer when scanning multine literals. */ 178 protected final Lexer.LineInfoReceiver lineInfoReceiver; 179 180 private RecompilableScriptFunctionData reparsedFunction; 181 182 /** 183 * Constructor 184 * 185 * @param env script environment 186 * @param source source to parse 187 * @param errors error manager 188 */ 189 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) { 190 this(env, source, errors, env._strict, null); 191 } 192 193 /** 194 * Constructor 195 * 196 * @param env script environment 197 * @param source source to parse 198 * @param errors error manager 199 * @param strict strict 200 * @param log debug logger if one is needed 201 */ 202 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) { 203 this(env, source, errors, strict, 0, log); 204 } 205 206 /** 207 * Construct a parser. 208 * 209 * @param env script environment 210 * @param source source to parse 211 * @param errors error manager 212 * @param strict parser created with strict mode enabled. 213 * @param lineOffset line offset to start counting lines from 214 * @param log debug logger if one is needed 215 */ 216 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { 217 super(source, errors, strict, lineOffset); 218 this.lc = new ParserContext(); 219 this.defaultNames = new ArrayDeque<>(); 220 this.env = env; 221 this.namespace = new Namespace(env.getNamespace()); 222 this.scripting = env._scripting; 223 if (this.scripting) { 224 this.lineInfoReceiver = new Lexer.LineInfoReceiver() { 225 @Override 226 public void lineInfo(final int receiverLine, final int receiverLinePosition) { 227 // update the parser maintained line information 228 Parser.this.line = receiverLine; 229 Parser.this.linePosition = receiverLinePosition; 230 } 231 }; 232 } else { 233 // non-scripting mode script can't have multi-line literals 234 this.lineInfoReceiver = null; 235 } 236 237 this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; 238 } 239 240 @Override 241 public DebugLogger getLogger() { 242 return log; 243 } 244 245 @Override 246 public DebugLogger initLogger(final Context context) { 247 return context.getLogger(this.getClass()); 248 } 249 250 /** 251 * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can 252 * preserve their already assigned name, as that name doesn't appear in their source text. 253 * @param name the name for the first parsed function. 254 */ 255 public void setFunctionName(final String name) { 256 defaultNames.push(createIdentNode(0, 0, name)); 257 } 258 259 /** 260 * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this 261 * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation). 262 * This will trigger various special behaviors, such as skipping nested function bodies. 263 * @param reparsedFunction the function being reparsed. 264 */ 265 public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) { 266 this.reparsedFunction = reparsedFunction; 267 } 268 269 /** 270 * Execute parse and return the resulting function node. 271 * Errors will be thrown and the error manager will contain information 272 * if parsing should fail 273 * 274 * This is the default parse call, which will name the function node 275 * {code :program} {@link CompilerConstants#PROGRAM} 276 * 277 * @return function node resulting from successful parse 278 */ 279 public FunctionNode parse() { 280 return parse(PROGRAM.symbolName(), 0, source.getLength(), false); 281 } 282 283 /** 284 * Set up first token. Skips opening EOL. 285 */ 286 private void scanFirstToken() { 287 k = -1; 288 next(); 289 } 290 291 /** 292 * Execute parse and return the resulting function node. 293 * Errors will be thrown and the error manager will contain information 294 * if parsing should fail 295 * 296 * This should be used to create one and only one function node 297 * 298 * @param scriptName name for the script, given to the parsed FunctionNode 299 * @param startPos start position in source 300 * @param len length of parse 301 * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by 302 * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a 303 * property getter or setter in an object literal. 304 * 305 * @return function node resulting from successful parse 306 */ 307 public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) { 308 final boolean isTimingEnabled = env.isTimingEnabled(); 309 final long t0 = isTimingEnabled ? System.nanoTime() : 0L; 310 log.info(this, " begin for '", scriptName, "'"); 311 312 try { 313 stream = new TokenStream(); 314 lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); 315 lexer.line = lexer.pendingLine = lineOffset + 1; 316 line = lineOffset; 317 318 scanFirstToken(); 319 // Begin parse. 320 return program(scriptName, allowPropertyFunction); 321 } catch (final Exception e) { 322 handleParseException(e); 323 324 return null; 325 } finally { 326 final String end = this + " end '" + scriptName + "'"; 327 if (isTimingEnabled) { 328 env._timing.accumulateTime(toString(), System.nanoTime() - t0); 329 log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms"); 330 } else { 331 log.info(end); 332 } 333 } 334 } 335 336 /** 337 * Parse and return the resulting module. 338 * Errors will be thrown and the error manager will contain information 339 * if parsing should fail 340 * 341 * @param moduleName name for the module, given to the parsed FunctionNode 342 * @param startPos start position in source 343 * @param len length of parse 344 * 345 * @return function node resulting from successful parse 346 */ 347 public FunctionNode parseModule(final String moduleName, final int startPos, final int len) { 348 try { 349 stream = new TokenStream(); 350 lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); 351 lexer.line = lexer.pendingLine = lineOffset + 1; 352 line = lineOffset; 353 354 scanFirstToken(); 355 // Begin parse. 356 return module(moduleName); 357 } catch (final Exception e) { 358 handleParseException(e); 359 360 return null; 361 } 362 } 363 364 /** 365 * Entry point for parsing a module. 366 * 367 * @param moduleName the module name 368 * @return the parsed module 369 */ 370 public FunctionNode parseModule(final String moduleName) { 371 return parseModule(moduleName, 0, source.getLength()); 372 } 373 374 /** 375 * Parse and return the list of function parameter list. A comma 376 * separated list of function parameter identifiers is expected to be parsed. 377 * Errors will be thrown and the error manager will contain information 378 * if parsing should fail. This method is used to check if parameter Strings 379 * passed to "Function" constructor is a valid or not. 380 * 381 * @return the list of IdentNodes representing the formal parameter list 382 */ 383 public List<IdentNode> parseFormalParameterList() { 384 try { 385 stream = new TokenStream(); 386 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); 387 388 scanFirstToken(); 389 390 return formalParameterList(TokenType.EOF, false); 391 } catch (final Exception e) { 392 handleParseException(e); 393 return null; 394 } 395 } 396 397 /** 398 * Execute parse and return the resulting function node. 399 * Errors will be thrown and the error manager will contain information 400 * if parsing should fail. This method is used to check if code String 401 * passed to "Function" constructor is a valid function body or not. 402 * 403 * @return function node resulting from successful parse 404 */ 405 public FunctionNode parseFunctionBody() { 406 try { 407 stream = new TokenStream(); 408 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); 409 final int functionLine = line; 410 411 scanFirstToken(); 412 413 // Make a fake token for the function. 414 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 415 // Set up the function to append elements. 416 417 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()); 418 final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList()); 419 lc.push(function); 420 421 final ParserContextBlockNode body = newBlock(); 422 423 functionDeclarations = new ArrayList<>(); 424 sourceElements(false); 425 addFunctionDeclarations(function); 426 functionDeclarations = null; 427 428 restoreBlock(body); 429 body.setFlag(Block.NEEDS_SCOPE); 430 431 final Block functionBody = new Block(functionToken, source.getLength() - 1, 432 body.getFlags() | Block.IS_SYNTHETIC, body.getStatements()); 433 lc.pop(function); 434 435 expect(EOF); 436 437 final FunctionNode functionNode = createFunctionNode( 438 function, 439 functionToken, 440 ident, 441 Collections.<IdentNode>emptyList(), 442 FunctionNode.Kind.NORMAL, 443 functionLine, 444 functionBody); 445 printAST(functionNode); 446 return functionNode; 447 } catch (final Exception e) { 448 handleParseException(e); 449 return null; 450 } 451 } 452 453 private void handleParseException(final Exception e) { 454 // Extract message from exception. The message will be in error 455 // message format. 456 String message = e.getMessage(); 457 458 // If empty message. 459 if (message == null) { 460 message = e.toString(); 461 } 462 463 // Issue message. 464 if (e instanceof ParserException) { 465 errors.error((ParserException)e); 466 } else { 467 errors.error(message); 468 } 469 470 if (env._dump_on_error) { 471 e.printStackTrace(env.getErr()); 472 } 473 } 474 475 /** 476 * Skip to a good parsing recovery point. 477 */ 478 private void recover(final Exception e) { 479 if (e != null) { 480 // Extract message from exception. The message will be in error 481 // message format. 482 String message = e.getMessage(); 483 484 // If empty message. 485 if (message == null) { 486 message = e.toString(); 487 } 488 489 // Issue message. 490 if (e instanceof ParserException) { 491 errors.error((ParserException)e); 492 } else { 493 errors.error(message); 494 } 495 496 if (env._dump_on_error) { 497 e.printStackTrace(env.getErr()); 498 } 499 } 500 501 // Skip to a recovery point. 502 loop: 503 while (true) { 504 switch (type) { 505 case EOF: 506 // Can not go any further. 507 break loop; 508 case EOL: 509 case SEMICOLON: 510 case RBRACE: 511 // Good recovery points. 512 next(); 513 break loop; 514 default: 515 // So we can recover after EOL. 516 nextOrEOL(); 517 break; 518 } 519 } 520 } 521 522 /** 523 * Set up a new block. 524 * 525 * @return New block. 526 */ 527 private ParserContextBlockNode newBlock() { 528 return lc.push(new ParserContextBlockNode(token)); 529 } 530 531 private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) { 532 // Build function name. 533 final StringBuilder sb = new StringBuilder(); 534 535 final ParserContextFunctionNode parentFunction = lc.getCurrentFunction(); 536 if (parentFunction != null && !parentFunction.isProgram()) { 537 sb.append(parentFunction.getName()).append('$'); 538 } 539 540 assert ident.getName() != null; 541 sb.append(ident.getName()); 542 543 final String name = namespace.uniqueName(sb.toString()); 544 assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name; 545 546 int flags = 0; 547 if (isStrictMode) { 548 flags |= FunctionNode.IS_STRICT; 549 } 550 if (parentFunction == null) { 551 flags |= FunctionNode.IS_PROGRAM; 552 } 553 554 final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters); 555 functionNode.setFlag(flags); 556 return functionNode; 557 } 558 559 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) { 560 // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody(); 561 // Start new block. 562 final FunctionNode functionNode = 563 new FunctionNode( 564 source, 565 functionLine, 566 body.getToken(), 567 Token.descPosition(body.getToken()), 568 startToken, 569 function.getLastToken(), 570 namespace, 571 ident, 572 function.getName(), 573 parameters, 574 kind, 575 function.getFlags(), 576 body, 577 function.getEndParserState(), 578 function.getModule(), 579 function.getDebugFlags()); 580 581 printAST(functionNode); 582 583 return functionNode; 584 } 585 586 /** 587 * Restore the current block. 588 */ 589 private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) { 590 return lc.pop(block); 591 } 592 593 /** 594 * Get the statements in a block. 595 * @return Block statements. 596 */ 597 private Block getBlock(final boolean needsBraces) { 598 final long blockToken = token; 599 final ParserContextBlockNode newBlock = newBlock(); 600 try { 601 // Block opening brace. 602 if (needsBraces) { 603 expect(LBRACE); 604 } 605 // Accumulate block statements. 606 statementList(); 607 608 } finally { 609 restoreBlock(newBlock); 610 } 611 612 // Block closing brace. 613 if (needsBraces) { 614 expect(RBRACE); 615 } 616 617 final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC); 618 return new Block(blockToken, finish, flags, newBlock.getStatements()); 619 } 620 621 /** 622 * Get the statements in a case clause. 623 */ 624 private List<Statement> caseStatementList() { 625 final ParserContextBlockNode newBlock = newBlock(); 626 try { 627 statementList(); 628 } finally { 629 restoreBlock(newBlock); 630 } 631 return newBlock.getStatements(); 632 } 633 634 /** 635 * Get all the statements generated by a single statement. 636 * @return Statements. 637 */ 638 private Block getStatement() { 639 return getStatement(false); 640 } 641 642 private Block getStatement(boolean labelledStatement) { 643 if (type == LBRACE) { 644 return getBlock(true); 645 } 646 // Set up new block. Captures first token. 647 final ParserContextBlockNode newBlock = newBlock(); 648 try { 649 statement(false, false, true, labelledStatement); 650 } finally { 651 restoreBlock(newBlock); 652 } 653 return new Block(newBlock.getToken(), finish, newBlock.getFlags() | Block.IS_SYNTHETIC, newBlock.getStatements()); 654 } 655 656 /** 657 * Detect calls to special functions. 658 * @param ident Called function. 659 */ 660 private void detectSpecialFunction(final IdentNode ident) { 661 final String name = ident.getName(); 662 663 if (EVAL.symbolName().equals(name)) { 664 markEval(lc); 665 } else if (SUPER.getName().equals(name)) { 666 assert ident.isDirectSuper(); 667 markSuperCall(lc); 668 } 669 } 670 671 /** 672 * Detect use of special properties. 673 * @param ident Referenced property. 674 */ 675 private void detectSpecialProperty(final IdentNode ident) { 676 if (isArguments(ident)) { 677 // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); } 678 getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS); 679 } 680 } 681 682 private boolean useBlockScope() { 683 return env._es6; 684 } 685 686 private boolean isES6() { 687 return env._es6; 688 } 689 690 private static boolean isArguments(final String name) { 691 return ARGUMENTS_NAME.equals(name); 692 } 693 694 static boolean isArguments(final IdentNode ident) { 695 return isArguments(ident.getName()); 696 } 697 698 /** 699 * Tells whether a IdentNode can be used as L-value of an assignment 700 * 701 * @param ident IdentNode to be checked 702 * @return whether the ident can be used as L-value 703 */ 704 private static boolean checkIdentLValue(final IdentNode ident) { 705 return ident.tokenType().getKind() != TokenKind.KEYWORD; 706 } 707 708 /** 709 * Verify an assignment expression. 710 * @param op Operation token. 711 * @param lhs Left hand side expression. 712 * @param rhs Right hand side expression. 713 * @return Verified expression. 714 */ 715 private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) { 716 final TokenType opType = Token.descType(op); 717 718 switch (opType) { 719 case ASSIGN: 720 case ASSIGN_ADD: 721 case ASSIGN_BIT_AND: 722 case ASSIGN_BIT_OR: 723 case ASSIGN_BIT_XOR: 724 case ASSIGN_DIV: 725 case ASSIGN_MOD: 726 case ASSIGN_MUL: 727 case ASSIGN_SAR: 728 case ASSIGN_SHL: 729 case ASSIGN_SHR: 730 case ASSIGN_SUB: 731 if (lhs instanceof IdentNode) { 732 if (!checkIdentLValue((IdentNode)lhs)) { 733 return referenceError(lhs, rhs, false); 734 } 735 verifyIdent((IdentNode)lhs, "assignment"); 736 break; 737 } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) { 738 break; 739 } else if (opType == ASSIGN && isDestructuringLhs(lhs)) { 740 verifyDestructuringAssignmentPattern(lhs, "assignment"); 741 break; 742 } else { 743 return referenceError(lhs, rhs, env._early_lvalue_error); 744 } 745 default: 746 break; 747 } 748 749 // Build up node. 750 if(BinaryNode.isLogical(opType)) { 751 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); 752 } 753 return new BinaryNode(op, lhs, rhs); 754 } 755 756 private boolean isDestructuringLhs(Expression lhs) { 757 if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) { 758 return isES6(); 759 } 760 return false; 761 } 762 763 private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) { 764 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; 765 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 766 @Override 767 public boolean enterLiteralNode(LiteralNode<?> literalNode) { 768 if (literalNode.isArray()) { 769 boolean restElement = false; 770 for (Expression element : literalNode.getElementExpressions()) { 771 if (element != null) { 772 if (restElement) { 773 throw error(String.format("Unexpected element after rest element"), element.getToken()); 774 } 775 if (element.isTokenType(SPREAD_ARRAY)) { 776 restElement = true; 777 Expression lvalue = ((UnaryNode) element).getExpression(); 778 if (!checkValidLValue(lvalue, contextString)) { 779 throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken()); 780 } 781 } 782 element.accept(this); 783 } 784 } 785 return false; 786 } else { 787 return enterDefault(literalNode); 788 } 789 } 790 791 @Override 792 public boolean enterObjectNode(ObjectNode objectNode) { 793 return true; 794 } 795 796 @Override 797 public boolean enterPropertyNode(PropertyNode propertyNode) { 798 if (propertyNode.getValue() != null) { 799 propertyNode.getValue().accept(this); 800 return false; 801 } else { 802 return enterDefault(propertyNode); 803 } 804 } 805 806 @Override 807 public boolean enterIdentNode(IdentNode identNode) { 808 verifyIdent(identNode, contextString); 809 if (!checkIdentLValue(identNode)) { 810 referenceError(identNode, null, true); 811 return false; 812 } 813 return false; 814 } 815 816 @Override 817 public boolean enterAccessNode(AccessNode accessNode) { 818 return false; 819 } 820 821 @Override 822 public boolean enterIndexNode(IndexNode indexNode) { 823 return false; 824 } 825 826 @Override 827 public boolean enterBinaryNode(BinaryNode binaryNode) { 828 if (binaryNode.isTokenType(ASSIGN)) { 829 binaryNode.lhs().accept(this); 830 // Initializer(rhs) can be any AssignmentExpression 831 return false; 832 } else { 833 return enterDefault(binaryNode); 834 } 835 } 836 837 @Override 838 public boolean enterUnaryNode(UnaryNode unaryNode) { 839 if (unaryNode.isTokenType(SPREAD_ARRAY)) { 840 // rest element 841 return true; 842 } else { 843 return enterDefault(unaryNode); 844 } 845 } 846 847 @Override 848 protected boolean enterDefault(Node node) { 849 throw error(String.format("unexpected node in AssignmentPattern: %s", node)); 850 } 851 }); 852 } 853 854 private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) { 855 final TokenType opType = Token.descType(op); 856 857 // Build up node. 858 if (BinaryNode.isLogical(opType)) { 859 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); 860 } 861 return new BinaryNode(op, lhs, rhs); 862 } 863 864 865 /** 866 * Reduce increment/decrement to simpler operations. 867 * @param firstToken First token. 868 * @param tokenType Operation token (INCPREFIX/DEC.) 869 * @param expression Left hand side expression. 870 * @param isPostfix Prefix or postfix. 871 * @return Reduced expression. 872 */ 873 private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) { 874 if (isPostfix) { 875 return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); 876 } 877 878 return new UnaryNode(firstToken, expression); 879 } 880 881 /** 882 * ----------------------------------------------------------------------- 883 * 884 * Grammar based on 885 * 886 * ECMAScript Language Specification 887 * ECMA-262 5th Edition / December 2009 888 * 889 * ----------------------------------------------------------------------- 890 */ 891 892 /** 893 * Program : 894 * SourceElements? 895 * 896 * See 14 897 * 898 * Parse the top level script. 899 */ 900 private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) { 901 // Make a pseudo-token for the script holding its start and length. 902 final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength()); 903 final int functionLine = line; 904 905 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName); 906 final ParserContextFunctionNode script = createParserContextFunctionNode( 907 ident, 908 functionToken, 909 FunctionNode.Kind.SCRIPT, 910 functionLine, 911 Collections.<IdentNode>emptyList()); 912 lc.push(script); 913 final ParserContextBlockNode body = newBlock(); 914 915 functionDeclarations = new ArrayList<>(); 916 sourceElements(allowPropertyFunction); 917 addFunctionDeclarations(script); 918 functionDeclarations = null; 919 920 restoreBlock(body); 921 body.setFlag(Block.NEEDS_SCOPE); 922 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); 923 lc.pop(script); 924 script.setLastToken(token); 925 926 expect(EOF); 927 928 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody); 929 } 930 931 /** 932 * Directive value or null if statement is not a directive. 933 * 934 * @param stmt Statement to be checked 935 * @return Directive value if the given statement is a directive 936 */ 937 private String getDirective(final Node stmt) { 938 if (stmt instanceof ExpressionStatement) { 939 final Node expr = ((ExpressionStatement)stmt).getExpression(); 940 if (expr instanceof LiteralNode) { 941 final LiteralNode<?> lit = (LiteralNode<?>)expr; 942 final long litToken = lit.getToken(); 943 final TokenType tt = Token.descType(litToken); 944 // A directive is either a string or an escape string 945 if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) { 946 // Make sure that we don't unescape anything. Return as seen in source! 947 return source.getString(lit.getStart(), Token.descLength(litToken)); 948 } 949 } 950 } 951 952 return null; 953 } 954 955 /** 956 * SourceElements : 957 * SourceElement 958 * SourceElements SourceElement 959 * 960 * See 14 961 * 962 * Parse the elements of the script or function. 963 */ 964 private void sourceElements(final boolean shouldAllowPropertyFunction) { 965 List<Node> directiveStmts = null; 966 boolean checkDirective = true; 967 boolean allowPropertyFunction = shouldAllowPropertyFunction; 968 final boolean oldStrictMode = isStrictMode; 969 970 971 try { 972 // If is a script, then process until the end of the script. 973 while (type != EOF) { 974 // Break if the end of a code block. 975 if (type == RBRACE) { 976 break; 977 } 978 979 try { 980 // Get the next element. 981 statement(true, allowPropertyFunction, false, false); 982 allowPropertyFunction = false; 983 984 // check for directive prologues 985 if (checkDirective) { 986 // skip any debug statement like line number to get actual first line 987 final Statement lastStatement = lc.getLastStatement(); 988 989 // get directive prologue, if any 990 final String directive = getDirective(lastStatement); 991 992 // If we have seen first non-directive statement, 993 // no more directive statements!! 994 checkDirective = directive != null; 995 996 if (checkDirective) { 997 if (!oldStrictMode) { 998 if (directiveStmts == null) { 999 directiveStmts = new ArrayList<>(); 1000 } 1001 directiveStmts.add(lastStatement); 1002 } 1003 1004 // handle use strict directive 1005 if ("use strict".equals(directive)) { 1006 isStrictMode = true; 1007 final ParserContextFunctionNode function = lc.getCurrentFunction(); 1008 function.setFlag(FunctionNode.IS_STRICT); 1009 1010 // We don't need to check these, if lexical environment is already strict 1011 if (!oldStrictMode && directiveStmts != null) { 1012 // check that directives preceding this one do not violate strictness 1013 for (final Node statement : directiveStmts) { 1014 // the get value will force unescape of preceding 1015 // escaped string directives 1016 getValue(statement.getToken()); 1017 } 1018 1019 // verify that function name as well as parameter names 1020 // satisfy strict mode restrictions. 1021 verifyIdent(function.getIdent(), "function name"); 1022 for (final IdentNode param : function.getParameters()) { 1023 verifyIdent(param, "function parameter"); 1024 } 1025 } 1026 } else if (Context.DEBUG) { 1027 final int debugFlag = FunctionNode.getDirectiveFlag(directive); 1028 if (debugFlag != 0) { 1029 final ParserContextFunctionNode function = lc.getCurrentFunction(); 1030 function.setDebugFlag(debugFlag); 1031 } 1032 } 1033 } 1034 } 1035 } catch (final Exception e) { 1036 final int errorLine = line; 1037 final long errorToken = token; 1038 //recover parsing 1039 recover(e); 1040 final ErrorNode errorExpr = new ErrorNode(errorToken, finish); 1041 final ExpressionStatement expressionStatement = new ExpressionStatement(errorLine, errorToken, finish, errorExpr); 1042 appendStatement(expressionStatement); 1043 } 1044 1045 // No backtracking from here on. 1046 stream.commit(k); 1047 } 1048 } finally { 1049 isStrictMode = oldStrictMode; 1050 } 1051 } 1052 1053 /** 1054 * Parse any of the basic statement types. 1055 * 1056 * Statement : 1057 * BlockStatement 1058 * VariableStatement 1059 * EmptyStatement 1060 * ExpressionStatement 1061 * IfStatement 1062 * BreakableStatement 1063 * ContinueStatement 1064 * BreakStatement 1065 * ReturnStatement 1066 * WithStatement 1067 * LabelledStatement 1068 * ThrowStatement 1069 * TryStatement 1070 * DebuggerStatement 1071 * 1072 * BreakableStatement : 1073 * IterationStatement 1074 * SwitchStatement 1075 * 1076 * BlockStatement : 1077 * Block 1078 * 1079 * Block : 1080 * { StatementList opt } 1081 * 1082 * StatementList : 1083 * StatementListItem 1084 * StatementList StatementListItem 1085 * 1086 * StatementItem : 1087 * Statement 1088 * Declaration 1089 * 1090 * Declaration : 1091 * HoistableDeclaration 1092 * ClassDeclaration 1093 * LexicalDeclaration 1094 * 1095 * HoistableDeclaration : 1096 * FunctionDeclaration 1097 * GeneratorDeclaration 1098 */ 1099 private void statement() { 1100 statement(false, false, false, false); 1101 } 1102 1103 /** 1104 * @param topLevel does this statement occur at the "top level" of a script or a function? 1105 * @param allowPropertyFunction allow property "get" and "set" functions? 1106 * @param singleStatement are we in a single statement context? 1107 */ 1108 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) { 1109 switch (type) { 1110 case LBRACE: 1111 block(); 1112 break; 1113 case VAR: 1114 variableStatement(type); 1115 break; 1116 case SEMICOLON: 1117 emptyStatement(); 1118 break; 1119 case IF: 1120 ifStatement(); 1121 break; 1122 case FOR: 1123 forStatement(); 1124 break; 1125 case WHILE: 1126 whileStatement(); 1127 break; 1128 case DO: 1129 doStatement(); 1130 break; 1131 case CONTINUE: 1132 continueStatement(); 1133 break; 1134 case BREAK: 1135 breakStatement(); 1136 break; 1137 case RETURN: 1138 returnStatement(); 1139 break; 1140 case WITH: 1141 withStatement(); 1142 break; 1143 case SWITCH: 1144 switchStatement(); 1145 break; 1146 case THROW: 1147 throwStatement(); 1148 break; 1149 case TRY: 1150 tryStatement(); 1151 break; 1152 case DEBUGGER: 1153 debuggerStatement(); 1154 break; 1155 case RPAREN: 1156 case RBRACKET: 1157 case EOF: 1158 expect(SEMICOLON); 1159 break; 1160 case FUNCTION: 1161 // As per spec (ECMA section 12), function declarations as arbitrary statement 1162 // is not "portable". Implementation can issue a warning or disallow the same. 1163 if (singleStatement) { 1164 // ES6 B.3.2 Labelled Function Declarations 1165 // It is a Syntax Error if any strict mode source code matches this rule: 1166 // LabelledItem : FunctionDeclaration. 1167 if (!labelledStatement || isStrictMode) { 1168 throw error(AbstractParser.message("expected.stmt", "function declaration"), token); 1169 } 1170 } 1171 functionExpression(true, topLevel || labelledStatement); 1172 return; 1173 default: 1174 if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) { 1175 if (singleStatement) { 1176 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); 1177 } 1178 variableStatement(type); 1179 break; 1180 } else if (type == CLASS && isES6()) { 1181 if (singleStatement) { 1182 throw error(AbstractParser.message("expected.stmt", "class declaration"), token); 1183 } 1184 classDeclaration(false); 1185 break; 1186 } 1187 if (env._const_as_var && type == CONST) { 1188 variableStatement(TokenType.VAR); 1189 break; 1190 } 1191 1192 if (type == IDENT || isNonStrictModeIdent()) { 1193 if (T(k + 1) == COLON) { 1194 labelStatement(); 1195 return; 1196 } 1197 if(allowPropertyFunction) { 1198 final String ident = (String)getValue(); 1199 final long propertyToken = token; 1200 final int propertyLine = line; 1201 if ("get".equals(ident)) { 1202 next(); 1203 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); 1204 return; 1205 } else if ("set".equals(ident)) { 1206 next(); 1207 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); 1208 return; 1209 } 1210 } 1211 } 1212 1213 expressionStatement(); 1214 break; 1215 } 1216 } 1217 1218 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { 1219 final FunctionNode fn = propertyFunction.functionNode; 1220 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); 1221 } 1222 1223 /** 1224 * ClassDeclaration[Yield, Default] : 1225 * class BindingIdentifier[?Yield] ClassTail[?Yield] 1226 * [+Default] class ClassTail[?Yield] 1227 */ 1228 private ClassNode classDeclaration(boolean isDefault) { 1229 int classLineNumber = line; 1230 1231 ClassNode classExpression = classExpression(!isDefault); 1232 1233 if (!isDefault) { 1234 VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST); 1235 appendStatement(classVar); 1236 } 1237 return classExpression; 1238 } 1239 1240 /** 1241 * ClassExpression[Yield] : 1242 * class BindingIdentifier[?Yield]opt ClassTail[?Yield] 1243 */ 1244 private ClassNode classExpression(boolean isStatement) { 1245 assert type == CLASS; 1246 int classLineNumber = line; 1247 long classToken = token; 1248 next(); 1249 1250 IdentNode className = null; 1251 if (isStatement || type == IDENT) { 1252 className = getIdent(); 1253 } 1254 1255 return classTail(classLineNumber, classToken, className); 1256 } 1257 1258 private static final class ClassElementKey { 1259 private final boolean isStatic; 1260 private final String propertyName; 1261 1262 private ClassElementKey(boolean isStatic, String propertyName) { 1263 this.isStatic = isStatic; 1264 this.propertyName = propertyName; 1265 } 1266 1267 @Override 1268 public int hashCode() { 1269 final int prime = 31; 1270 int result = 1; 1271 result = prime * result + (isStatic ? 1231 : 1237); 1272 result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); 1273 return result; 1274 } 1275 1276 @Override 1277 public boolean equals(Object obj) { 1278 if (obj instanceof ClassElementKey) { 1279 ClassElementKey other = (ClassElementKey) obj; 1280 return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName); 1281 } 1282 return false; 1283 } 1284 } 1285 1286 /** 1287 * Parse ClassTail and ClassBody. 1288 * 1289 * ClassTail[Yield] : 1290 * ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } 1291 * ClassHeritage[Yield] : 1292 * extends LeftHandSideExpression[?Yield] 1293 * 1294 * ClassBody[Yield] : 1295 * ClassElementList[?Yield] 1296 * ClassElementList[Yield] : 1297 * ClassElement[?Yield] 1298 * ClassElementList[?Yield] ClassElement[?Yield] 1299 * ClassElement[Yield] : 1300 * MethodDefinition[?Yield] 1301 * static MethodDefinition[?Yield] 1302 * ; 1303 */ 1304 private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) { 1305 final boolean oldStrictMode = isStrictMode; 1306 isStrictMode = true; 1307 try { 1308 Expression classHeritage = null; 1309 if (type == EXTENDS) { 1310 next(); 1311 classHeritage = leftHandSideExpression(); 1312 } 1313 1314 expect(LBRACE); 1315 1316 PropertyNode constructor = null; 1317 final ArrayList<PropertyNode> classElements = new ArrayList<>(); 1318 final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>(); 1319 for (;;) { 1320 if (type == SEMICOLON) { 1321 next(); 1322 continue; 1323 } 1324 if (type == RBRACE) { 1325 break; 1326 } 1327 final long classElementToken = token; 1328 boolean isStatic = false; 1329 if (type == STATIC) { 1330 isStatic = true; 1331 next(); 1332 } 1333 boolean generator = false; 1334 if (isES6() && type == MUL) { 1335 generator = true; 1336 next(); 1337 } 1338 final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator); 1339 if (classElement.isComputed()) { 1340 classElements.add(classElement); 1341 } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) { 1342 if (constructor == null) { 1343 constructor = classElement; 1344 } else { 1345 throw error(AbstractParser.message("multiple.constructors"), classElementToken); 1346 } 1347 } else { 1348 // Check for duplicate method definitions and combine accessor methods. 1349 // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names). 1350 1351 final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName()); 1352 final Integer existing = keyToIndexMap.get(key); 1353 1354 if (existing == null) { 1355 keyToIndexMap.put(key, classElements.size()); 1356 classElements.add(classElement); 1357 } else { 1358 final PropertyNode existingProperty = classElements.get(existing); 1359 1360 final Expression value = classElement.getValue(); 1361 final FunctionNode getter = classElement.getGetter(); 1362 final FunctionNode setter = classElement.getSetter(); 1363 1364 if (value != null || existingProperty.getValue() != null) { 1365 keyToIndexMap.put(key, classElements.size()); 1366 classElements.add(classElement); 1367 } else if (getter != null) { 1368 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; 1369 classElements.set(existing, existingProperty.setGetter(getter)); 1370 } else if (setter != null) { 1371 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null; 1372 classElements.set(existing, existingProperty.setSetter(setter)); 1373 } 1374 } 1375 } 1376 } 1377 1378 final long lastToken = token; 1379 expect(RBRACE); 1380 1381 if (constructor == null) { 1382 constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null); 1383 } 1384 1385 classElements.trimToSize(); 1386 return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements); 1387 } finally { 1388 isStrictMode = oldStrictMode; 1389 } 1390 } 1391 1392 private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) { 1393 final int ctorFinish = finish; 1394 final List<Statement> statements; 1395 final List<IdentNode> parameters; 1396 final long identToken = Token.recast(classToken, TokenType.IDENT); 1397 if (subclass) { 1398 final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper(); 1399 final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter(); 1400 final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent); 1401 final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false); 1402 statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall)); 1403 parameters = Collections.singletonList(argsIdent); 1404 } else { 1405 statements = Collections.emptyList(); 1406 parameters = Collections.emptyList(); 1407 } 1408 1409 final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements); 1410 final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor"); 1411 final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters); 1412 function.setLastToken(lastToken); 1413 1414 function.setFlag(FunctionNode.ES6_IS_METHOD); 1415 function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR); 1416 if (subclass) { 1417 function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR); 1418 function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); 1419 } 1420 if (className == null) { 1421 function.setFlag(FunctionNode.IS_ANONYMOUS); 1422 } 1423 1424 final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode( 1425 function, 1426 classToken, 1427 ctorName, 1428 parameters, 1429 FunctionNode.Kind.NORMAL, 1430 classLineNumber, 1431 body 1432 ), null, null, false, false); 1433 return constructor; 1434 } 1435 1436 private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) { 1437 final long methodToken = token; 1438 final int methodLine = line; 1439 final boolean computed = type == LBRACKET; 1440 final boolean isIdent = type == IDENT; 1441 final Expression propertyName = propertyName(); 1442 int flags = FunctionNode.ES6_IS_METHOD; 1443 if (!computed) { 1444 final String name = ((PropertyKey)propertyName).getPropertyName(); 1445 if (!generator && isIdent && type != LPAREN && name.equals("get")) { 1446 final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags); 1447 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); 1448 return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed); 1449 } else if (!generator && isIdent && type != LPAREN && name.equals("set")) { 1450 final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags); 1451 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true); 1452 return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed); 1453 } else { 1454 if (!isStatic && !generator && name.equals("constructor")) { 1455 flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR; 1456 if (subclass) { 1457 flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR; 1458 } 1459 } 1460 verifyAllowedMethodName(propertyName, isStatic, computed, generator, false); 1461 } 1462 } 1463 final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed); 1464 return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed); 1465 } 1466 1467 /** 1468 * ES6 14.5.1 Static Semantics: Early Errors. 1469 */ 1470 private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) { 1471 if (!computed) { 1472 if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) { 1473 throw error(AbstractParser.message("generator.constructor"), key.getToken()); 1474 } 1475 if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) { 1476 throw error(AbstractParser.message("accessor.constructor"), key.getToken()); 1477 } 1478 if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) { 1479 throw error(AbstractParser.message("static.prototype.method"), key.getToken()); 1480 } 1481 } 1482 } 1483 1484 /** 1485 * block : 1486 * { StatementList? } 1487 * 1488 * see 12.1 1489 * 1490 * Parse a statement block. 1491 */ 1492 private void block() { 1493 appendStatement(new BlockStatement(line, getBlock(true))); 1494 } 1495 1496 /** 1497 * StatementList : 1498 * Statement 1499 * StatementList Statement 1500 * 1501 * See 12.1 1502 * 1503 * Parse a list of statements. 1504 */ 1505 private void statementList() { 1506 // Accumulate statements until end of list. */ 1507 loop: 1508 while (type != EOF) { 1509 switch (type) { 1510 case EOF: 1511 case CASE: 1512 case DEFAULT: 1513 case RBRACE: 1514 break loop; 1515 default: 1516 break; 1517 } 1518 1519 // Get next statement. 1520 statement(); 1521 } 1522 } 1523 1524 /** 1525 * Make sure that the identifier name used is allowed. 1526 * 1527 * @param ident Identifier that is verified 1528 * @param contextString String used in error message to give context to the user 1529 */ 1530 private void verifyIdent(final IdentNode ident, final String contextString) { 1531 verifyStrictIdent(ident, contextString); 1532 if (isES6()) { 1533 final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length()); 1534 if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) { 1535 throw error(expectMessage(IDENT)); 1536 } 1537 } 1538 } 1539 1540 /** 1541 * Make sure that in strict mode, the identifier name used is allowed. 1542 * 1543 * @param ident Identifier that is verified 1544 * @param contextString String used in error message to give context to the user 1545 */ 1546 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 1547 if (isStrictMode) { 1548 switch (ident.getName()) { 1549 case "eval": 1550 case "arguments": 1551 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1552 default: 1553 break; 1554 } 1555 1556 if (ident.isFutureStrictName()) { 1557 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1558 } 1559 } 1560 } 1561 1562 /* 1563 * VariableStatement : 1564 * var VariableDeclarationList ; 1565 * 1566 * VariableDeclarationList : 1567 * VariableDeclaration 1568 * VariableDeclarationList , VariableDeclaration 1569 * 1570 * VariableDeclaration : 1571 * Identifier Initializer? 1572 * 1573 * Initializer : 1574 * = AssignmentExpression 1575 * 1576 * See 12.2 1577 * 1578 * Parse a VAR statement. 1579 * @param isStatement True if a statement (not used in a FOR.) 1580 */ 1581 private void variableStatement(final TokenType varType) { 1582 variableDeclarationList(varType, true, -1); 1583 } 1584 1585 private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) { 1586 // VAR tested in caller. 1587 assert varType == VAR || varType == LET || varType == CONST; 1588 next(); 1589 1590 final List<Expression> bindings = new ArrayList<>(); 1591 int varFlags = 0; 1592 if (varType == LET) { 1593 varFlags |= VarNode.IS_LET; 1594 } else if (varType == CONST) { 1595 varFlags |= VarNode.IS_CONST; 1596 } 1597 1598 Expression missingAssignment = null; 1599 while (true) { 1600 // Get starting token. 1601 final int varLine = line; 1602 final long varToken = token; 1603 // Get name of var. 1604 if (type == YIELD && inGeneratorFunction()) { 1605 expect(IDENT); 1606 } 1607 1608 final String contextString = "variable name"; 1609 Expression binding = bindingIdentifierOrPattern(contextString); 1610 final boolean isDestructuring = !(binding instanceof IdentNode); 1611 if (isDestructuring) { 1612 final int finalVarFlags = varFlags; 1613 verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() { 1614 public void accept(final IdentNode identNode) { 1615 verifyIdent(identNode, contextString); 1616 final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags); 1617 appendStatement(var); 1618 } 1619 }); 1620 } 1621 1622 // Assume no init. 1623 Expression init = null; 1624 1625 // Look for initializer assignment. 1626 if (type == ASSIGN) { 1627 next(); 1628 1629 // Get initializer expression. Suppress IN if not statement. 1630 if (!isDestructuring) { 1631 defaultNames.push(binding); 1632 } 1633 try { 1634 init = assignmentExpression(!isStatement); 1635 } finally { 1636 if (!isDestructuring) { 1637 defaultNames.pop(); 1638 } 1639 } 1640 } else if (isStatement) { 1641 if (isDestructuring) { 1642 throw error(AbstractParser.message("missing.destructuring.assignment"), token); 1643 } else if (varType == CONST) { 1644 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName())); 1645 } 1646 // else, if we are in a for loop, delay checking until we know the kind of loop 1647 } 1648 1649 if (!isDestructuring) { 1650 assert init != null || varType != CONST || !isStatement; 1651 final IdentNode ident = (IdentNode)binding; 1652 if (!isStatement && ident.getName().equals("let")) { 1653 throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1 1654 } 1655 // Only set declaration flag on lexically scoped let/const as it adds runtime overhead. 1656 final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident; 1657 binding = name; 1658 final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags); 1659 appendStatement(var); 1660 if (init == null && varType == CONST) { 1661 if (missingAssignment == null) { 1662 missingAssignment = binding; 1663 } 1664 } 1665 } else { 1666 assert init != null || !isStatement; 1667 binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init); 1668 if (isStatement) { 1669 appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding)); 1670 } else if (init == null) { 1671 if (missingAssignment == null) { 1672 missingAssignment = binding; 1673 } 1674 } 1675 } 1676 bindings.add(binding); 1677 1678 if (type != COMMARIGHT) { 1679 break; 1680 } 1681 next(); 1682 } 1683 1684 // If is a statement then handle end of line. 1685 if (isStatement) { 1686 endOfLine(); 1687 } else { 1688 if (type == SEMICOLON) { 1689 // late check for missing assignment, now we know it's a for (init; test; modify) loop 1690 if (missingAssignment != null) { 1691 if (missingAssignment instanceof IdentNode) { 1692 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName())); 1693 } else { 1694 throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken()); 1695 } 1696 } 1697 } 1698 } 1699 1700 return bindings; 1701 } 1702 1703 private boolean isBindingIdentifier() { 1704 return type == IDENT || isNonStrictModeIdent(); 1705 } 1706 1707 private IdentNode bindingIdentifier(final String contextString) { 1708 final IdentNode name = getIdent(); 1709 verifyIdent(name, contextString); 1710 return name; 1711 } 1712 1713 private Expression bindingPattern() { 1714 if (type == LBRACKET) { 1715 return arrayLiteral(); 1716 } else if (type == LBRACE) { 1717 return objectLiteral(); 1718 } else { 1719 throw error(AbstractParser.message("expected.binding")); 1720 } 1721 } 1722 1723 private Expression bindingIdentifierOrPattern(final String contextString) { 1724 if (isBindingIdentifier() || !isES6()) { 1725 return bindingIdentifier(contextString); 1726 } else { 1727 return bindingPattern(); 1728 } 1729 } 1730 1731 /** 1732 * Verify destructuring variable declaration binding pattern and extract bound variable declarations. 1733 */ 1734 private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) { 1735 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode; 1736 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 1737 @Override 1738 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 1739 if (literalNode.isArray()) { 1740 boolean restElement = false; 1741 for (final Expression element : literalNode.getElementExpressions()) { 1742 if (restElement) { 1743 throw error(String.format("Unexpected element after rest element"), element.getToken()); 1744 } 1745 if (element != null) { 1746 if (element.isTokenType(SPREAD_ARRAY)) { 1747 restElement = true; 1748 if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) { 1749 throw error(String.format("Expected a valid binding identifier"), element.getToken()); 1750 1751 } 1752 } 1753 element.accept(this); 1754 } 1755 } 1756 return false; 1757 } else { 1758 return enterDefault(literalNode); 1759 } 1760 } 1761 1762 @Override 1763 public boolean enterObjectNode(final ObjectNode objectNode) { 1764 return true; 1765 } 1766 1767 @Override 1768 public boolean enterPropertyNode(final PropertyNode propertyNode) { 1769 if (propertyNode.getValue() != null) { 1770 propertyNode.getValue().accept(this); 1771 return false; 1772 } else { 1773 return enterDefault(propertyNode); 1774 } 1775 } 1776 1777 @Override 1778 public boolean enterIdentNode(final IdentNode identNode) { 1779 identifierCallback.accept(identNode); 1780 return false; 1781 } 1782 1783 @Override 1784 public boolean enterBinaryNode(final BinaryNode binaryNode) { 1785 if (binaryNode.isTokenType(ASSIGN)) { 1786 binaryNode.lhs().accept(this); 1787 // Initializer(rhs) can be any AssignmentExpression 1788 return false; 1789 } else { 1790 return enterDefault(binaryNode); 1791 } 1792 } 1793 1794 @Override 1795 public boolean enterUnaryNode(final UnaryNode unaryNode) { 1796 if (unaryNode.isTokenType(SPREAD_ARRAY)) { 1797 // rest element 1798 return true; 1799 } else { 1800 return enterDefault(unaryNode); 1801 } 1802 } 1803 1804 @Override 1805 protected boolean enterDefault(final Node node) { 1806 throw error(String.format("unexpected node in BindingPattern: %s", node)); 1807 } 1808 }); 1809 } 1810 1811 /** 1812 * EmptyStatement : 1813 * ; 1814 * 1815 * See 12.3 1816 * 1817 * Parse an empty statement. 1818 */ 1819 private void emptyStatement() { 1820 if (env._empty_statements) { 1821 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); 1822 } 1823 1824 // SEMICOLON checked in caller. 1825 next(); 1826 } 1827 1828 /** 1829 * ExpressionStatement : 1830 * Expression ; // [lookahead ~( or function )] 1831 * 1832 * See 12.4 1833 * 1834 * Parse an expression used in a statement block. 1835 */ 1836 private void expressionStatement() { 1837 // Lookahead checked in caller. 1838 final int expressionLine = line; 1839 final long expressionToken = token; 1840 1841 // Get expression and add as statement. 1842 final Expression expression = expression(); 1843 1844 ExpressionStatement expressionStatement = null; 1845 if (expression != null) { 1846 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); 1847 appendStatement(expressionStatement); 1848 } else { 1849 expect(null); 1850 } 1851 1852 endOfLine(); 1853 } 1854 1855 /** 1856 * IfStatement : 1857 * if ( Expression ) Statement else Statement 1858 * if ( Expression ) Statement 1859 * 1860 * See 12.5 1861 * 1862 * Parse an IF statement. 1863 */ 1864 private void ifStatement() { 1865 // Capture IF token. 1866 final int ifLine = line; 1867 final long ifToken = token; 1868 // IF tested in caller. 1869 next(); 1870 1871 expect(LPAREN); 1872 final Expression test = expression(); 1873 expect(RPAREN); 1874 final Block pass = getStatement(); 1875 1876 Block fail = null; 1877 if (type == ELSE) { 1878 next(); 1879 fail = getStatement(); 1880 } 1881 1882 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 1883 } 1884 1885 /** 1886 * ... IterationStatement: 1887 * ... 1888 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement 1889 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement 1890 * for ( LeftHandSideExpression in Expression ) Statement 1891 * for ( var VariableDeclaration[NoIn] in Expression ) Statement 1892 * 1893 * See 12.6 1894 * 1895 * Parse a FOR statement. 1896 */ 1897 @SuppressWarnings("fallthrough") 1898 private void forStatement() { 1899 final long forToken = token; 1900 final int forLine = line; 1901 // start position of this for statement. This is used 1902 // for sort order for variables declared in the initializer 1903 // part of this 'for' statement (if any). 1904 final int forStart = Token.descPosition(forToken); 1905 // When ES6 for-let is enabled we create a container block to capture the LET. 1906 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null; 1907 1908 // Create FOR node, capturing FOR token. 1909 final ParserContextLoopNode forNode = new ParserContextLoopNode(); 1910 lc.push(forNode); 1911 Block body = null; 1912 List<Expression> vars = null; 1913 Expression init = null; 1914 JoinPredecessorExpression test = null; 1915 JoinPredecessorExpression modify = null; 1916 1917 int flags = 0; 1918 boolean isForOf = false; 1919 1920 try { 1921 // FOR tested in caller. 1922 next(); 1923 1924 // Nashorn extension: for each expression. 1925 // iterate property values rather than property names. 1926 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 1927 flags |= ForNode.IS_FOR_EACH; 1928 next(); 1929 } 1930 1931 expect(LPAREN); 1932 1933 switch (type) { 1934 case VAR: 1935 // Var declaration captured in for outer block. 1936 vars = variableDeclarationList(type, false, forStart); 1937 break; 1938 case SEMICOLON: 1939 break; 1940 default: 1941 if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) { 1942 flags |= ForNode.PER_ITERATION_SCOPE; 1943 // LET/CONST declaration captured in container block created above. 1944 vars = variableDeclarationList(type, false, forStart); 1945 break; 1946 } 1947 if (env._const_as_var && type == CONST) { 1948 // Var declaration captured in for outer block. 1949 vars = variableDeclarationList(TokenType.VAR, false, forStart); 1950 break; 1951 } 1952 1953 init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 1954 break; 1955 } 1956 1957 switch (type) { 1958 case SEMICOLON: 1959 // for (init; test; modify) 1960 1961 // for each (init; test; modify) is invalid 1962 if ((flags & ForNode.IS_FOR_EACH) != 0) { 1963 throw error(AbstractParser.message("for.each.without.in"), token); 1964 } 1965 1966 expect(SEMICOLON); 1967 if (type != SEMICOLON) { 1968 test = joinPredecessorExpression(); 1969 } 1970 expect(SEMICOLON); 1971 if (type != RPAREN) { 1972 modify = joinPredecessorExpression(); 1973 } 1974 break; 1975 1976 case IDENT: 1977 if (env._es6 && "of".equals(getValue())) { 1978 isForOf = true; 1979 // fall through 1980 } else { 1981 expect(SEMICOLON); // fail with expected message 1982 break; 1983 } 1984 case IN: 1985 1986 flags |= isForOf ? ForNode.IS_FOR_OF : ForNode.IS_FOR_IN; 1987 test = new JoinPredecessorExpression(); 1988 if (vars != null) { 1989 // for (var i in obj) 1990 if (vars.size() == 1) { 1991 init = new IdentNode((IdentNode)vars.get(0)); 1992 if (init.isTokenType(ASSIGN)) { 1993 throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken()); 1994 } 1995 assert init instanceof IdentNode || isDestructuringLhs(init); 1996 } else { 1997 // for (var i, j in obj) is invalid 1998 throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken()); 1999 } 2000 } else { 2001 // for (expr in obj) 2002 assert init != null : "for..in/of init expression can not be null here"; 2003 2004 // check if initial expression is a valid L-value 2005 if (!(init instanceof AccessNode || 2006 init instanceof IndexNode || 2007 init instanceof IdentNode)) { 2008 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken()); 2009 } 2010 2011 if (init instanceof IdentNode) { 2012 if (!checkIdentLValue((IdentNode)init)) { 2013 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken()); 2014 } 2015 verifyStrictIdent((IdentNode)init, isForOf ? "for-of iterator" : "for-in iterator"); 2016 } 2017 } 2018 2019 next(); 2020 2021 // For-of only allows AssignmentExpression. 2022 modify = isForOf ? new JoinPredecessorExpression(assignmentExpression(false)) : joinPredecessorExpression(); 2023 break; 2024 2025 default: 2026 expect(SEMICOLON); 2027 break; 2028 } 2029 2030 expect(RPAREN); 2031 2032 // Set the for body. 2033 body = getStatement(); 2034 } finally { 2035 lc.pop(forNode); 2036 2037 for (final Statement var : forNode.getStatements()) { 2038 assert var instanceof VarNode; 2039 appendStatement(var); 2040 } 2041 if (body != null) { 2042 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); 2043 } 2044 if (outer != null) { 2045 restoreBlock(outer); 2046 if (body != null) { 2047 appendStatement(new BlockStatement(forLine, new Block( 2048 outer.getToken(), 2049 body.getFinish(), 2050 outer.getStatements()))); 2051 } 2052 } 2053 } 2054 } 2055 2056 private boolean checkValidLValue(final Expression init, final String contextString) { 2057 if (init instanceof IdentNode) { 2058 if (!checkIdentLValue((IdentNode)init)) { 2059 return false; 2060 } 2061 verifyIdent((IdentNode)init, contextString); 2062 return true; 2063 } else if (init instanceof AccessNode || init instanceof IndexNode) { 2064 return true; 2065 } else if (isDestructuringLhs(init)) { 2066 verifyDestructuringAssignmentPattern(init, contextString); 2067 return true; 2068 } else { 2069 return false; 2070 } 2071 } 2072 2073 private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) { 2074 assert type == LET; 2075 for (int i = 1;; i++) { 2076 TokenType t = T(k + i); 2077 switch (t) { 2078 case EOL: 2079 case COMMENT: 2080 continue; 2081 case IDENT: 2082 if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) { 2083 return false; 2084 } 2085 // fall through 2086 case LBRACKET: 2087 case LBRACE: 2088 return true; 2089 default: 2090 // accept future strict tokens in non-strict mode (including LET) 2091 if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) { 2092 return true; 2093 } 2094 return false; 2095 } 2096 } 2097 } 2098 2099 /** 2100 * ...IterationStatement : 2101 * ... 2102 * while ( Expression ) Statement 2103 * ... 2104 * 2105 * See 12.6 2106 * 2107 * Parse while statement. 2108 */ 2109 private void whileStatement() { 2110 // Capture WHILE token. 2111 final long whileToken = token; 2112 final int whileLine = line; 2113 // WHILE tested in caller. 2114 next(); 2115 2116 final ParserContextLoopNode whileNode = new ParserContextLoopNode(); 2117 lc.push(whileNode); 2118 2119 JoinPredecessorExpression test = null; 2120 Block body = null; 2121 2122 try { 2123 expect(LPAREN); 2124 test = joinPredecessorExpression(); 2125 expect(RPAREN); 2126 body = getStatement(); 2127 } finally { 2128 lc.pop(whileNode); 2129 } 2130 2131 if (body != null) { 2132 appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body)); 2133 } 2134 } 2135 2136 /** 2137 * ...IterationStatement : 2138 * ... 2139 * do Statement while( Expression ) ; 2140 * ... 2141 * 2142 * See 12.6 2143 * 2144 * Parse DO WHILE statement. 2145 */ 2146 private void doStatement() { 2147 // Capture DO token. 2148 final long doToken = token; 2149 int doLine = 0; 2150 // DO tested in the caller. 2151 next(); 2152 2153 final ParserContextLoopNode doWhileNode = new ParserContextLoopNode(); 2154 lc.push(doWhileNode); 2155 2156 Block body = null; 2157 JoinPredecessorExpression test = null; 2158 2159 try { 2160 // Get DO body. 2161 body = getStatement(); 2162 2163 expect(WHILE); 2164 expect(LPAREN); 2165 doLine = line; 2166 test = joinPredecessorExpression(); 2167 expect(RPAREN); 2168 2169 if (type == SEMICOLON) { 2170 endOfLine(); 2171 } 2172 } finally { 2173 lc.pop(doWhileNode); 2174 } 2175 2176 appendStatement(new WhileNode(doLine, doToken, finish, true, test, body)); 2177 } 2178 2179 /** 2180 * ContinueStatement : 2181 * continue Identifier? ; // [no LineTerminator here] 2182 * 2183 * See 12.7 2184 * 2185 * Parse CONTINUE statement. 2186 */ 2187 private void continueStatement() { 2188 // Capture CONTINUE token. 2189 final int continueLine = line; 2190 final long continueToken = token; 2191 // CONTINUE tested in caller. 2192 nextOrEOL(); 2193 2194 ParserContextLabelNode labelNode = null; 2195 2196 // SEMICOLON or label. 2197 switch (type) { 2198 case RBRACE: 2199 case SEMICOLON: 2200 case EOL: 2201 case EOF: 2202 break; 2203 2204 default: 2205 final IdentNode ident = getIdent(); 2206 labelNode = lc.findLabel(ident.getName()); 2207 2208 if (labelNode == null) { 2209 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 2210 } 2211 2212 break; 2213 } 2214 2215 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 2216 final ParserContextLoopNode targetNode = lc.getContinueTo(labelName); 2217 2218 if (targetNode == null) { 2219 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 2220 } 2221 2222 endOfLine(); 2223 2224 // Construct and add CONTINUE node. 2225 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); 2226 } 2227 2228 /** 2229 * BreakStatement : 2230 * break Identifier? ; // [no LineTerminator here] 2231 * 2232 * See 12.8 2233 * 2234 */ 2235 private void breakStatement() { 2236 // Capture BREAK token. 2237 final int breakLine = line; 2238 final long breakToken = token; 2239 // BREAK tested in caller. 2240 nextOrEOL(); 2241 2242 ParserContextLabelNode labelNode = null; 2243 2244 // SEMICOLON or label. 2245 switch (type) { 2246 case RBRACE: 2247 case SEMICOLON: 2248 case EOL: 2249 case EOF: 2250 break; 2251 2252 default: 2253 final IdentNode ident = getIdent(); 2254 labelNode = lc.findLabel(ident.getName()); 2255 2256 if (labelNode == null) { 2257 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 2258 } 2259 2260 break; 2261 } 2262 2263 //either an explicit label - then get its node or just a "break" - get first breakable 2264 //targetNode is what we are breaking out from. 2265 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 2266 final ParserContextBreakableNode targetNode = lc.getBreakable(labelName); 2267 if (targetNode == null) { 2268 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 2269 } 2270 2271 endOfLine(); 2272 2273 // Construct and add BREAK node. 2274 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); 2275 } 2276 2277 /** 2278 * ReturnStatement : 2279 * return Expression? ; // [no LineTerminator here] 2280 * 2281 * See 12.9 2282 * 2283 * Parse RETURN statement. 2284 */ 2285 private void returnStatement() { 2286 // check for return outside function 2287 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) { 2288 throw error(AbstractParser.message("invalid.return")); 2289 } 2290 2291 // Capture RETURN token. 2292 final int returnLine = line; 2293 final long returnToken = token; 2294 // RETURN tested in caller. 2295 nextOrEOL(); 2296 2297 Expression expression = null; 2298 2299 // SEMICOLON or expression. 2300 switch (type) { 2301 case RBRACE: 2302 case SEMICOLON: 2303 case EOL: 2304 case EOF: 2305 break; 2306 2307 default: 2308 expression = expression(); 2309 break; 2310 } 2311 2312 endOfLine(); 2313 2314 // Construct and add RETURN node. 2315 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); 2316 } 2317 2318 /** 2319 * Parse YieldExpression. 2320 * 2321 * YieldExpression[In] : 2322 * yield 2323 * yield [no LineTerminator here] AssignmentExpression[?In, Yield] 2324 * yield [no LineTerminator here] * AssignmentExpression[?In, Yield] 2325 */ 2326 private Expression yieldExpression(final boolean noIn) { 2327 assert inGeneratorFunction(); 2328 // Capture YIELD token. 2329 long yieldToken = token; 2330 // YIELD tested in caller. 2331 assert type == YIELD; 2332 nextOrEOL(); 2333 2334 Expression expression = null; 2335 2336 boolean yieldAsterisk = false; 2337 if (type == MUL) { 2338 yieldAsterisk = true; 2339 yieldToken = Token.recast(yieldToken, YIELD_STAR); 2340 next(); 2341 } 2342 2343 switch (type) { 2344 case RBRACE: 2345 case SEMICOLON: 2346 case EOL: 2347 case EOF: 2348 case COMMARIGHT: 2349 case RPAREN: 2350 case RBRACKET: 2351 case COLON: 2352 if (!yieldAsterisk) { 2353 // treat (yield) as (yield void 0) 2354 expression = newUndefinedLiteral(yieldToken, finish); 2355 if (type == EOL) { 2356 next(); 2357 } 2358 break; 2359 } else { 2360 // AssignmentExpression required, fall through 2361 } 2362 2363 default: 2364 expression = assignmentExpression(noIn); 2365 break; 2366 } 2367 2368 // Construct and add YIELD node. 2369 return new UnaryNode(yieldToken, expression); 2370 } 2371 2372 private static UnaryNode newUndefinedLiteral(final long token, final int finish) { 2373 return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0)); 2374 } 2375 2376 /** 2377 * WithStatement : 2378 * with ( Expression ) Statement 2379 * 2380 * See 12.10 2381 * 2382 * Parse WITH statement. 2383 */ 2384 private void withStatement() { 2385 // Capture WITH token. 2386 final int withLine = line; 2387 final long withToken = token; 2388 // WITH tested in caller. 2389 next(); 2390 2391 // ECMA 12.10.1 strict mode restrictions 2392 if (isStrictMode) { 2393 throw error(AbstractParser.message("strict.no.with"), withToken); 2394 } 2395 2396 expect(LPAREN); 2397 final Expression expression = expression(); 2398 expect(RPAREN); 2399 final Block body = getStatement(); 2400 2401 appendStatement(new WithNode(withLine, withToken, finish, expression, body)); 2402 } 2403 2404 /** 2405 * SwitchStatement : 2406 * switch ( Expression ) CaseBlock 2407 * 2408 * CaseBlock : 2409 * { CaseClauses? } 2410 * { CaseClauses? DefaultClause CaseClauses } 2411 * 2412 * CaseClauses : 2413 * CaseClause 2414 * CaseClauses CaseClause 2415 * 2416 * CaseClause : 2417 * case Expression : StatementList? 2418 * 2419 * DefaultClause : 2420 * default : StatementList? 2421 * 2422 * See 12.11 2423 * 2424 * Parse SWITCH statement. 2425 */ 2426 private void switchStatement() { 2427 final int switchLine = line; 2428 final long switchToken = token; 2429 2430 // Block to capture variables declared inside the switch statement. 2431 final ParserContextBlockNode switchBlock = newBlock(); 2432 2433 // SWITCH tested in caller. 2434 next(); 2435 2436 // Create and add switch statement. 2437 final ParserContextSwitchNode switchNode = new ParserContextSwitchNode(); 2438 lc.push(switchNode); 2439 2440 CaseNode defaultCase = null; 2441 // Prepare to accumulate cases. 2442 final List<CaseNode> cases = new ArrayList<>(); 2443 2444 Expression expression = null; 2445 2446 try { 2447 expect(LPAREN); 2448 expression = expression(); 2449 expect(RPAREN); 2450 2451 expect(LBRACE); 2452 2453 2454 while (type != RBRACE) { 2455 // Prepare for next case. 2456 Expression caseExpression = null; 2457 final long caseToken = token; 2458 2459 switch (type) { 2460 case CASE: 2461 next(); 2462 caseExpression = expression(); 2463 break; 2464 2465 case DEFAULT: 2466 if (defaultCase != null) { 2467 throw error(AbstractParser.message("duplicate.default.in.switch")); 2468 } 2469 next(); 2470 break; 2471 2472 default: 2473 // Force an error. 2474 expect(CASE); 2475 break; 2476 } 2477 2478 expect(COLON); 2479 2480 // Get CASE body. 2481 final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList(); 2482 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); 2483 2484 if (caseExpression == null) { 2485 defaultCase = caseNode; 2486 } 2487 2488 cases.add(caseNode); 2489 } 2490 2491 next(); 2492 } finally { 2493 lc.pop(switchNode); 2494 restoreBlock(switchBlock); 2495 } 2496 2497 final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase); 2498 appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement))); 2499 } 2500 2501 /** 2502 * LabelledStatement : 2503 * Identifier : Statement 2504 * 2505 * See 12.12 2506 * 2507 * Parse label statement. 2508 */ 2509 private void labelStatement() { 2510 // Capture label token. 2511 final long labelToken = token; 2512 // Get label ident. 2513 final IdentNode ident = getIdent(); 2514 2515 expect(COLON); 2516 2517 if (lc.findLabel(ident.getName()) != null) { 2518 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 2519 } 2520 2521 final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName()); 2522 Block body = null; 2523 try { 2524 lc.push(labelNode); 2525 body = getStatement(true); 2526 } finally { 2527 assert lc.peek() instanceof ParserContextLabelNode; 2528 lc.pop(labelNode); 2529 } 2530 2531 appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body)); 2532 } 2533 2534 /** 2535 * ThrowStatement : 2536 * throw Expression ; // [no LineTerminator here] 2537 * 2538 * See 12.13 2539 * 2540 * Parse throw statement. 2541 */ 2542 private void throwStatement() { 2543 // Capture THROW token. 2544 final int throwLine = line; 2545 final long throwToken = token; 2546 // THROW tested in caller. 2547 nextOrEOL(); 2548 2549 Expression expression = null; 2550 2551 // SEMICOLON or expression. 2552 switch (type) { 2553 case RBRACE: 2554 case SEMICOLON: 2555 case EOL: 2556 break; 2557 2558 default: 2559 expression = expression(); 2560 break; 2561 } 2562 2563 if (expression == null) { 2564 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2565 } 2566 2567 endOfLine(); 2568 2569 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); 2570 } 2571 2572 /** 2573 * TryStatement : 2574 * try Block Catch 2575 * try Block Finally 2576 * try Block Catch Finally 2577 * 2578 * Catch : 2579 * catch( Identifier if Expression ) Block 2580 * catch( Identifier ) Block 2581 * 2582 * Finally : 2583 * finally Block 2584 * 2585 * See 12.14 2586 * 2587 * Parse TRY statement. 2588 */ 2589 private void tryStatement() { 2590 // Capture TRY token. 2591 final int tryLine = line; 2592 final long tryToken = token; 2593 // TRY tested in caller. 2594 next(); 2595 2596 // Container block needed to act as target for labeled break statements 2597 final int startLine = line; 2598 final ParserContextBlockNode outer = newBlock(); 2599 // Create try. 2600 2601 try { 2602 final Block tryBody = getBlock(true); 2603 final List<Block> catchBlocks = new ArrayList<>(); 2604 2605 while (type == CATCH) { 2606 final int catchLine = line; 2607 final long catchToken = token; 2608 next(); 2609 expect(LPAREN); 2610 final IdentNode exception = getIdent(); 2611 2612 // ECMA 12.4.1 strict mode restrictions 2613 verifyStrictIdent(exception, "catch argument"); 2614 2615 // Nashorn extension: catch clause can have optional 2616 // condition. So, a single try can have more than one 2617 // catch clause each with it's own condition. 2618 final Expression ifExpression; 2619 if (!env._no_syntax_extensions && type == IF) { 2620 next(); 2621 // Get the exception condition. 2622 ifExpression = expression(); 2623 } else { 2624 ifExpression = null; 2625 } 2626 2627 expect(RPAREN); 2628 2629 final ParserContextBlockNode catchBlock = newBlock(); 2630 try { 2631 // Get CATCH body. 2632 final Block catchBody = getBlock(true); 2633 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); 2634 appendStatement(catchNode); 2635 } finally { 2636 restoreBlock(catchBlock); 2637 catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags() | Block.IS_SYNTHETIC, catchBlock.getStatements())); 2638 } 2639 2640 // If unconditional catch then should to be the end. 2641 if (ifExpression == null) { 2642 break; 2643 } 2644 } 2645 2646 // Prepare to capture finally statement. 2647 Block finallyStatements = null; 2648 2649 if (type == FINALLY) { 2650 next(); 2651 finallyStatements = getBlock(true); 2652 } 2653 2654 // Need at least one catch or a finally. 2655 if (catchBlocks.isEmpty() && finallyStatements == null) { 2656 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 2657 } 2658 2659 final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements); 2660 // Add try. 2661 assert lc.peek() == outer; 2662 appendStatement(tryNode); 2663 } finally { 2664 restoreBlock(outer); 2665 } 2666 2667 appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags() | Block.IS_SYNTHETIC, outer.getStatements()))); 2668 } 2669 2670 /** 2671 * DebuggerStatement : 2672 * debugger ; 2673 * 2674 * See 12.15 2675 * 2676 * Parse debugger statement. 2677 */ 2678 private void debuggerStatement() { 2679 // Capture DEBUGGER token. 2680 final int debuggerLine = line; 2681 final long debuggerToken = token; 2682 // DEBUGGER tested in caller. 2683 next(); 2684 endOfLine(); 2685 appendStatement(new DebuggerNode(debuggerLine, debuggerToken, finish)); 2686 } 2687 2688 /** 2689 * PrimaryExpression : 2690 * this 2691 * IdentifierReference 2692 * Literal 2693 * ArrayLiteral 2694 * ObjectLiteral 2695 * RegularExpressionLiteral 2696 * TemplateLiteral 2697 * CoverParenthesizedExpressionAndArrowParameterList 2698 * 2699 * CoverParenthesizedExpressionAndArrowParameterList : 2700 * ( Expression ) 2701 * ( ) 2702 * ( ... BindingIdentifier ) 2703 * ( Expression , ... BindingIdentifier ) 2704 * 2705 * Parse primary expression. 2706 * @return Expression node. 2707 */ 2708 @SuppressWarnings("fallthrough") 2709 private Expression primaryExpression() { 2710 // Capture first token. 2711 final int primaryLine = line; 2712 final long primaryToken = token; 2713 2714 switch (type) { 2715 case THIS: 2716 final String name = type.getName(); 2717 next(); 2718 markThis(lc); 2719 return new IdentNode(primaryToken, finish, name); 2720 case IDENT: 2721 final IdentNode ident = getIdent(); 2722 if (ident == null) { 2723 break; 2724 } 2725 detectSpecialProperty(ident); 2726 return ident; 2727 case OCTAL_LEGACY: 2728 if (isStrictMode) { 2729 throw error(AbstractParser.message("strict.no.octal"), token); 2730 } 2731 case STRING: 2732 case ESCSTRING: 2733 case DECIMAL: 2734 case HEXADECIMAL: 2735 case OCTAL: 2736 case BINARY_NUMBER: 2737 case FLOATING: 2738 case REGEX: 2739 case XML: 2740 return getLiteral(); 2741 case EXECSTRING: 2742 return execString(primaryLine, primaryToken); 2743 case FALSE: 2744 next(); 2745 return LiteralNode.newInstance(primaryToken, finish, false); 2746 case TRUE: 2747 next(); 2748 return LiteralNode.newInstance(primaryToken, finish, true); 2749 case NULL: 2750 next(); 2751 return LiteralNode.newInstance(primaryToken, finish); 2752 case LBRACKET: 2753 return arrayLiteral(); 2754 case LBRACE: 2755 return objectLiteral(); 2756 case LPAREN: 2757 next(); 2758 2759 if (isES6()) { 2760 if (type == RPAREN) { 2761 // () 2762 nextOrEOL(); 2763 expectDontAdvance(ARROW); 2764 return new ExpressionList(primaryToken, finish, Collections.emptyList()); 2765 } else if (type == ELLIPSIS) { 2766 // (...rest) 2767 final IdentNode restParam = formalParameterList(false).get(0); 2768 expectDontAdvance(RPAREN); 2769 nextOrEOL(); 2770 expectDontAdvance(ARROW); 2771 return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam)); 2772 } 2773 } 2774 2775 final Expression expression = expression(); 2776 2777 expect(RPAREN); 2778 2779 return expression; 2780 case TEMPLATE: 2781 case TEMPLATE_HEAD: 2782 return templateLiteral(); 2783 2784 default: 2785 // In this context some operator tokens mark the start of a literal. 2786 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 2787 next(); 2788 return getLiteral(); 2789 } 2790 if (isNonStrictModeIdent()) { 2791 return getIdent(); 2792 } 2793 break; 2794 } 2795 2796 return null; 2797 } 2798 2799 /** 2800 * Convert execString to a call to $EXEC. 2801 * 2802 * @param primaryToken Original string token. 2803 * @return callNode to $EXEC. 2804 */ 2805 CallNode execString(final int primaryLine, final long primaryToken) { 2806 // Synthesize an ident to call $EXEC. 2807 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 2808 // Skip over EXECSTRING. 2809 next(); 2810 // Set up argument list for call. 2811 // Skip beginning of edit string expression. 2812 expect(LBRACE); 2813 // Add the following expression to arguments. 2814 final List<Expression> arguments = Collections.singletonList(expression()); 2815 // Skip ending of edit string expression. 2816 expect(RBRACE); 2817 2818 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2819 } 2820 2821 /** 2822 * ArrayLiteral : 2823 * [ Elision? ] 2824 * [ ElementList ] 2825 * [ ElementList , Elision? ] 2826 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2827 * 2828 * ElementList : Elision? AssignmentExpression 2829 * ElementList , Elision? AssignmentExpression 2830 * 2831 * Elision : 2832 * , 2833 * Elision , 2834 * 2835 * See 12.1.4 2836 * JavaScript 1.8 2837 * 2838 * Parse array literal. 2839 * @return Expression node. 2840 */ 2841 private LiteralNode<Expression[]> arrayLiteral() { 2842 // Capture LBRACKET token. 2843 final long arrayToken = token; 2844 // LBRACKET tested in caller. 2845 next(); 2846 2847 // Prepare to accumulate elements. 2848 final List<Expression> elements = new ArrayList<>(); 2849 // Track elisions. 2850 boolean elision = true; 2851 loop: 2852 while (true) { 2853 long spreadToken = 0; 2854 switch (type) { 2855 case RBRACKET: 2856 next(); 2857 2858 break loop; 2859 2860 case COMMARIGHT: 2861 next(); 2862 2863 // If no prior expression 2864 if (elision) { 2865 elements.add(null); 2866 } 2867 2868 elision = true; 2869 2870 break; 2871 2872 case ELLIPSIS: 2873 if (isES6()) { 2874 spreadToken = token; 2875 next(); 2876 } 2877 // fall through 2878 2879 default: 2880 if (!elision) { 2881 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2882 } 2883 2884 // Add expression element. 2885 Expression expression = assignmentExpression(false); 2886 if (expression != null) { 2887 if (spreadToken != 0) { 2888 expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression); 2889 } 2890 elements.add(expression); 2891 } else { 2892 expect(RBRACKET); 2893 } 2894 2895 elision = false; 2896 break; 2897 } 2898 } 2899 2900 return LiteralNode.newInstance(arrayToken, finish, elements); 2901 } 2902 2903 /** 2904 * ObjectLiteral : 2905 * { } 2906 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2907 * 2908 * PropertyNameAndValueList : 2909 * PropertyAssignment 2910 * PropertyNameAndValueList , PropertyAssignment 2911 * 2912 * See 11.1.5 2913 * 2914 * Parse an object literal. 2915 * @return Expression node. 2916 */ 2917 private ObjectNode objectLiteral() { 2918 // Capture LBRACE token. 2919 final long objectToken = token; 2920 // LBRACE tested in caller. 2921 next(); 2922 2923 // Object context. 2924 // Prepare to accumulate elements. 2925 final List<PropertyNode> elements = new ArrayList<>(); 2926 final Map<String, Integer> map = new HashMap<>(); 2927 2928 // Create a block for the object literal. 2929 boolean commaSeen = true; 2930 loop: 2931 while (true) { 2932 switch (type) { 2933 case RBRACE: 2934 next(); 2935 break loop; 2936 2937 case COMMARIGHT: 2938 if (commaSeen) { 2939 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2940 } 2941 next(); 2942 commaSeen = true; 2943 break; 2944 2945 default: 2946 if (!commaSeen) { 2947 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2948 } 2949 2950 commaSeen = false; 2951 // Get and add the next property. 2952 final PropertyNode property = propertyAssignment(); 2953 2954 if (property.isComputed()) { 2955 elements.add(property); 2956 break; 2957 } 2958 2959 final String key = property.getKeyName(); 2960 final Integer existing = map.get(key); 2961 2962 if (existing == null) { 2963 map.put(key, elements.size()); 2964 elements.add(property); 2965 break; 2966 } 2967 2968 final PropertyNode existingProperty = elements.get(existing); 2969 2970 // ECMA section 11.1.5 Object Initialiser 2971 // point # 4 on property assignment production 2972 final Expression value = property.getValue(); 2973 final FunctionNode getter = property.getGetter(); 2974 final FunctionNode setter = property.getSetter(); 2975 2976 final Expression prevValue = existingProperty.getValue(); 2977 final FunctionNode prevGetter = existingProperty.getGetter(); 2978 final FunctionNode prevSetter = existingProperty.getSetter(); 2979 2980 if (!isES6()) { 2981 checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter); 2982 } else { 2983 if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() && 2984 existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) { 2985 throw error(AbstractParser.message("multiple.proto.key"), property.getToken()); 2986 } 2987 } 2988 2989 if (value != null || prevValue != null) { 2990 map.put(key, elements.size()); 2991 elements.add(property); 2992 } else if (getter != null) { 2993 assert prevGetter != null || prevSetter != null; 2994 elements.set(existing, existingProperty.setGetter(getter)); 2995 } else if (setter != null) { 2996 assert prevGetter != null || prevSetter != null; 2997 elements.set(existing, existingProperty.setSetter(setter)); 2998 } 2999 break; 3000 } 3001 } 3002 3003 return new ObjectNode(objectToken, finish, elements); 3004 } 3005 3006 private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) { 3007 // ECMA 11.1.5 strict mode restrictions 3008 if (isStrictMode && value != null && prevValue != null) { 3009 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); 3010 } 3011 3012 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 3013 final boolean isAccessor = getter != null || setter != null; 3014 3015 // data property redefined as accessor property 3016 if (prevValue != null && isAccessor) { 3017 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); 3018 } 3019 3020 // accessor property redefined as data 3021 if (isPrevAccessor && value != null) { 3022 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); 3023 } 3024 3025 if (isAccessor && isPrevAccessor) { 3026 if (getter != null && prevGetter != null || 3027 setter != null && prevSetter != null) { 3028 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken()); 3029 } 3030 } 3031 } 3032 3033 /** 3034 * LiteralPropertyName : 3035 * IdentifierName 3036 * StringLiteral 3037 * NumericLiteral 3038 * 3039 * @return PropertyName node 3040 */ 3041 @SuppressWarnings("fallthrough") 3042 private PropertyKey literalPropertyName() { 3043 switch (type) { 3044 case IDENT: 3045 return getIdent().setIsPropertyName(); 3046 case OCTAL_LEGACY: 3047 if (isStrictMode) { 3048 throw error(AbstractParser.message("strict.no.octal"), token); 3049 } 3050 case STRING: 3051 case ESCSTRING: 3052 case DECIMAL: 3053 case HEXADECIMAL: 3054 case OCTAL: 3055 case BINARY_NUMBER: 3056 case FLOATING: 3057 return getLiteral(); 3058 default: 3059 return getIdentifierName().setIsPropertyName(); 3060 } 3061 } 3062 3063 /** 3064 * ComputedPropertyName : 3065 * AssignmentExpression 3066 * 3067 * @return PropertyName node 3068 */ 3069 private Expression computedPropertyName() { 3070 expect(LBRACKET); 3071 Expression expression = assignmentExpression(false); 3072 expect(RBRACKET); 3073 return expression; 3074 } 3075 3076 /** 3077 * PropertyName : 3078 * LiteralPropertyName 3079 * ComputedPropertyName 3080 * 3081 * @return PropertyName node 3082 */ 3083 private Expression propertyName() { 3084 if (type == LBRACKET && isES6()) { 3085 return computedPropertyName(); 3086 } else { 3087 return (Expression)literalPropertyName(); 3088 } 3089 } 3090 3091 /** 3092 * PropertyAssignment : 3093 * PropertyName : AssignmentExpression 3094 * get PropertyName ( ) { FunctionBody } 3095 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 3096 * 3097 * PropertySetParameterList : 3098 * Identifier 3099 * 3100 * PropertyName : 3101 * IdentifierName 3102 * StringLiteral 3103 * NumericLiteral 3104 * 3105 * See 11.1.5 3106 * 3107 * Parse an object literal property. 3108 * @return Property or reference node. 3109 */ 3110 private PropertyNode propertyAssignment() { 3111 // Capture firstToken. 3112 final long propertyToken = token; 3113 final int functionLine = line; 3114 3115 final Expression propertyName; 3116 final boolean isIdentifier; 3117 3118 boolean generator = false; 3119 if (type == MUL && isES6()) { 3120 generator = true; 3121 next(); 3122 } 3123 3124 final boolean computed = type == LBRACKET; 3125 if (type == IDENT) { 3126 // Get IDENT. 3127 final String ident = (String)expectValue(IDENT); 3128 3129 if (type != COLON && (type != LPAREN || !isES6())) { 3130 final long getSetToken = propertyToken; 3131 3132 switch (ident) { 3133 case "get": 3134 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 3135 return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed); 3136 3137 case "set": 3138 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 3139 return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed); 3140 default: 3141 break; 3142 } 3143 } 3144 3145 isIdentifier = true; 3146 IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 3147 if (type == COLON && ident.equals("__proto__")) { 3148 identNode = identNode.setIsProtoPropertyName(); 3149 } 3150 propertyName = identNode; 3151 } else { 3152 isIdentifier = isNonStrictModeIdent(); 3153 propertyName = propertyName(); 3154 } 3155 3156 Expression propertyValue; 3157 3158 if (generator) { 3159 expectDontAdvance(LPAREN); 3160 } 3161 3162 if (type == LPAREN && isES6()) { 3163 propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode; 3164 } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) { 3165 propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName()); 3166 if (type == ASSIGN && isES6()) { 3167 // TODO if not destructuring, this is a SyntaxError 3168 final long assignToken = token; 3169 next(); 3170 final Expression rhs = assignmentExpression(false); 3171 propertyValue = verifyAssignment(assignToken, propertyValue, rhs); 3172 } 3173 } else { 3174 expect(COLON); 3175 3176 defaultNames.push(propertyName); 3177 try { 3178 propertyValue = assignmentExpression(false); 3179 } finally { 3180 defaultNames.pop(); 3181 } 3182 } 3183 3184 return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed); 3185 } 3186 3187 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 3188 return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); 3189 } 3190 3191 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) { 3192 final boolean computed = type == LBRACKET; 3193 final Expression propertyName = propertyName(); 3194 final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); 3195 final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName)); 3196 expect(LPAREN); 3197 expect(RPAREN); 3198 3199 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); 3200 functionNode.setFlag(flags); 3201 if (computed) { 3202 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 3203 } 3204 lc.push(functionNode); 3205 3206 Block functionBody; 3207 3208 3209 try { 3210 functionBody = functionBody(functionNode); 3211 } finally { 3212 lc.pop(functionNode); 3213 } 3214 3215 final FunctionNode function = createFunctionNode( 3216 functionNode, 3217 getSetToken, 3218 getNameNode, 3219 Collections.<IdentNode>emptyList(), 3220 FunctionNode.Kind.GETTER, 3221 functionLine, 3222 functionBody); 3223 3224 return new PropertyFunction(propertyName, function, computed); 3225 } 3226 3227 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 3228 return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD); 3229 } 3230 3231 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) { 3232 final boolean computed = type == LBRACKET; 3233 final Expression propertyName = propertyName(); 3234 final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false); 3235 final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName)); 3236 expect(LPAREN); 3237 // be sloppy and allow missing setter parameter even though 3238 // spec does not permit it! 3239 final IdentNode argIdent; 3240 if (isBindingIdentifier()) { 3241 argIdent = getIdent(); 3242 verifyIdent(argIdent, "setter argument"); 3243 } else { 3244 argIdent = null; 3245 } 3246 expect(RPAREN); 3247 final List<IdentNode> parameters = new ArrayList<>(); 3248 if (argIdent != null) { 3249 parameters.add(argIdent); 3250 } 3251 3252 3253 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); 3254 functionNode.setFlag(flags); 3255 if (computed) { 3256 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 3257 } 3258 lc.push(functionNode); 3259 3260 Block functionBody; 3261 try { 3262 functionBody = functionBody(functionNode); 3263 } finally { 3264 lc.pop(functionNode); 3265 } 3266 3267 3268 final FunctionNode function = createFunctionNode( 3269 functionNode, 3270 getSetToken, 3271 setNameNode, 3272 parameters, 3273 FunctionNode.Kind.SETTER, 3274 functionLine, 3275 functionBody); 3276 3277 return new PropertyFunction(propertyName, function, computed); 3278 } 3279 3280 private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) { 3281 final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false); 3282 final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName); 3283 3284 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; 3285 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null); 3286 functionNode.setFlag(flags); 3287 if (computed) { 3288 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 3289 } 3290 lc.push(functionNode); 3291 3292 try { 3293 final ParserContextBlockNode parameterBlock = newBlock(); 3294 final List<IdentNode> parameters; 3295 try { 3296 expect(LPAREN); 3297 parameters = formalParameterList(generator); 3298 functionNode.setParameters(parameters); 3299 expect(RPAREN); 3300 } finally { 3301 restoreBlock(parameterBlock); 3302 } 3303 3304 Block functionBody = functionBody(functionNode); 3305 3306 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); 3307 3308 final FunctionNode function = createFunctionNode( 3309 functionNode, 3310 methodToken, 3311 methodNameNode, 3312 parameters, 3313 functionKind, 3314 methodLine, 3315 functionBody); 3316 return new PropertyFunction(key, function, computed); 3317 } finally { 3318 lc.pop(functionNode); 3319 } 3320 } 3321 3322 private static class PropertyFunction { 3323 final Expression key; 3324 final FunctionNode functionNode; 3325 final boolean computed; 3326 3327 PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) { 3328 this.key = key; 3329 this.functionNode = function; 3330 this.computed = computed; 3331 } 3332 } 3333 3334 /** 3335 * LeftHandSideExpression : 3336 * NewExpression 3337 * CallExpression 3338 * 3339 * CallExpression : 3340 * MemberExpression Arguments 3341 * SuperCall 3342 * CallExpression Arguments 3343 * CallExpression [ Expression ] 3344 * CallExpression . IdentifierName 3345 * 3346 * SuperCall : 3347 * super Arguments 3348 * 3349 * See 11.2 3350 * 3351 * Parse left hand side expression. 3352 * @return Expression node. 3353 */ 3354 private Expression leftHandSideExpression() { 3355 int callLine = line; 3356 long callToken = token; 3357 3358 Expression lhs = memberExpression(); 3359 3360 if (type == LPAREN) { 3361 final List<Expression> arguments = optimizeList(argumentList()); 3362 3363 // Catch special functions. 3364 if (lhs instanceof IdentNode) { 3365 detectSpecialFunction((IdentNode)lhs); 3366 } 3367 3368 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 3369 } 3370 3371 loop: 3372 while (true) { 3373 // Capture token. 3374 callLine = line; 3375 callToken = token; 3376 3377 switch (type) { 3378 case LPAREN: { 3379 // Get NEW or FUNCTION arguments. 3380 final List<Expression> arguments = optimizeList(argumentList()); 3381 3382 // Create call node. 3383 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 3384 3385 break; 3386 } 3387 case LBRACKET: { 3388 next(); 3389 3390 // Get array index. 3391 final Expression rhs = expression(); 3392 3393 expect(RBRACKET); 3394 3395 // Create indexing node. 3396 lhs = new IndexNode(callToken, finish, lhs, rhs); 3397 3398 break; 3399 } 3400 case PERIOD: { 3401 next(); 3402 3403 final IdentNode property = getIdentifierName(); 3404 3405 // Create property access node. 3406 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 3407 3408 break; 3409 } 3410 case TEMPLATE: 3411 case TEMPLATE_HEAD: { 3412 // tagged template literal 3413 final List<Expression> arguments = templateLiteralArgumentList(); 3414 3415 // Create call node. 3416 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 3417 3418 break; 3419 } 3420 default: 3421 break loop; 3422 } 3423 } 3424 3425 return lhs; 3426 } 3427 3428 /** 3429 * NewExpression : 3430 * MemberExpression 3431 * new NewExpression 3432 * 3433 * See 11.2 3434 * 3435 * Parse new expression. 3436 * @return Expression node. 3437 */ 3438 private Expression newExpression() { 3439 final long newToken = token; 3440 // NEW is tested in caller. 3441 next(); 3442 3443 if (type == PERIOD && isES6()) { 3444 next(); 3445 if (type == IDENT && "target".equals(getValue())) { 3446 if (lc.getCurrentFunction().isProgram()) { 3447 throw error(AbstractParser.message("new.target.in.function"), token); 3448 } 3449 next(); 3450 markNewTarget(lc); 3451 return new IdentNode(newToken, finish, "new.target"); 3452 } else { 3453 throw error(AbstractParser.message("expected.target"), token); 3454 } 3455 } 3456 3457 // Get function base. 3458 final int callLine = line; 3459 final Expression constructor = memberExpression(); 3460 if (constructor == null) { 3461 return null; 3462 } 3463 // Get arguments. 3464 ArrayList<Expression> arguments; 3465 3466 // Allow for missing arguments. 3467 if (type == LPAREN) { 3468 arguments = argumentList(); 3469 } else { 3470 arguments = new ArrayList<>(); 3471 } 3472 3473 // Nashorn extension: This is to support the following interface implementation 3474 // syntax: 3475 // 3476 // var r = new java.lang.Runnable() { 3477 // run: function() { println("run"); } 3478 // }; 3479 // 3480 // The object literal following the "new Constructor()" expression 3481 // is passed as an additional (last) argument to the constructor. 3482 if (!env._no_syntax_extensions && type == LBRACE) { 3483 arguments.add(objectLiteral()); 3484 } 3485 3486 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 3487 3488 return new UnaryNode(newToken, callNode); 3489 } 3490 3491 /** 3492 * MemberExpression : 3493 * PrimaryExpression 3494 * FunctionExpression 3495 * ClassExpression 3496 * GeneratorExpression 3497 * MemberExpression [ Expression ] 3498 * MemberExpression . IdentifierName 3499 * MemberExpression TemplateLiteral 3500 * SuperProperty 3501 * MetaProperty 3502 * new MemberExpression Arguments 3503 * 3504 * SuperProperty : 3505 * super [ Expression ] 3506 * super . IdentifierName 3507 * 3508 * MetaProperty : 3509 * NewTarget 3510 * 3511 * Parse member expression. 3512 * @return Expression node. 3513 */ 3514 @SuppressWarnings("fallthrough") 3515 private Expression memberExpression() { 3516 // Prepare to build operation. 3517 Expression lhs; 3518 boolean isSuper = false; 3519 3520 switch (type) { 3521 case NEW: 3522 // Get new expression. 3523 lhs = newExpression(); 3524 break; 3525 3526 case FUNCTION: 3527 // Get function expression. 3528 lhs = functionExpression(false, false); 3529 break; 3530 3531 case CLASS: 3532 if (isES6()) { 3533 lhs = classExpression(false); 3534 break; 3535 } else { 3536 // fall through 3537 } 3538 3539 case SUPER: 3540 if (isES6()) { 3541 final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction(); 3542 if (currentFunction.isMethod()) { 3543 long identToken = Token.recast(token, IDENT); 3544 next(); 3545 lhs = createIdentNode(identToken, finish, SUPER.getName()); 3546 3547 switch (type) { 3548 case LBRACKET: 3549 case PERIOD: 3550 getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER); 3551 isSuper = true; 3552 break; 3553 case LPAREN: 3554 if (currentFunction.isSubclassConstructor()) { 3555 lhs = ((IdentNode)lhs).setIsDirectSuper(); 3556 break; 3557 } else { 3558 // fall through to throw error 3559 } 3560 default: 3561 throw error(AbstractParser.message("invalid.super"), identToken); 3562 } 3563 break; 3564 } else { 3565 // fall through 3566 } 3567 } else { 3568 // fall through 3569 } 3570 3571 default: 3572 // Get primary expression. 3573 lhs = primaryExpression(); 3574 break; 3575 } 3576 3577 loop: 3578 while (true) { 3579 // Capture token. 3580 final long callToken = token; 3581 3582 switch (type) { 3583 case LBRACKET: { 3584 next(); 3585 3586 // Get array index. 3587 final Expression index = expression(); 3588 3589 expect(RBRACKET); 3590 3591 // Create indexing node. 3592 lhs = new IndexNode(callToken, finish, lhs, index); 3593 3594 if (isSuper) { 3595 isSuper = false; 3596 lhs = ((BaseNode) lhs).setIsSuper(); 3597 } 3598 3599 break; 3600 } 3601 case PERIOD: { 3602 if (lhs == null) { 3603 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3604 } 3605 3606 next(); 3607 3608 final IdentNode property = getIdentifierName(); 3609 3610 // Create property access node. 3611 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 3612 3613 if (isSuper) { 3614 isSuper = false; 3615 lhs = ((BaseNode) lhs).setIsSuper(); 3616 } 3617 3618 break; 3619 } 3620 case TEMPLATE: 3621 case TEMPLATE_HEAD: { 3622 // tagged template literal 3623 final int callLine = line; 3624 final List<Expression> arguments = templateLiteralArgumentList(); 3625 3626 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 3627 3628 break; 3629 } 3630 default: 3631 break loop; 3632 } 3633 } 3634 3635 return lhs; 3636 } 3637 3638 /** 3639 * Arguments : 3640 * ( ) 3641 * ( ArgumentList ) 3642 * 3643 * ArgumentList : 3644 * AssignmentExpression 3645 * ... AssignmentExpression 3646 * ArgumentList , AssignmentExpression 3647 * ArgumentList , ... AssignmentExpression 3648 * 3649 * See 11.2 3650 * 3651 * Parse function call arguments. 3652 * @return Argument list. 3653 */ 3654 private ArrayList<Expression> argumentList() { 3655 // Prepare to accumulate list of arguments. 3656 final ArrayList<Expression> nodeList = new ArrayList<>(); 3657 // LPAREN tested in caller. 3658 next(); 3659 3660 // Track commas. 3661 boolean first = true; 3662 3663 while (type != RPAREN) { 3664 // Comma prior to every argument except the first. 3665 if (!first) { 3666 expect(COMMARIGHT); 3667 } else { 3668 first = false; 3669 } 3670 3671 long spreadToken = 0; 3672 if (type == ELLIPSIS && isES6()) { 3673 spreadToken = token; 3674 next(); 3675 } 3676 3677 // Get argument expression. 3678 Expression expression = assignmentExpression(false); 3679 if (spreadToken != 0) { 3680 expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression); 3681 } 3682 nodeList.add(expression); 3683 } 3684 3685 expect(RPAREN); 3686 return nodeList; 3687 } 3688 3689 private static <T> List<T> optimizeList(final ArrayList<T> list) { 3690 switch(list.size()) { 3691 case 0: { 3692 return Collections.emptyList(); 3693 } 3694 case 1: { 3695 return Collections.singletonList(list.get(0)); 3696 } 3697 default: { 3698 list.trimToSize(); 3699 return list; 3700 } 3701 } 3702 } 3703 3704 /** 3705 * FunctionDeclaration : 3706 * function Identifier ( FormalParameterList? ) { FunctionBody } 3707 * 3708 * FunctionExpression : 3709 * function Identifier? ( FormalParameterList? ) { FunctionBody } 3710 * 3711 * See 13 3712 * 3713 * Parse function declaration. 3714 * @param isStatement True if for is a statement. 3715 * 3716 * @return Expression node. 3717 */ 3718 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 3719 final long functionToken = token; 3720 final int functionLine = line; 3721 // FUNCTION is tested in caller. 3722 assert type == FUNCTION; 3723 next(); 3724 3725 boolean generator = false; 3726 if (type == MUL && isES6()) { 3727 generator = true; 3728 next(); 3729 } 3730 3731 IdentNode name = null; 3732 3733 if (isBindingIdentifier()) { 3734 if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) { 3735 // 12.1.1 Early SyntaxError if: 3736 // GeneratorExpression with BindingIdentifier yield 3737 // HoistableDeclaration with BindingIdentifier yield in generator function body 3738 expect(IDENT); 3739 } 3740 name = getIdent(); 3741 verifyStrictIdent(name, "function name"); 3742 } else if (isStatement) { 3743 // Nashorn extension: anonymous function statements. 3744 // Do not allow anonymous function statement if extensions 3745 // are now allowed. But if we are reparsing then anon function 3746 // statement is possible - because it was used as function 3747 // expression in surrounding code. 3748 if (env._no_syntax_extensions && reparsedFunction == null) { 3749 expect(IDENT); 3750 } 3751 } 3752 3753 // name is null, generate anonymous name 3754 boolean isAnonymous = false; 3755 if (name == null) { 3756 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); 3757 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 3758 isAnonymous = true; 3759 } 3760 3761 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL; 3762 List<IdentNode> parameters = Collections.emptyList(); 3763 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters); 3764 lc.push(functionNode); 3765 3766 Block functionBody = null; 3767 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" 3768 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". 3769 hideDefaultName(); 3770 try { 3771 final ParserContextBlockNode parameterBlock = newBlock(); 3772 try { 3773 expect(LPAREN); 3774 parameters = formalParameterList(generator); 3775 functionNode.setParameters(parameters); 3776 expect(RPAREN); 3777 } finally { 3778 restoreBlock(parameterBlock); 3779 } 3780 3781 functionBody = functionBody(functionNode); 3782 3783 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); 3784 } finally { 3785 defaultNames.pop(); 3786 lc.pop(functionNode); 3787 } 3788 3789 if (isStatement) { 3790 if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) { 3791 functionNode.setFlag(FunctionNode.IS_DECLARED); 3792 } else if (isStrictMode) { 3793 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 3794 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 3795 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 3796 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 3797 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 3798 } 3799 if (isArguments(name)) { 3800 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); 3801 } 3802 } 3803 3804 if (isAnonymous) { 3805 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 3806 } 3807 3808 verifyParameterList(parameters, functionNode); 3809 3810 final FunctionNode function = createFunctionNode( 3811 functionNode, 3812 functionToken, 3813 name, 3814 parameters, 3815 functionKind, 3816 functionLine, 3817 functionBody); 3818 3819 if (isStatement) { 3820 if (isAnonymous) { 3821 appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function)); 3822 return function; 3823 } 3824 3825 // mark ES6 block functions as lexically scoped 3826 final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; 3827 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); 3828 if (topLevel) { 3829 functionDeclarations.add(varNode); 3830 } else if (useBlockScope()) { 3831 prependStatement(varNode); // Hoist to beginning of current block 3832 } else { 3833 appendStatement(varNode); 3834 } 3835 } 3836 3837 return function; 3838 } 3839 3840 private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) { 3841 final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding(); 3842 if (duplicateParameter != null) { 3843 if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) { 3844 throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken()); 3845 } 3846 3847 final int arity = parameters.size(); 3848 final HashSet<String> parametersSet = new HashSet<>(arity); 3849 3850 for (int i = arity - 1; i >= 0; i--) { 3851 final IdentNode parameter = parameters.get(i); 3852 String parameterName = parameter.getName(); 3853 3854 if (parametersSet.contains(parameterName)) { 3855 // redefinition of parameter name, rename in non-strict mode 3856 parameterName = functionNode.uniqueName(parameterName); 3857 final long parameterToken = parameter.getToken(); 3858 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 3859 } 3860 parametersSet.add(parameterName); 3861 } 3862 } 3863 } 3864 3865 private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) { 3866 assert functionBody.isFunctionBody(); 3867 if (!parameterBlock.getStatements().isEmpty()) { 3868 parameterBlock.appendStatement(new BlockStatement(functionBody)); 3869 return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements()); 3870 } 3871 return functionBody; 3872 } 3873 3874 private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { 3875 final String defaultFunctionName = getDefaultFunctionName(); 3876 if (isValidIdentifier(defaultFunctionName)) { 3877 if (isStatement) { 3878 // The name will be used as the LHS of a symbol assignment. We add the anonymous function 3879 // prefix to ensure that it can't clash with another variable. 3880 return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; 3881 } 3882 return defaultFunctionName; 3883 } 3884 return ANON_FUNCTION_PREFIX.symbolName() + functionLine; 3885 } 3886 3887 private static boolean isValidIdentifier(final String name) { 3888 if (name == null || name.isEmpty()) { 3889 return false; 3890 } 3891 if (!Character.isJavaIdentifierStart(name.charAt(0))) { 3892 return false; 3893 } 3894 for (int i = 1; i < name.length(); ++i) { 3895 if (!Character.isJavaIdentifierPart(name.charAt(i))) { 3896 return false; 3897 } 3898 } 3899 return true; 3900 } 3901 3902 private String getDefaultFunctionName() { 3903 if (!defaultNames.isEmpty()) { 3904 final Object nameExpr = defaultNames.peek(); 3905 if (nameExpr instanceof PropertyKey) { 3906 markDefaultNameUsed(); 3907 return ((PropertyKey)nameExpr).getPropertyName(); 3908 } else if (nameExpr instanceof AccessNode) { 3909 markDefaultNameUsed(); 3910 return ((AccessNode)nameExpr).getProperty(); 3911 } 3912 } 3913 return null; 3914 } 3915 3916 private void markDefaultNameUsed() { 3917 defaultNames.pop(); 3918 hideDefaultName(); 3919 } 3920 3921 private void hideDefaultName() { 3922 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 3923 // from. Can't be null 3924 defaultNames.push(""); 3925 } 3926 3927 /** 3928 * FormalParameterList : 3929 * Identifier 3930 * FormalParameterList , Identifier 3931 * 3932 * See 13 3933 * 3934 * Parse function parameter list. 3935 * @return List of parameter nodes. 3936 */ 3937 private List<IdentNode> formalParameterList(final boolean yield) { 3938 return formalParameterList(RPAREN, yield); 3939 } 3940 3941 /** 3942 * Same as the other method of the same name - except that the end 3943 * token type expected is passed as argument to this method. 3944 * 3945 * FormalParameterList : 3946 * Identifier 3947 * FormalParameterList , Identifier 3948 * 3949 * See 13 3950 * 3951 * Parse function parameter list. 3952 * @return List of parameter nodes. 3953 */ 3954 private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) { 3955 // Prepare to gather parameters. 3956 final ArrayList<IdentNode> parameters = new ArrayList<>(); 3957 // Track commas. 3958 boolean first = true; 3959 3960 while (type != endType) { 3961 // Comma prior to every argument except the first. 3962 if (!first) { 3963 expect(COMMARIGHT); 3964 } else { 3965 first = false; 3966 } 3967 3968 boolean restParameter = false; 3969 if (type == ELLIPSIS && isES6()) { 3970 next(); 3971 restParameter = true; 3972 } 3973 3974 if (type == YIELD && yield) { 3975 expect(IDENT); 3976 } 3977 3978 final long paramToken = token; 3979 final int paramLine = line; 3980 final String contextString = "function parameter"; 3981 IdentNode ident; 3982 if (isBindingIdentifier() || restParameter || !isES6()) { 3983 ident = bindingIdentifier(contextString); 3984 3985 if (restParameter) { 3986 ident = ident.setIsRestParameter(); 3987 // rest parameter must be last 3988 expectDontAdvance(endType); 3989 parameters.add(ident); 3990 break; 3991 } else if (type == ASSIGN && isES6()) { 3992 next(); 3993 ident = ident.setIsDefaultParameter(); 3994 3995 if (type == YIELD && yield) { 3996 // error: yield in default expression 3997 expect(IDENT); 3998 } 3999 4000 // default parameter 4001 Expression initializer = assignmentExpression(false); 4002 4003 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4004 if (currentFunction != null) { 4005 // desugar to: param = (param === undefined) ? initializer : param; 4006 // possible alternative: if (param === undefined) param = initializer; 4007 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); 4008 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); 4009 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); 4010 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); 4011 } 4012 } 4013 4014 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4015 if (currentFunction != null) { 4016 currentFunction.addParameterBinding(ident); 4017 if (ident.isRestParameter() || ident.isDefaultParameter()) { 4018 currentFunction.setSimpleParameterList(false); 4019 } 4020 } 4021 } else { 4022 final Expression pattern = bindingPattern(); 4023 // Introduce synthetic temporary parameter to capture the object to be destructured. 4024 ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter(); 4025 verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString); 4026 4027 Expression value = ident; 4028 if (type == ASSIGN) { 4029 next(); 4030 ident = ident.setIsDefaultParameter(); 4031 4032 // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param 4033 Expression initializer = assignmentExpression(false); 4034 // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list) 4035 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); 4036 value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); 4037 } 4038 4039 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4040 if (currentFunction != null) { 4041 // destructuring assignment 4042 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value); 4043 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); 4044 } 4045 } 4046 parameters.add(ident); 4047 } 4048 4049 parameters.trimToSize(); 4050 return parameters; 4051 } 4052 4053 private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) { 4054 verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() { 4055 public void accept(IdentNode identNode) { 4056 verifyIdent(identNode, contextString); 4057 4058 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4059 if (currentFunction != null) { 4060 // declare function-scope variables for destructuring bindings 4061 lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null)); 4062 // detect duplicate bounds names in parameter list 4063 currentFunction.addParameterBinding(identNode); 4064 currentFunction.setSimpleParameterList(false); 4065 } 4066 } 4067 }); 4068 } 4069 4070 /** 4071 * FunctionBody : 4072 * SourceElements? 4073 * 4074 * See 13 4075 * 4076 * Parse function body. 4077 * @return function node (body.) 4078 */ 4079 private Block functionBody(final ParserContextFunctionNode functionNode) { 4080 long lastToken = 0L; 4081 ParserContextBlockNode body = null; 4082 final long bodyToken = token; 4083 Block functionBody; 4084 int bodyFinish = 0; 4085 4086 final boolean parseBody; 4087 Object endParserState = null; 4088 try { 4089 // Create a new function block. 4090 body = newBlock(); 4091 if (env._debug_scopes) { 4092 // debug scope options forces everything to be in scope 4093 markEval(lc); 4094 } 4095 assert functionNode != null; 4096 final int functionId = functionNode.getId(); 4097 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 4098 // Nashorn extension: expression closures 4099 if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) { 4100 /* 4101 * Example: 4102 * 4103 * function square(x) x * x; 4104 * print(square(3)); 4105 */ 4106 4107 // just expression as function body 4108 final Expression expr = assignmentExpression(false); 4109 lastToken = previousToken; 4110 functionNode.setLastToken(previousToken); 4111 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 4112 // EOL uses length field to store the line number 4113 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 4114 // Only create the return node if we aren't skipping nested functions. Note that we aren't 4115 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 4116 // they don't end with a single well known token, so it'd be very hard to get correctly (see 4117 // the note below for reasoning on skipping happening before instead of after RBRACE for 4118 // details). 4119 if (parseBody) { 4120 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 4121 appendStatement(returnNode); 4122 } 4123 // bodyFinish = finish; 4124 } else { 4125 expectDontAdvance(LBRACE); 4126 if (parseBody || !skipFunctionBody(functionNode)) { 4127 next(); 4128 // Gather the function elements. 4129 final List<Statement> prevFunctionDecls = functionDeclarations; 4130 functionDeclarations = new ArrayList<>(); 4131 try { 4132 sourceElements(false); 4133 addFunctionDeclarations(functionNode); 4134 } finally { 4135 functionDeclarations = prevFunctionDecls; 4136 } 4137 4138 lastToken = token; 4139 if (parseBody) { 4140 // Since the lexer can read ahead and lexify some number of tokens in advance and have 4141 // them buffered in the TokenStream, we need to produce a lexer state as it was just 4142 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 4143 // ahead) state. 4144 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 4145 4146 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 4147 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 4148 // state after it. The reason is that RBRACE is a well-known token that we can expect and 4149 // will never involve us getting into a weird lexer state, and as such is a great reparse 4150 // point. Typical example of a weird lexer state after RBRACE would be: 4151 // function this_is_skipped() { ... } "use strict"; 4152 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 4153 // of compensating for the possibility of a string literal (or similar) after RBRACE, 4154 // we'll rather just restart parsing from this well-known, friendly token instead. 4155 } 4156 } 4157 bodyFinish = finish; 4158 functionNode.setLastToken(token); 4159 expect(RBRACE); 4160 } 4161 } finally { 4162 restoreBlock(body); 4163 } 4164 4165 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 4166 4167 if (parseBody) { 4168 functionNode.setEndParserState(endParserState); 4169 } else if (!body.getStatements().isEmpty()){ 4170 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 4171 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 4172 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 4173 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 4174 // nested bodies early if we were supposed to skip 'em. 4175 body.setStatements(Collections.<Statement>emptyList()); 4176 } 4177 4178 if (reparsedFunction != null) { 4179 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 4180 // eagerly parsed the code. We're doing it because some flags would be set based on the 4181 // content of the function, or even content of its nested functions, most of which are normally 4182 // skipped during an on-demand compilation. 4183 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 4184 if (data != null) { 4185 // Data can be null if when we originally parsed the file, we removed the function declaration 4186 // as it was dead code. 4187 functionNode.setFlag(data.getFunctionFlags()); 4188 // This compensates for missing markEval() in case the function contains an inner function 4189 // that contains eval(), that now we didn't discover since we skipped the inner function. 4190 if (functionNode.hasNestedEval()) { 4191 assert functionNode.hasScopeBlock(); 4192 body.setFlag(Block.NEEDS_SCOPE); 4193 } 4194 } 4195 } 4196 functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements()); 4197 return functionBody; 4198 } 4199 4200 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { 4201 if (reparsedFunction == null) { 4202 // Not reparsing, so don't skip any function body. 4203 return false; 4204 } 4205 // Skip to the RBRACE of this function, and continue parsing from there. 4206 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 4207 if (data == null) { 4208 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 4209 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 4210 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 4211 return false; 4212 } 4213 final ParserState parserState = (ParserState)data.getEndParserState(); 4214 assert parserState != null; 4215 4216 if (k < stream.last() && start < parserState.position && parserState.position <= Token.descPosition(stream.get(stream.last()))) { 4217 // RBRACE is already in the token stream, so fast forward to it 4218 for (; k < stream.last(); k++) { 4219 final long nextToken = stream.get(k + 1); 4220 if (Token.descPosition(nextToken) == parserState.position && Token.descType(nextToken) == RBRACE) { 4221 token = stream.get(k); 4222 type = Token.descType(token); 4223 next(); 4224 assert type == RBRACE && start == parserState.position; 4225 return true; 4226 } 4227 } 4228 } 4229 4230 stream.reset(); 4231 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6); 4232 line = parserState.line; 4233 linePosition = parserState.linePosition; 4234 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 4235 // the RBRACE. 4236 type = SEMICOLON; 4237 scanFirstToken(); 4238 4239 return true; 4240 } 4241 4242 /** 4243 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 4244 * for resuming parsing after skipping a function body. 4245 */ 4246 private static class ParserState implements Serializable { 4247 private final int position; 4248 private final int line; 4249 private final int linePosition; 4250 4251 private static final long serialVersionUID = -2382565130754093694L; 4252 4253 ParserState(final int position, final int line, final int linePosition) { 4254 this.position = position; 4255 this.line = line; 4256 this.linePosition = linePosition; 4257 } 4258 4259 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) { 4260 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true); 4261 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 4262 return newLexer; 4263 } 4264 } 4265 4266 private void printAST(final FunctionNode functionNode) { 4267 if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) { 4268 env.getErr().println(new ASTWriter(functionNode)); 4269 } 4270 4271 if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) { 4272 env.getErr().println(new PrintVisitor(functionNode, true, false)); 4273 } 4274 } 4275 4276 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { 4277 VarNode lastDecl = null; 4278 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 4279 Statement decl = functionDeclarations.get(i); 4280 if (lastDecl == null && decl instanceof VarNode) { 4281 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 4282 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); 4283 } 4284 prependStatement(decl); 4285 } 4286 } 4287 4288 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 4289 if (earlyError) { 4290 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 4291 } 4292 final ArrayList<Expression> args = new ArrayList<>(); 4293 args.add(lhs); 4294 if (rhs == null) { 4295 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 4296 } else { 4297 args.add(rhs); 4298 } 4299 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 4300 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 4301 } 4302 4303 /** 4304 * PostfixExpression : 4305 * LeftHandSideExpression 4306 * LeftHandSideExpression ++ // [no LineTerminator here] 4307 * LeftHandSideExpression -- // [no LineTerminator here] 4308 * 4309 * See 11.3 4310 * 4311 * UnaryExpression : 4312 * PostfixExpression 4313 * delete UnaryExpression 4314 * void UnaryExpression 4315 * typeof UnaryExpression 4316 * ++ UnaryExpression 4317 * -- UnaryExpression 4318 * + UnaryExpression 4319 * - UnaryExpression 4320 * ~ UnaryExpression 4321 * ! UnaryExpression 4322 * 4323 * See 11.4 4324 * 4325 * Parse unary expression. 4326 * @return Expression node. 4327 */ 4328 private Expression unaryExpression() { 4329 final int unaryLine = line; 4330 final long unaryToken = token; 4331 4332 switch (type) { 4333 case DELETE: { 4334 next(); 4335 final Expression expr = unaryExpression(); 4336 if (expr instanceof BaseNode || expr instanceof IdentNode) { 4337 return new UnaryNode(unaryToken, expr); 4338 } 4339 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 4340 return LiteralNode.newInstance(unaryToken, finish, true); 4341 } 4342 case VOID: 4343 case TYPEOF: 4344 case ADD: 4345 case SUB: 4346 case BIT_NOT: 4347 case NOT: 4348 next(); 4349 final Expression expr = unaryExpression(); 4350 return new UnaryNode(unaryToken, expr); 4351 4352 case INCPREFIX: 4353 case DECPREFIX: 4354 final TokenType opType = type; 4355 next(); 4356 4357 final Expression lhs = leftHandSideExpression(); 4358 // ++, -- without operand.. 4359 if (lhs == null) { 4360 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 4361 } 4362 4363 return verifyIncDecExpression(unaryToken, opType, lhs, false); 4364 4365 default: 4366 break; 4367 } 4368 4369 Expression expression = leftHandSideExpression(); 4370 4371 if (last != EOL) { 4372 switch (type) { 4373 case INCPREFIX: 4374 case DECPREFIX: 4375 final long opToken = token; 4376 final TokenType opType = type; 4377 final Expression lhs = expression; 4378 // ++, -- without operand.. 4379 if (lhs == null) { 4380 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 4381 } 4382 next(); 4383 4384 return verifyIncDecExpression(opToken, opType, lhs, true); 4385 default: 4386 break; 4387 } 4388 } 4389 4390 if (expression == null) { 4391 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 4392 } 4393 4394 return expression; 4395 } 4396 4397 private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) { 4398 assert lhs != null; 4399 4400 if (!(lhs instanceof AccessNode || 4401 lhs instanceof IndexNode || 4402 lhs instanceof IdentNode)) { 4403 return referenceError(lhs, null, env._early_lvalue_error); 4404 } 4405 4406 if (lhs instanceof IdentNode) { 4407 if (!checkIdentLValue((IdentNode)lhs)) { 4408 return referenceError(lhs, null, false); 4409 } 4410 verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 4411 } 4412 4413 return incDecExpression(unaryToken, opType, lhs, isPostfix); 4414 } 4415 4416 /** 4417 * {@code 4418 * MultiplicativeExpression : 4419 * UnaryExpression 4420 * MultiplicativeExpression * UnaryExpression 4421 * MultiplicativeExpression / UnaryExpression 4422 * MultiplicativeExpression % UnaryExpression 4423 * 4424 * See 11.5 4425 * 4426 * AdditiveExpression : 4427 * MultiplicativeExpression 4428 * AdditiveExpression + MultiplicativeExpression 4429 * AdditiveExpression - MultiplicativeExpression 4430 * 4431 * See 11.6 4432 * 4433 * ShiftExpression : 4434 * AdditiveExpression 4435 * ShiftExpression << AdditiveExpression 4436 * ShiftExpression >> AdditiveExpression 4437 * ShiftExpression >>> AdditiveExpression 4438 * 4439 * See 11.7 4440 * 4441 * RelationalExpression : 4442 * ShiftExpression 4443 * RelationalExpression < ShiftExpression 4444 * RelationalExpression > ShiftExpression 4445 * RelationalExpression <= ShiftExpression 4446 * RelationalExpression >= ShiftExpression 4447 * RelationalExpression instanceof ShiftExpression 4448 * RelationalExpression in ShiftExpression // if !noIf 4449 * 4450 * See 11.8 4451 * 4452 * RelationalExpression 4453 * EqualityExpression == RelationalExpression 4454 * EqualityExpression != RelationalExpression 4455 * EqualityExpression === RelationalExpression 4456 * EqualityExpression !== RelationalExpression 4457 * 4458 * See 11.9 4459 * 4460 * BitwiseANDExpression : 4461 * EqualityExpression 4462 * BitwiseANDExpression & EqualityExpression 4463 * 4464 * BitwiseXORExpression : 4465 * BitwiseANDExpression 4466 * BitwiseXORExpression ^ BitwiseANDExpression 4467 * 4468 * BitwiseORExpression : 4469 * BitwiseXORExpression 4470 * BitwiseORExpression | BitwiseXORExpression 4471 * 4472 * See 11.10 4473 * 4474 * LogicalANDExpression : 4475 * BitwiseORExpression 4476 * LogicalANDExpression && BitwiseORExpression 4477 * 4478 * LogicalORExpression : 4479 * LogicalANDExpression 4480 * LogicalORExpression || LogicalANDExpression 4481 * 4482 * See 11.11 4483 * 4484 * ConditionalExpression : 4485 * LogicalORExpression 4486 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 4487 * 4488 * See 11.12 4489 * 4490 * AssignmentExpression : 4491 * ConditionalExpression 4492 * LeftHandSideExpression AssignmentOperator AssignmentExpression 4493 * 4494 * AssignmentOperator : 4495 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 4496 * 4497 * See 11.13 4498 * 4499 * Expression : 4500 * AssignmentExpression 4501 * Expression , AssignmentExpression 4502 * 4503 * See 11.14 4504 * } 4505 * 4506 * Parse expression. 4507 * @return Expression node. 4508 */ 4509 protected Expression expression() { 4510 // This method is protected so that subclass can get details 4511 // at expression start point! 4512 4513 // Include commas in expression parsing. 4514 return expression(false); 4515 } 4516 4517 private Expression expression(final boolean noIn) { 4518 Expression assignmentExpression = assignmentExpression(noIn); 4519 while (type == COMMARIGHT) { 4520 long commaToken = token; 4521 next(); 4522 4523 boolean rhsRestParameter = false; 4524 if (type == ELLIPSIS && isES6()) { 4525 // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error). 4526 // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead. 4527 if (isRestParameterEndOfArrowFunctionParameterList()) { 4528 next(); 4529 rhsRestParameter = true; 4530 } 4531 } 4532 4533 Expression rhs = assignmentExpression(noIn); 4534 4535 if (rhsRestParameter) { 4536 rhs = ((IdentNode)rhs).setIsRestParameter(); 4537 // Our only valid move is to end Expression here and continue with ArrowFunction. 4538 // We've already checked that this is the parameter list of an arrow function (see above). 4539 // RPAREN is next, so we'll finish the binary expression and drop out of the loop. 4540 assert type == RPAREN; 4541 } 4542 4543 assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs); 4544 } 4545 return assignmentExpression; 4546 } 4547 4548 private Expression expression(final int minPrecedence, final boolean noIn) { 4549 return expression(unaryExpression(), minPrecedence, noIn); 4550 } 4551 4552 private JoinPredecessorExpression joinPredecessorExpression() { 4553 return new JoinPredecessorExpression(expression()); 4554 } 4555 4556 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 4557 // Get the precedence of the next operator. 4558 int precedence = type.getPrecedence(); 4559 Expression lhs = exprLhs; 4560 4561 // While greater precedence. 4562 while (type.isOperator(noIn) && precedence >= minPrecedence) { 4563 // Capture the operator token. 4564 final long op = token; 4565 4566 if (type == TERNARY) { 4567 // Skip operator. 4568 next(); 4569 4570 // Pass expression. Middle expression of a conditional expression can be a "in" 4571 // expression - even in the contexts where "in" is not permitted. 4572 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 4573 4574 expect(COLON); 4575 4576 // Fail expression. 4577 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 4578 4579 // Build up node. 4580 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 4581 } else { 4582 // Skip operator. 4583 next(); 4584 4585 // Get the next primary expression. 4586 Expression rhs; 4587 final boolean isAssign = Token.descType(op) == ASSIGN; 4588 if(isAssign) { 4589 defaultNames.push(lhs); 4590 } 4591 try { 4592 rhs = unaryExpression(); 4593 // Get precedence of next operator. 4594 int nextPrecedence = type.getPrecedence(); 4595 4596 // Subtask greater precedence. 4597 while (type.isOperator(noIn) && 4598 (nextPrecedence > precedence || 4599 nextPrecedence == precedence && !type.isLeftAssociative())) { 4600 rhs = expression(rhs, nextPrecedence, noIn); 4601 nextPrecedence = type.getPrecedence(); 4602 } 4603 } finally { 4604 if(isAssign) { 4605 defaultNames.pop(); 4606 } 4607 } 4608 lhs = verifyAssignment(op, lhs, rhs); 4609 } 4610 4611 precedence = type.getPrecedence(); 4612 } 4613 4614 return lhs; 4615 } 4616 4617 /** 4618 * AssignmentExpression. 4619 * 4620 * AssignmentExpression[In, Yield] : 4621 * ConditionalExpression[?In, ?Yield] 4622 * [+Yield] YieldExpression[?In] 4623 * ArrowFunction[?In, ?Yield] 4624 * LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield] 4625 * LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield] 4626 */ 4627 protected Expression assignmentExpression(final boolean noIn) { 4628 // This method is protected so that subclass can get details 4629 // at assignment expression start point! 4630 4631 if (type == YIELD && inGeneratorFunction() && isES6()) { 4632 return yieldExpression(noIn); 4633 } 4634 4635 final long startToken = token; 4636 final int startLine = line; 4637 final Expression exprLhs = conditionalExpression(noIn); 4638 4639 if (type == ARROW && isES6()) { 4640 if (checkNoLineTerminator()) { 4641 final Expression paramListExpr; 4642 if (exprLhs instanceof ExpressionList) { 4643 paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0)); 4644 } else { 4645 paramListExpr = exprLhs; 4646 } 4647 return arrowFunction(startToken, startLine, paramListExpr); 4648 } 4649 } 4650 assert !(exprLhs instanceof ExpressionList); 4651 4652 if (isAssignmentOperator(type)) { 4653 final boolean isAssign = type == ASSIGN; 4654 if (isAssign) { 4655 defaultNames.push(exprLhs); 4656 } 4657 try { 4658 final long assignToken = token; 4659 next(); 4660 final Expression exprRhs = assignmentExpression(noIn); 4661 return verifyAssignment(assignToken, exprLhs, exprRhs); 4662 } finally { 4663 if (isAssign) { 4664 defaultNames.pop(); 4665 } 4666 } 4667 } else { 4668 return exprLhs; 4669 } 4670 } 4671 4672 /** 4673 * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}? 4674 */ 4675 private static boolean isAssignmentOperator(TokenType type) { 4676 switch (type) { 4677 case ASSIGN: 4678 case ASSIGN_ADD: 4679 case ASSIGN_BIT_AND: 4680 case ASSIGN_BIT_OR: 4681 case ASSIGN_BIT_XOR: 4682 case ASSIGN_DIV: 4683 case ASSIGN_MOD: 4684 case ASSIGN_MUL: 4685 case ASSIGN_SAR: 4686 case ASSIGN_SHL: 4687 case ASSIGN_SHR: 4688 case ASSIGN_SUB: 4689 return true; 4690 } 4691 return false; 4692 } 4693 4694 /** 4695 * ConditionalExpression. 4696 */ 4697 private Expression conditionalExpression(boolean noIn) { 4698 return expression(TERNARY.getPrecedence(), noIn); 4699 } 4700 4701 /** 4702 * ArrowFunction. 4703 * 4704 * @param startToken start token of the ArrowParameters expression 4705 * @param functionLine start line of the arrow function 4706 * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list) 4707 */ 4708 private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) { 4709 // caller needs to check that there's no LineTerminator between parameter list and arrow 4710 assert type != ARROW || checkNoLineTerminator(); 4711 expect(ARROW); 4712 4713 final long functionToken = Token.recast(startToken, ARROW); 4714 final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), "=>:" + functionLine); 4715 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null); 4716 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 4717 4718 lc.push(functionNode); 4719 try { 4720 ParserContextBlockNode parameterBlock = newBlock(); 4721 final List<IdentNode> parameters; 4722 try { 4723 parameters = convertArrowFunctionParameterList(paramListExpr, functionLine); 4724 functionNode.setParameters(parameters); 4725 4726 if (!functionNode.isSimpleParameterList()) { 4727 markEvalInArrowParameterList(parameterBlock); 4728 } 4729 } finally { 4730 restoreBlock(parameterBlock); 4731 } 4732 Block functionBody = functionBody(functionNode); 4733 4734 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock); 4735 4736 verifyParameterList(parameters, functionNode); 4737 4738 final FunctionNode function = createFunctionNode( 4739 functionNode, 4740 functionToken, 4741 name, 4742 parameters, 4743 FunctionNode.Kind.ARROW, 4744 functionLine, 4745 functionBody); 4746 return function; 4747 } finally { 4748 lc.pop(functionNode); 4749 } 4750 } 4751 4752 private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) { 4753 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 4754 final ParserContextFunctionNode current = iter.next(); 4755 final ParserContextFunctionNode parent = iter.next(); 4756 4757 if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) { 4758 // we might have flagged has-eval in the parent function during parsing the parameter list, 4759 // if the parameter list contains eval; must tag arrow function as has-eval. 4760 for (final Statement st : parameterBlock.getStatements()) { 4761 st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 4762 @Override 4763 public boolean enterCallNode(final CallNode callNode) { 4764 if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) { 4765 current.setFlag(FunctionNode.HAS_EVAL); 4766 } 4767 return true; 4768 } 4769 }); 4770 } 4771 // TODO: function containing the arrow function should not be flagged has-eval 4772 } 4773 } 4774 4775 private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) { 4776 final List<IdentNode> parameters; 4777 if (paramListExpr == null) { 4778 // empty parameter list, i.e. () => 4779 parameters = Collections.emptyList(); 4780 } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) { 4781 parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine)); 4782 } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) { 4783 parameters = new ArrayList<>(); 4784 Expression car = paramListExpr; 4785 do { 4786 final Expression cdr = ((BinaryNode) car).rhs(); 4787 parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine)); 4788 car = ((BinaryNode) car).lhs(); 4789 } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT); 4790 parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine)); 4791 } else { 4792 throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken()); 4793 } 4794 return parameters; 4795 } 4796 4797 private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) { 4798 final String contextString = "function parameter"; 4799 if (param instanceof IdentNode) { 4800 IdentNode ident = (IdentNode)param; 4801 verifyStrictIdent(ident, contextString); 4802 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4803 if (currentFunction != null) { 4804 currentFunction.addParameterBinding(ident); 4805 } 4806 return ident; 4807 } 4808 4809 if (param.isTokenType(ASSIGN)) { 4810 Expression lhs = ((BinaryNode) param).lhs(); 4811 long paramToken = lhs.getToken(); 4812 Expression initializer = ((BinaryNode) param).rhs(); 4813 if (lhs instanceof IdentNode) { 4814 // default parameter 4815 IdentNode ident = (IdentNode) lhs; 4816 4817 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4818 if (currentFunction != null) { 4819 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); 4820 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); 4821 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value); 4822 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); 4823 4824 currentFunction.addParameterBinding(ident); 4825 currentFunction.setSimpleParameterList(false); 4826 } 4827 return ident; 4828 } else if (isDestructuringLhs(lhs)) { 4829 // binding pattern with initializer 4830 // Introduce synthetic temporary parameter to capture the object to be destructured. 4831 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter(); 4832 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); 4833 4834 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4835 if (currentFunction != null) { 4836 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish)); 4837 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident)); 4838 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value); 4839 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); 4840 } 4841 return ident; 4842 } 4843 } else if (isDestructuringLhs(param)) { 4844 // binding pattern 4845 long paramToken = param.getToken(); 4846 4847 // Introduce synthetic temporary parameter to capture the object to be destructured. 4848 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter(); 4849 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString); 4850 4851 ParserContextFunctionNode currentFunction = lc.getCurrentFunction(); 4852 if (currentFunction != null) { 4853 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident); 4854 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment)); 4855 } 4856 return ident; 4857 } 4858 throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken()); 4859 } 4860 4861 private boolean checkNoLineTerminator() { 4862 assert type == ARROW; 4863 if (last == RPAREN) { 4864 return true; 4865 } else if (last == IDENT) { 4866 return true; 4867 } 4868 for (int i = k - 1; i >= 0; i--) { 4869 TokenType t = T(i); 4870 switch (t) { 4871 case RPAREN: 4872 case IDENT: 4873 return true; 4874 case EOL: 4875 return false; 4876 case COMMENT: 4877 continue; 4878 default: 4879 if (t.getKind() == TokenKind.FUTURESTRICT) { 4880 return true; 4881 } 4882 return false; 4883 } 4884 } 4885 return false; 4886 } 4887 4888 /** 4889 * Peek ahead to see if what follows after the ellipsis is a rest parameter 4890 * at the end of an arrow function parameter list. 4891 */ 4892 private boolean isRestParameterEndOfArrowFunctionParameterList() { 4893 assert type == ELLIPSIS; 4894 // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT 4895 int i = 1; 4896 for (;;) { 4897 TokenType t = T(k + i++); 4898 if (t == IDENT) { 4899 break; 4900 } else if (t == EOL || t == COMMENT) { 4901 continue; 4902 } else { 4903 return false; 4904 } 4905 } 4906 for (;;) { 4907 TokenType t = T(k + i++); 4908 if (t == RPAREN) { 4909 break; 4910 } else if (t == EOL || t == COMMENT) { 4911 continue; 4912 } else { 4913 return false; 4914 } 4915 } 4916 for (;;) { 4917 TokenType t = T(k + i++); 4918 if (t == ARROW) { 4919 break; 4920 } else if (t == COMMENT) { 4921 continue; 4922 } else { 4923 return false; 4924 } 4925 } 4926 return true; 4927 } 4928 4929 /** 4930 * Parse an end of line. 4931 */ 4932 private void endOfLine() { 4933 switch (type) { 4934 case SEMICOLON: 4935 case EOL: 4936 next(); 4937 break; 4938 case RPAREN: 4939 case RBRACKET: 4940 case RBRACE: 4941 case EOF: 4942 break; 4943 default: 4944 if (last != EOL) { 4945 expect(SEMICOLON); 4946 } 4947 break; 4948 } 4949 } 4950 4951 /** 4952 * Parse untagged template literal as string concatenation. 4953 */ 4954 private Expression templateLiteral() { 4955 assert type == TEMPLATE || type == TEMPLATE_HEAD; 4956 final boolean noSubstitutionTemplate = type == TEMPLATE; 4957 long lastLiteralToken = token; 4958 LiteralNode<?> literal = getLiteral(); 4959 if (noSubstitutionTemplate) { 4960 return literal; 4961 } 4962 4963 Expression concat = literal; 4964 TokenType lastLiteralType; 4965 do { 4966 final Expression expression = expression(); 4967 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { 4968 throw error(AbstractParser.message("unterminated.template.expression"), token); 4969 } 4970 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, expression); 4971 lastLiteralType = type; 4972 lastLiteralToken = token; 4973 literal = getLiteral(); 4974 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, literal); 4975 } while (lastLiteralType == TEMPLATE_MIDDLE); 4976 return concat; 4977 } 4978 4979 /** 4980 * Parse tagged template literal as argument list. 4981 * @return argument list for a tag function call (template object, ...substitutions) 4982 */ 4983 private List<Expression> templateLiteralArgumentList() { 4984 assert type == TEMPLATE || type == TEMPLATE_HEAD; 4985 final ArrayList<Expression> argumentList = new ArrayList<>(); 4986 final ArrayList<Expression> rawStrings = new ArrayList<>(); 4987 final ArrayList<Expression> cookedStrings = new ArrayList<>(); 4988 argumentList.add(null); // filled at the end 4989 4990 final long templateToken = token; 4991 final boolean hasSubstitutions = type == TEMPLATE_HEAD; 4992 addTemplateLiteralString(rawStrings, cookedStrings); 4993 4994 if (hasSubstitutions) { 4995 TokenType lastLiteralType; 4996 do { 4997 final Expression expression = expression(); 4998 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) { 4999 throw error(AbstractParser.message("unterminated.template.expression"), token); 5000 } 5001 argumentList.add(expression); 5002 5003 lastLiteralType = type; 5004 addTemplateLiteralString(rawStrings, cookedStrings); 5005 } while (lastLiteralType == TEMPLATE_MIDDLE); 5006 } 5007 5008 final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings); 5009 final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings); 5010 final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray); 5011 argumentList.set(0, templateObject); 5012 return optimizeList(argumentList); 5013 } 5014 5015 private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, final ArrayList<Expression> cookedStrings) { 5016 final long stringToken = token; 5017 final String rawString = lexer.valueOfRawString(stringToken); 5018 final String cookedString = (String) getValue(); 5019 next(); 5020 rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString)); 5021 cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString)); 5022 } 5023 5024 5025 /** 5026 * Parse a module. 5027 * 5028 * Module : 5029 * ModuleBody? 5030 * 5031 * ModuleBody : 5032 * ModuleItemList 5033 */ 5034 private FunctionNode module(final String moduleName) { 5035 boolean oldStrictMode = isStrictMode; 5036 try { 5037 isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1) 5038 5039 // Make a pseudo-token for the script holding its start and length. 5040 int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish); 5041 final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart); 5042 final int functionLine = line; 5043 5044 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName); 5045 final ParserContextFunctionNode script = createParserContextFunctionNode( 5046 ident, 5047 functionToken, 5048 FunctionNode.Kind.MODULE, 5049 functionLine, 5050 Collections.<IdentNode>emptyList()); 5051 lc.push(script); 5052 5053 final ParserContextModuleNode module = new ParserContextModuleNode(moduleName); 5054 lc.push(module); 5055 5056 final ParserContextBlockNode body = newBlock(); 5057 5058 functionDeclarations = new ArrayList<>(); 5059 moduleBody(); 5060 addFunctionDeclarations(script); 5061 functionDeclarations = null; 5062 5063 restoreBlock(body); 5064 body.setFlag(Block.NEEDS_SCOPE); 5065 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements()); 5066 lc.pop(module); 5067 lc.pop(script); 5068 script.setLastToken(token); 5069 5070 expect(EOF); 5071 5072 script.setModule(module.createModule()); 5073 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody); 5074 } finally { 5075 isStrictMode = oldStrictMode; 5076 } 5077 } 5078 5079 /** 5080 * Parse module body. 5081 * 5082 * ModuleBody : 5083 * ModuleItemList 5084 * 5085 * ModuleItemList : 5086 * ModuleItem 5087 * ModuleItemList ModuleItem 5088 * 5089 * ModuleItem : 5090 * ImportDeclaration 5091 * ExportDeclaration 5092 * StatementListItem 5093 */ 5094 private void moduleBody() { 5095 loop: 5096 while (type != EOF) { 5097 switch (type) { 5098 case EOF: 5099 break loop; 5100 case IMPORT: 5101 importDeclaration(); 5102 break; 5103 case EXPORT: 5104 exportDeclaration(); 5105 break; 5106 default: 5107 // StatementListItem 5108 statement(true, false, false, false); 5109 break; 5110 } 5111 } 5112 } 5113 5114 5115 /** 5116 * Parse import declaration. 5117 * 5118 * ImportDeclaration : 5119 * import ImportClause FromClause ; 5120 * import ModuleSpecifier ; 5121 * ImportClause : 5122 * ImportedDefaultBinding 5123 * NameSpaceImport 5124 * NamedImports 5125 * ImportedDefaultBinding , NameSpaceImport 5126 * ImportedDefaultBinding , NamedImports 5127 * ImportedDefaultBinding : 5128 * ImportedBinding 5129 * ModuleSpecifier : 5130 * StringLiteral 5131 * ImportedBinding : 5132 * BindingIdentifier 5133 */ 5134 private void importDeclaration() { 5135 expect(IMPORT); 5136 final ParserContextModuleNode module = lc.getCurrentModule(); 5137 if (type == STRING || type == ESCSTRING) { 5138 // import ModuleSpecifier ; 5139 final String moduleSpecifier = (String) getValue(); 5140 next(); 5141 module.addModuleRequest(moduleSpecifier); 5142 } else { 5143 // import ImportClause FromClause ; 5144 List<Module.ImportEntry> importEntries; 5145 if (type == MUL) { 5146 importEntries = Collections.singletonList(nameSpaceImport()); 5147 } else if (type == LBRACE) { 5148 importEntries = namedImports(); 5149 } else if (isBindingIdentifier()) { 5150 // ImportedDefaultBinding 5151 final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding"); 5152 Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName()); 5153 5154 if (type == COMMARIGHT) { 5155 next(); 5156 importEntries = new ArrayList<>(); 5157 if (type == MUL) { 5158 importEntries.add(nameSpaceImport()); 5159 } else if (type == LBRACE) { 5160 importEntries.addAll(namedImports()); 5161 } else { 5162 throw error(AbstractParser.message("expected.named.import")); 5163 } 5164 } else { 5165 importEntries = Collections.singletonList(defaultImport); 5166 } 5167 } else { 5168 throw error(AbstractParser.message("expected.import")); 5169 } 5170 5171 final String moduleSpecifier = fromClause(); 5172 module.addModuleRequest(moduleSpecifier); 5173 for (int i = 0; i < importEntries.size(); i++) { 5174 module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier)); 5175 } 5176 } 5177 expect(SEMICOLON); 5178 } 5179 5180 /** 5181 * NameSpaceImport : 5182 * * as ImportedBinding 5183 * 5184 * @return imported binding identifier 5185 */ 5186 private Module.ImportEntry nameSpaceImport() { 5187 assert type == MUL; 5188 next(); 5189 final long asToken = token; 5190 final String as = (String) expectValue(IDENT); 5191 if (!"as".equals(as)) { 5192 throw error(AbstractParser.message("expected.as"), asToken); 5193 } 5194 final IdentNode localNameSpace = bindingIdentifier("ImportedBinding"); 5195 return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName()); 5196 } 5197 5198 /** 5199 * NamedImports : 5200 * { } 5201 * { ImportsList } 5202 * { ImportsList , } 5203 * ImportsList : 5204 * ImportSpecifier 5205 * ImportsList , ImportSpecifier 5206 * ImportSpecifier : 5207 * ImportedBinding 5208 * IdentifierName as ImportedBinding 5209 * ImportedBinding : 5210 * BindingIdentifier 5211 */ 5212 private List<Module.ImportEntry> namedImports() { 5213 assert type == LBRACE; 5214 next(); 5215 List<Module.ImportEntry> importEntries = new ArrayList<>(); 5216 while (type != RBRACE) { 5217 final boolean bindingIdentifier = isBindingIdentifier(); 5218 final long nameToken = token; 5219 final IdentNode importName = getIdentifierName(); 5220 if (type == IDENT && "as".equals(getValue())) { 5221 next(); 5222 final IdentNode localName = bindingIdentifier("ImportedBinding"); 5223 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName())); 5224 } else if (!bindingIdentifier) { 5225 throw error(AbstractParser.message("expected.binding.identifier"), nameToken); 5226 } else { 5227 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName())); 5228 } 5229 if (type == COMMARIGHT) { 5230 next(); 5231 } else { 5232 break; 5233 } 5234 } 5235 expect(RBRACE); 5236 return importEntries; 5237 } 5238 5239 /** 5240 * FromClause : 5241 * from ModuleSpecifier 5242 */ 5243 private String fromClause() { 5244 final long fromToken = token; 5245 final String name = (String) expectValue(IDENT); 5246 if (!"from".equals(name)) { 5247 throw error(AbstractParser.message("expected.from"), fromToken); 5248 } 5249 if (type == STRING || type == ESCSTRING) { 5250 final String moduleSpecifier = (String) getValue(); 5251 next(); 5252 return moduleSpecifier; 5253 } else { 5254 throw error(expectMessage(STRING)); 5255 } 5256 } 5257 5258 /** 5259 * Parse export declaration. 5260 * 5261 * ExportDeclaration : 5262 * export * FromClause ; 5263 * export ExportClause FromClause ; 5264 * export ExportClause ; 5265 * export VariableStatement 5266 * export Declaration 5267 * export default HoistableDeclaration[Default] 5268 * export default ClassDeclaration[Default] 5269 * export default [lookahead !in {function, class}] AssignmentExpression[In] ; 5270 */ 5271 private void exportDeclaration() { 5272 expect(EXPORT); 5273 final ParserContextModuleNode module = lc.getCurrentModule(); 5274 switch (type) { 5275 case MUL: { 5276 next(); 5277 final String moduleRequest = fromClause(); 5278 expect(SEMICOLON); 5279 module.addModuleRequest(moduleRequest); 5280 module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest)); 5281 break; 5282 } 5283 case LBRACE: { 5284 final List<Module.ExportEntry> exportEntries = exportClause(); 5285 if (type == IDENT && "from".equals(getValue())) { 5286 final String moduleRequest = fromClause(); 5287 module.addModuleRequest(moduleRequest); 5288 for (Module.ExportEntry exportEntry : exportEntries) { 5289 module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest)); 5290 } 5291 } else { 5292 for (Module.ExportEntry exportEntry : exportEntries) { 5293 module.addLocalExportEntry(exportEntry); 5294 } 5295 } 5296 expect(SEMICOLON); 5297 break; 5298 } 5299 case DEFAULT: 5300 next(); 5301 final Expression assignmentExpression; 5302 IdentNode ident; 5303 final int lineNumber = line; 5304 final long rhsToken = token; 5305 final boolean declaration; 5306 switch (type) { 5307 case FUNCTION: 5308 assignmentExpression = functionExpression(false, true); 5309 ident = ((FunctionNode) assignmentExpression).getIdent(); 5310 declaration = true; 5311 break; 5312 case CLASS: 5313 assignmentExpression = classDeclaration(true); 5314 ident = ((ClassNode) assignmentExpression).getIdent(); 5315 declaration = true; 5316 break; 5317 default: 5318 assignmentExpression = assignmentExpression(false); 5319 ident = null; 5320 declaration = false; 5321 break; 5322 } 5323 if (ident != null) { 5324 module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName())); 5325 } else { 5326 ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME); 5327 lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression)); 5328 if (!declaration) { 5329 expect(SEMICOLON); 5330 } 5331 module.addLocalExportEntry(Module.ExportEntry.exportDefault()); 5332 } 5333 break; 5334 case VAR: 5335 case LET: 5336 case CONST: 5337 final List<Statement> statements = lc.getCurrentBlock().getStatements(); 5338 final int previousEnd = statements.size(); 5339 variableStatement(type); 5340 for (final Statement statement : statements.subList(previousEnd, statements.size())) { 5341 if (statement instanceof VarNode) { 5342 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName())); 5343 } 5344 } 5345 break; 5346 case CLASS: { 5347 final ClassNode classDeclaration = classDeclaration(false); 5348 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName())); 5349 break; 5350 } 5351 case FUNCTION: { 5352 final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true); 5353 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName())); 5354 break; 5355 } 5356 default: 5357 throw error(AbstractParser.message("invalid.export"), token); 5358 } 5359 } 5360 5361 /** 5362 * ExportClause : 5363 * { } 5364 * { ExportsList } 5365 * { ExportsList , } 5366 * ExportsList : 5367 * ExportSpecifier 5368 * ExportsList , ExportSpecifier 5369 * ExportSpecifier : 5370 * IdentifierName 5371 * IdentifierName as IdentifierName 5372 * 5373 * @return a list of ExportSpecifiers 5374 */ 5375 private List<Module.ExportEntry> exportClause() { 5376 assert type == LBRACE; 5377 next(); 5378 List<Module.ExportEntry> exports = new ArrayList<>(); 5379 while (type != RBRACE) { 5380 final IdentNode localName = getIdentifierName(); 5381 if (type == IDENT && "as".equals(getValue())) { 5382 next(); 5383 final IdentNode exportName = getIdentifierName(); 5384 exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName())); 5385 } else { 5386 exports.add(Module.ExportEntry.exportSpecifier(localName.getName())); 5387 } 5388 if (type == COMMARIGHT) { 5389 next(); 5390 } else { 5391 break; 5392 } 5393 } 5394 expect(RBRACE); 5395 return exports; 5396 } 5397 5398 @Override 5399 public String toString() { 5400 return "'JavaScript Parsing'"; 5401 } 5402 5403 private static void markEval(final ParserContext lc) { 5404 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 5405 boolean flaggedCurrentFn = false; 5406 while (iter.hasNext()) { 5407 final ParserContextFunctionNode fn = iter.next(); 5408 if (!flaggedCurrentFn) { 5409 fn.setFlag(FunctionNode.HAS_EVAL); 5410 flaggedCurrentFn = true; 5411 if (fn.getKind() == FunctionNode.Kind.ARROW) { 5412 // possible use of this in an eval that's nested in an arrow function, e.g.: 5413 // function fun(){ return (() => eval("this"))(); }; 5414 markThis(lc); 5415 markNewTarget(lc); 5416 } 5417 } else { 5418 fn.setFlag(FunctionNode.HAS_NESTED_EVAL); 5419 } 5420 final ParserContextBlockNode body = lc.getFunctionBody(fn); 5421 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 5422 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 5423 // this method when the parser skips a nested function. 5424 body.setFlag(Block.NEEDS_SCOPE); 5425 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); 5426 } 5427 } 5428 5429 private void prependStatement(final Statement statement) { 5430 lc.prependStatementToCurrentNode(statement); 5431 } 5432 5433 private void appendStatement(final Statement statement) { 5434 lc.appendStatementToCurrentNode(statement); 5435 } 5436 5437 private static void markSuperCall(final ParserContext lc) { 5438 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 5439 while (iter.hasNext()) { 5440 final ParserContextFunctionNode fn = iter.next(); 5441 if (fn.getKind() != FunctionNode.Kind.ARROW) { 5442 assert fn.isSubclassConstructor(); 5443 fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER); 5444 break; 5445 } 5446 } 5447 } 5448 5449 private ParserContextFunctionNode getCurrentNonArrowFunction() { 5450 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 5451 while (iter.hasNext()) { 5452 final ParserContextFunctionNode fn = iter.next(); 5453 if (fn.getKind() != FunctionNode.Kind.ARROW) { 5454 return fn; 5455 } 5456 } 5457 return null; 5458 } 5459 5460 private static void markThis(final ParserContext lc) { 5461 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 5462 while (iter.hasNext()) { 5463 final ParserContextFunctionNode fn = iter.next(); 5464 fn.setFlag(FunctionNode.USES_THIS); 5465 if (fn.getKind() != FunctionNode.Kind.ARROW) { 5466 break; 5467 } 5468 } 5469 } 5470 5471 private static void markNewTarget(final ParserContext lc) { 5472 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 5473 while (iter.hasNext()) { 5474 final ParserContextFunctionNode fn = iter.next(); 5475 if (fn.getKind() != FunctionNode.Kind.ARROW) { 5476 if (!fn.isProgram()) { 5477 fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET); 5478 } 5479 break; 5480 } 5481 } 5482 } 5483 5484 private boolean inGeneratorFunction() { 5485 return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR; 5486 } 5487 }