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