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