Parser.java revision 1423:c13179703f65
1/* 2 * Copyright (c) 2010, 2013, 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.ASSIGN; 32import static jdk.nashorn.internal.parser.TokenType.CASE; 33import static jdk.nashorn.internal.parser.TokenType.CATCH; 34import static jdk.nashorn.internal.parser.TokenType.COLON; 35import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT; 36import static jdk.nashorn.internal.parser.TokenType.CONST; 37import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; 38import static jdk.nashorn.internal.parser.TokenType.DECPREFIX; 39import static jdk.nashorn.internal.parser.TokenType.ELSE; 40import static jdk.nashorn.internal.parser.TokenType.EOF; 41import static jdk.nashorn.internal.parser.TokenType.EOL; 42import static jdk.nashorn.internal.parser.TokenType.FINALLY; 43import static jdk.nashorn.internal.parser.TokenType.FUNCTION; 44import static jdk.nashorn.internal.parser.TokenType.IDENT; 45import static jdk.nashorn.internal.parser.TokenType.IF; 46import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; 47import static jdk.nashorn.internal.parser.TokenType.LBRACE; 48import static jdk.nashorn.internal.parser.TokenType.LET; 49import static jdk.nashorn.internal.parser.TokenType.LPAREN; 50import static jdk.nashorn.internal.parser.TokenType.RBRACE; 51import static jdk.nashorn.internal.parser.TokenType.RBRACKET; 52import static jdk.nashorn.internal.parser.TokenType.RPAREN; 53import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; 54import static jdk.nashorn.internal.parser.TokenType.TERNARY; 55import static jdk.nashorn.internal.parser.TokenType.WHILE; 56 57import java.io.Serializable; 58import java.util.ArrayDeque; 59import java.util.ArrayList; 60import java.util.Collections; 61import java.util.Deque; 62import java.util.HashMap; 63import java.util.HashSet; 64import java.util.Iterator; 65import java.util.List; 66import java.util.Map; 67import jdk.internal.dynalink.support.NameCodec; 68import jdk.nashorn.internal.codegen.CompilerConstants; 69import jdk.nashorn.internal.codegen.Namespace; 70import jdk.nashorn.internal.ir.AccessNode; 71import jdk.nashorn.internal.ir.BaseNode; 72import jdk.nashorn.internal.ir.BinaryNode; 73import jdk.nashorn.internal.ir.Block; 74import jdk.nashorn.internal.ir.BlockStatement; 75import jdk.nashorn.internal.ir.BreakNode; 76import jdk.nashorn.internal.ir.CallNode; 77import jdk.nashorn.internal.ir.CaseNode; 78import jdk.nashorn.internal.ir.CatchNode; 79import jdk.nashorn.internal.ir.ContinueNode; 80import jdk.nashorn.internal.ir.DebuggerNode; 81import jdk.nashorn.internal.ir.EmptyNode; 82import jdk.nashorn.internal.ir.ErrorNode; 83import jdk.nashorn.internal.ir.Expression; 84import jdk.nashorn.internal.ir.ExpressionStatement; 85import jdk.nashorn.internal.ir.ForNode; 86import jdk.nashorn.internal.ir.FunctionNode; 87import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 88import jdk.nashorn.internal.ir.IdentNode; 89import jdk.nashorn.internal.ir.IfNode; 90import jdk.nashorn.internal.ir.IndexNode; 91import jdk.nashorn.internal.ir.JoinPredecessorExpression; 92import jdk.nashorn.internal.ir.LabelNode; 93import jdk.nashorn.internal.ir.LiteralNode; 94import jdk.nashorn.internal.ir.Node; 95import jdk.nashorn.internal.ir.ObjectNode; 96import jdk.nashorn.internal.ir.PropertyKey; 97import jdk.nashorn.internal.ir.PropertyNode; 98import jdk.nashorn.internal.ir.ReturnNode; 99import jdk.nashorn.internal.ir.RuntimeNode; 100import jdk.nashorn.internal.ir.Statement; 101import jdk.nashorn.internal.ir.SwitchNode; 102import jdk.nashorn.internal.ir.TernaryNode; 103import jdk.nashorn.internal.ir.ThrowNode; 104import jdk.nashorn.internal.ir.TryNode; 105import jdk.nashorn.internal.ir.UnaryNode; 106import jdk.nashorn.internal.ir.VarNode; 107import jdk.nashorn.internal.ir.WhileNode; 108import jdk.nashorn.internal.ir.WithNode; 109import jdk.nashorn.internal.ir.debug.ASTWriter; 110import jdk.nashorn.internal.ir.debug.PrintVisitor; 111import jdk.nashorn.internal.runtime.Context; 112import jdk.nashorn.internal.runtime.ErrorManager; 113import jdk.nashorn.internal.runtime.JSErrorType; 114import jdk.nashorn.internal.runtime.ParserException; 115import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData; 116import jdk.nashorn.internal.runtime.ScriptEnvironment; 117import jdk.nashorn.internal.runtime.ScriptingFunctions; 118import jdk.nashorn.internal.runtime.Source; 119import jdk.nashorn.internal.runtime.Timing; 120import jdk.nashorn.internal.runtime.logging.DebugLogger; 121import jdk.nashorn.internal.runtime.logging.Loggable; 122import jdk.nashorn.internal.runtime.logging.Logger; 123 124/** 125 * Builds the IR. 126 */ 127@Logger(name="parser") 128public class Parser extends AbstractParser implements Loggable { 129 private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName(); 130 131 /** Current env. */ 132 private final ScriptEnvironment env; 133 134 /** Is scripting mode. */ 135 private final boolean scripting; 136 137 private List<Statement> functionDeclarations; 138 139 private final ParserContext lc; 140 private final Deque<Object> defaultNames; 141 142 /** Namespace for function names where not explicitly given */ 143 private final Namespace namespace; 144 145 private final DebugLogger log; 146 147 /** to receive line information from Lexer when scanning multine literals. */ 148 protected final Lexer.LineInfoReceiver lineInfoReceiver; 149 150 private RecompilableScriptFunctionData reparsedFunction; 151 152 /** 153 * Constructor 154 * 155 * @param env script environment 156 * @param source source to parse 157 * @param errors error manager 158 */ 159 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) { 160 this(env, source, errors, env._strict, null); 161 } 162 163 /** 164 * Constructor 165 * 166 * @param env script environment 167 * @param source source to parse 168 * @param errors error manager 169 * @param strict strict 170 * @param log debug logger if one is needed 171 */ 172 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) { 173 this(env, source, errors, strict, 0, log); 174 } 175 176 /** 177 * Construct a parser. 178 * 179 * @param env script environment 180 * @param source source to parse 181 * @param errors error manager 182 * @param strict parser created with strict mode enabled. 183 * @param lineOffset line offset to start counting lines from 184 * @param log debug logger if one is needed 185 */ 186 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) { 187 super(source, errors, strict, lineOffset); 188 this.lc = new ParserContext(); 189 this.defaultNames = new ArrayDeque<>(); 190 this.env = env; 191 this.namespace = new Namespace(env.getNamespace()); 192 this.scripting = env._scripting; 193 if (this.scripting) { 194 this.lineInfoReceiver = new Lexer.LineInfoReceiver() { 195 @Override 196 public void lineInfo(final int receiverLine, final int receiverLinePosition) { 197 // update the parser maintained line information 198 Parser.this.line = receiverLine; 199 Parser.this.linePosition = receiverLinePosition; 200 } 201 }; 202 } else { 203 // non-scripting mode script can't have multi-line literals 204 this.lineInfoReceiver = null; 205 } 206 207 this.log = log == null ? DebugLogger.DISABLED_LOGGER : log; 208 } 209 210 @Override 211 public DebugLogger getLogger() { 212 return log; 213 } 214 215 @Override 216 public DebugLogger initLogger(final Context context) { 217 return context.getLogger(this.getClass()); 218 } 219 220 /** 221 * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can 222 * preserve their already assigned name, as that name doesn't appear in their source text. 223 * @param name the name for the first parsed function. 224 */ 225 public void setFunctionName(final String name) { 226 defaultNames.push(createIdentNode(0, 0, name)); 227 } 228 229 /** 230 * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this 231 * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation). 232 * This will trigger various special behaviors, such as skipping nested function bodies. 233 * @param reparsedFunction the function being reparsed. 234 */ 235 public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) { 236 this.reparsedFunction = reparsedFunction; 237 } 238 239 /** 240 * Execute parse and return the resulting function node. 241 * Errors will be thrown and the error manager will contain information 242 * if parsing should fail 243 * 244 * This is the default parse call, which will name the function node 245 * {code :program} {@link CompilerConstants#PROGRAM} 246 * 247 * @return function node resulting from successful parse 248 */ 249 public FunctionNode parse() { 250 return parse(PROGRAM.symbolName(), 0, source.getLength(), false); 251 } 252 253 /** 254 * Execute parse and return the resulting function node. 255 * Errors will be thrown and the error manager will contain information 256 * if parsing should fail 257 * 258 * This should be used to create one and only one function node 259 * 260 * @param scriptName name for the script, given to the parsed FunctionNode 261 * @param startPos start position in source 262 * @param len length of parse 263 * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by 264 * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a 265 * property getter or setter in an object literal. 266 * 267 * @return function node resulting from successful parse 268 */ 269 public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) { 270 final boolean isTimingEnabled = env.isTimingEnabled(); 271 final long t0 = isTimingEnabled ? System.nanoTime() : 0L; 272 log.info(this, " begin for '", scriptName, "'"); 273 274 try { 275 stream = new TokenStream(); 276 lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null); 277 lexer.line = lexer.pendingLine = lineOffset + 1; 278 line = lineOffset; 279 280 // Set up first token (skips opening EOL.) 281 k = -1; 282 next(); 283 // Begin parse. 284 return program(scriptName, allowPropertyFunction); 285 } catch (final Exception e) { 286 handleParseException(e); 287 288 return null; 289 } finally { 290 final String end = this + " end '" + scriptName + "'"; 291 if (isTimingEnabled) { 292 env._timing.accumulateTime(toString(), System.nanoTime() - t0); 293 log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms"); 294 } else { 295 log.info(end); 296 } 297 } 298 } 299 300 /** 301 * Parse and return the list of function parameter list. A comma 302 * separated list of function parameter identifiers is expected to be parsed. 303 * Errors will be thrown and the error manager will contain information 304 * if parsing should fail. This method is used to check if parameter Strings 305 * passed to "Function" constructor is a valid or not. 306 * 307 * @return the list of IdentNodes representing the formal parameter list 308 */ 309 public List<IdentNode> parseFormalParameterList() { 310 try { 311 stream = new TokenStream(); 312 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); 313 314 // Set up first token (skips opening EOL.) 315 k = -1; 316 next(); 317 318 return formalParameterList(TokenType.EOF); 319 } catch (final Exception e) { 320 handleParseException(e); 321 return null; 322 } 323 } 324 325 /** 326 * Execute parse and return the resulting function node. 327 * Errors will be thrown and the error manager will contain information 328 * if parsing should fail. This method is used to check if code String 329 * passed to "Function" constructor is a valid function body or not. 330 * 331 * @return function node resulting from successful parse 332 */ 333 public FunctionNode parseFunctionBody() { 334 try { 335 stream = new TokenStream(); 336 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6); 337 final int functionLine = line; 338 339 // Set up first token (skips opening EOL.) 340 k = -1; 341 next(); 342 343 // Make a fake token for the function. 344 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 345 // Set up the function to append elements. 346 347 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName()); 348 final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList()); 349 lc.push(function); 350 351 final ParserContextBlockNode body = newBlock(); 352 353 functionDeclarations = new ArrayList<>(); 354 sourceElements(false); 355 addFunctionDeclarations(function); 356 functionDeclarations = null; 357 358 restoreBlock(body); 359 body.setFlag(Block.NEEDS_SCOPE); 360 361 final Block functionBody = new Block(functionToken, source.getLength() - 1, 362 body.getFlags() | Block.IS_SYNTHETIC, body.getStatements()); 363 lc.pop(function); 364 365 expect(EOF); 366 367 final FunctionNode functionNode = createFunctionNode( 368 function, 369 functionToken, 370 ident, 371 Collections.<IdentNode>emptyList(), 372 FunctionNode.Kind.NORMAL, 373 functionLine, 374 functionBody); 375 printAST(functionNode); 376 return functionNode; 377 } catch (final Exception e) { 378 handleParseException(e); 379 return null; 380 } 381 } 382 383 private void handleParseException(final Exception e) { 384 // Extract message from exception. The message will be in error 385 // message format. 386 String message = e.getMessage(); 387 388 // If empty message. 389 if (message == null) { 390 message = e.toString(); 391 } 392 393 // Issue message. 394 if (e instanceof ParserException) { 395 errors.error((ParserException)e); 396 } else { 397 errors.error(message); 398 } 399 400 if (env._dump_on_error) { 401 e.printStackTrace(env.getErr()); 402 } 403 } 404 405 /** 406 * Skip to a good parsing recovery point. 407 */ 408 private void recover(final Exception e) { 409 if (e != null) { 410 // Extract message from exception. The message will be in error 411 // message format. 412 String message = e.getMessage(); 413 414 // If empty message. 415 if (message == null) { 416 message = e.toString(); 417 } 418 419 // Issue message. 420 if (e instanceof ParserException) { 421 errors.error((ParserException)e); 422 } else { 423 errors.error(message); 424 } 425 426 if (env._dump_on_error) { 427 e.printStackTrace(env.getErr()); 428 } 429 } 430 431 // Skip to a recovery point. 432loop: 433 while (true) { 434 switch (type) { 435 case EOF: 436 // Can not go any further. 437 break loop; 438 case EOL: 439 case SEMICOLON: 440 case RBRACE: 441 // Good recovery points. 442 next(); 443 break loop; 444 default: 445 // So we can recover after EOL. 446 nextOrEOL(); 447 break; 448 } 449 } 450 } 451 452 /** 453 * Set up a new block. 454 * 455 * @return New block. 456 */ 457 private ParserContextBlockNode newBlock() { 458 return lc.push(new ParserContextBlockNode(token)); 459 } 460 461 private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) { 462 // Build function name. 463 final StringBuilder sb = new StringBuilder(); 464 465 final ParserContextFunctionNode parentFunction = lc.getCurrentFunction(); 466 if (parentFunction != null && !parentFunction.isProgram()) { 467 sb.append(parentFunction.getName()).append('$'); 468 } 469 470 assert ident.getName() != null; 471 sb.append(ident.getName()); 472 473 final String name = namespace.uniqueName(sb.toString()); 474 assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name; 475 476 int flags = 0; 477 if (isStrictMode) { 478 flags |= FunctionNode.IS_STRICT; 479 } 480 if (parentFunction == null) { 481 flags |= FunctionNode.IS_PROGRAM; 482 } 483 484 final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters); 485 functionNode.setFlag(flags); 486 return functionNode; 487 } 488 489 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){ 490 final CompilationState state = errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED; 491 // Start new block. 492 final FunctionNode functionNode = 493 new FunctionNode( 494 source, 495 functionLine, 496 body.getToken(), 497 Token.descPosition(body.getToken()), 498 startToken, 499 function.getLastToken(), 500 namespace, 501 ident, 502 function.getName(), 503 parameters, 504 kind, 505 function.getFlags(), 506 body, 507 state, 508 function.getEndParserState()); 509 510 printAST(functionNode); 511 512 return functionNode; 513 } 514 515 /** 516 * Restore the current block. 517 */ 518 private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) { 519 return lc.pop(block); 520 } 521 522 /** 523 * Get the statements in a block. 524 * @return Block statements. 525 */ 526 private Block getBlock(final boolean needsBraces) { 527 final long blockToken = token; 528 final ParserContextBlockNode newBlock = newBlock(); 529 try { 530 // Block opening brace. 531 if (needsBraces) { 532 expect(LBRACE); 533 } 534 // Accumulate block statements. 535 statementList(); 536 537 } finally { 538 restoreBlock(newBlock); 539 } 540 541 // Block closing brace. 542 if (needsBraces) { 543 expect(RBRACE); 544 } 545 546 final int flags = newBlock.getFlags() | (needsBraces? 0 : Block.IS_SYNTHETIC); 547 return new Block(blockToken, finish, flags, newBlock.getStatements()); 548 } 549 550 551 /** 552 * Get all the statements generated by a single statement. 553 * @return Statements. 554 */ 555 private Block getStatement() { 556 if (type == LBRACE) { 557 return getBlock(true); 558 } 559 // Set up new block. Captures first token. 560 final ParserContextBlockNode newBlock = newBlock(); 561 try { 562 statement(false, false, true); 563 } finally { 564 restoreBlock(newBlock); 565 } 566 return new Block(newBlock.getToken(), finish, newBlock.getFlags() | Block.IS_SYNTHETIC, newBlock.getStatements()); 567 } 568 569 /** 570 * Detect calls to special functions. 571 * @param ident Called function. 572 */ 573 private void detectSpecialFunction(final IdentNode ident) { 574 final String name = ident.getName(); 575 576 if (EVAL.symbolName().equals(name)) { 577 markEval(lc); 578 } 579 } 580 581 /** 582 * Detect use of special properties. 583 * @param ident Referenced property. 584 */ 585 private void detectSpecialProperty(final IdentNode ident) { 586 if (isArguments(ident)) { 587 lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS); 588 } 589 } 590 591 private boolean useBlockScope() { 592 return env._es6; 593 } 594 595 private static boolean isArguments(final String name) { 596 return ARGUMENTS_NAME.equals(name); 597 } 598 599 private static boolean isArguments(final IdentNode ident) { 600 return isArguments(ident.getName()); 601 } 602 603 /** 604 * Tells whether a IdentNode can be used as L-value of an assignment 605 * 606 * @param ident IdentNode to be checked 607 * @return whether the ident can be used as L-value 608 */ 609 private static boolean checkIdentLValue(final IdentNode ident) { 610 return ident.tokenType().getKind() != TokenKind.KEYWORD; 611 } 612 613 /** 614 * Verify an assignment expression. 615 * @param op Operation token. 616 * @param lhs Left hand side expression. 617 * @param rhs Right hand side expression. 618 * @return Verified expression. 619 */ 620 private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) { 621 final TokenType opType = Token.descType(op); 622 623 switch (opType) { 624 case ASSIGN: 625 case ASSIGN_ADD: 626 case ASSIGN_BIT_AND: 627 case ASSIGN_BIT_OR: 628 case ASSIGN_BIT_XOR: 629 case ASSIGN_DIV: 630 case ASSIGN_MOD: 631 case ASSIGN_MUL: 632 case ASSIGN_SAR: 633 case ASSIGN_SHL: 634 case ASSIGN_SHR: 635 case ASSIGN_SUB: 636 if (!(lhs instanceof AccessNode || 637 lhs instanceof IndexNode || 638 lhs instanceof IdentNode)) { 639 return referenceError(lhs, rhs, env._early_lvalue_error); 640 } 641 642 if (lhs instanceof IdentNode) { 643 if (!checkIdentLValue((IdentNode)lhs)) { 644 return referenceError(lhs, rhs, false); 645 } 646 verifyStrictIdent((IdentNode)lhs, "assignment"); 647 } 648 break; 649 650 default: 651 break; 652 } 653 654 // Build up node. 655 if(BinaryNode.isLogical(opType)) { 656 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs)); 657 } 658 return new BinaryNode(op, lhs, rhs); 659 } 660 661 662 /** 663 * Reduce increment/decrement to simpler operations. 664 * @param firstToken First token. 665 * @param tokenType Operation token (INCPREFIX/DEC.) 666 * @param expression Left hand side expression. 667 * @param isPostfix Prefix or postfix. 668 * @return Reduced expression. 669 */ 670 private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) { 671 if (isPostfix) { 672 return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); 673 } 674 675 return new UnaryNode(firstToken, expression); 676 } 677 678 /** 679 * ----------------------------------------------------------------------- 680 * 681 * Grammar based on 682 * 683 * ECMAScript Language Specification 684 * ECMA-262 5th Edition / December 2009 685 * 686 * ----------------------------------------------------------------------- 687 */ 688 689 /** 690 * Program : 691 * SourceElements? 692 * 693 * See 14 694 * 695 * Parse the top level script. 696 */ 697 private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) { 698 // Make a pseudo-token for the script holding its start and length. 699 final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength()); 700 final int functionLine = line; 701 702 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName); 703 final ParserContextFunctionNode script = createParserContextFunctionNode( 704 ident, 705 functionToken, 706 FunctionNode.Kind.SCRIPT, 707 functionLine, 708 Collections.<IdentNode>emptyList()); 709 lc.push(script); 710 final ParserContextBlockNode body = newBlock(); 711 712 functionDeclarations = new ArrayList<>(); 713 sourceElements(allowPropertyFunction); 714 addFunctionDeclarations(script); 715 functionDeclarations = null; 716 717 restoreBlock(body); 718 body.setFlag(Block.NEEDS_SCOPE); 719 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements()); 720 lc.pop(script); 721 script.setLastToken(token); 722 723 expect(EOF); 724 725 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody); 726 } 727 728 /** 729 * Directive value or null if statement is not a directive. 730 * 731 * @param stmt Statement to be checked 732 * @return Directive value if the given statement is a directive 733 */ 734 private String getDirective(final Node stmt) { 735 if (stmt instanceof ExpressionStatement) { 736 final Node expr = ((ExpressionStatement)stmt).getExpression(); 737 if (expr instanceof LiteralNode) { 738 final LiteralNode<?> lit = (LiteralNode<?>)expr; 739 final long litToken = lit.getToken(); 740 final TokenType tt = Token.descType(litToken); 741 // A directive is either a string or an escape string 742 if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) { 743 // Make sure that we don't unescape anything. Return as seen in source! 744 return source.getString(lit.getStart(), Token.descLength(litToken)); 745 } 746 } 747 } 748 749 return null; 750 } 751 752 /** 753 * SourceElements : 754 * SourceElement 755 * SourceElements SourceElement 756 * 757 * See 14 758 * 759 * Parse the elements of the script or function. 760 */ 761 private void sourceElements(final boolean shouldAllowPropertyFunction) { 762 List<Node> directiveStmts = null; 763 boolean checkDirective = true; 764 boolean allowPropertyFunction = shouldAllowPropertyFunction; 765 final boolean oldStrictMode = isStrictMode; 766 767 768 try { 769 // If is a script, then process until the end of the script. 770 while (type != EOF) { 771 // Break if the end of a code block. 772 if (type == RBRACE) { 773 break; 774 } 775 776 try { 777 // Get the next element. 778 statement(true, allowPropertyFunction, false); 779 allowPropertyFunction = false; 780 781 // check for directive prologues 782 if (checkDirective) { 783 // skip any debug statement like line number to get actual first line 784 final Statement lastStatement = lc.getLastStatement(); 785 786 // get directive prologue, if any 787 final String directive = getDirective(lastStatement); 788 789 // If we have seen first non-directive statement, 790 // no more directive statements!! 791 checkDirective = directive != null; 792 793 if (checkDirective) { 794 if (!oldStrictMode) { 795 if (directiveStmts == null) { 796 directiveStmts = new ArrayList<>(); 797 } 798 directiveStmts.add(lastStatement); 799 } 800 801 // handle use strict directive 802 if ("use strict".equals(directive)) { 803 isStrictMode = true; 804 final ParserContextFunctionNode function = lc.getCurrentFunction(); 805 function.setFlag(FunctionNode.IS_STRICT); 806 807 // We don't need to check these, if lexical environment is already strict 808 if (!oldStrictMode && directiveStmts != null) { 809 // check that directives preceding this one do not violate strictness 810 for (final Node statement : directiveStmts) { 811 // the get value will force unescape of preceding 812 // escaped string directives 813 getValue(statement.getToken()); 814 } 815 816 // verify that function name as well as parameter names 817 // satisfy strict mode restrictions. 818 verifyStrictIdent(function.getIdent(), "function name"); 819 for (final IdentNode param : function.getParameters()) { 820 verifyStrictIdent(param, "function parameter"); 821 } 822 } 823 } else if (Context.DEBUG) { 824 final int flag = FunctionNode.getDirectiveFlag(directive); 825 if (flag != 0) { 826 final ParserContextFunctionNode function = lc.getCurrentFunction(); 827 function.setFlag(flag); 828 } 829 } 830 } 831 } 832 } catch (final Exception e) { 833 final int errorLine = line; 834 final long errorToken = token; 835 //recover parsing 836 recover(e); 837 final ErrorNode errorExpr = new ErrorNode(errorToken, finish); 838 final ExpressionStatement expressionStatement = new ExpressionStatement(errorLine, errorToken, finish, errorExpr); 839 appendStatement(expressionStatement); 840 } 841 842 // No backtracking from here on. 843 stream.commit(k); 844 } 845 } finally { 846 isStrictMode = oldStrictMode; 847 } 848 } 849 850 /** 851 * Statement : 852 * Block 853 * VariableStatement 854 * EmptyStatement 855 * ExpressionStatement 856 * IfStatement 857 * IterationStatement 858 * ContinueStatement 859 * BreakStatement 860 * ReturnStatement 861 * WithStatement 862 * LabelledStatement 863 * SwitchStatement 864 * ThrowStatement 865 * TryStatement 866 * DebuggerStatement 867 * 868 * see 12 869 * 870 * Parse any of the basic statement types. 871 */ 872 private void statement() { 873 statement(false, false, false); 874 } 875 876 /** 877 * @param topLevel does this statement occur at the "top level" of a script or a function? 878 * @param allowPropertyFunction allow property "get" and "set" functions? 879 * @param singleStatement are we in a single statement context? 880 */ 881 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) { 882 if (type == FUNCTION) { 883 // As per spec (ECMA section 12), function declarations as arbitrary statement 884 // is not "portable". Implementation can issue a warning or disallow the same. 885 functionExpression(true, topLevel); 886 return; 887 } 888 889 switch (type) { 890 case LBRACE: 891 block(); 892 break; 893 case VAR: 894 variableStatement(type, true); 895 break; 896 case SEMICOLON: 897 emptyStatement(); 898 break; 899 case IF: 900 ifStatement(); 901 break; 902 case FOR: 903 forStatement(); 904 break; 905 case WHILE: 906 whileStatement(); 907 break; 908 case DO: 909 doStatement(); 910 break; 911 case CONTINUE: 912 continueStatement(); 913 break; 914 case BREAK: 915 breakStatement(); 916 break; 917 case RETURN: 918 returnStatement(); 919 break; 920 case YIELD: 921 yieldStatement(); 922 break; 923 case WITH: 924 withStatement(); 925 break; 926 case SWITCH: 927 switchStatement(); 928 break; 929 case THROW: 930 throwStatement(); 931 break; 932 case TRY: 933 tryStatement(); 934 break; 935 case DEBUGGER: 936 debuggerStatement(); 937 break; 938 case RPAREN: 939 case RBRACKET: 940 case EOF: 941 expect(SEMICOLON); 942 break; 943 default: 944 if (useBlockScope() && (type == LET || type == CONST)) { 945 if (singleStatement) { 946 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token); 947 } 948 variableStatement(type, true); 949 break; 950 } 951 if (env._const_as_var && type == CONST) { 952 variableStatement(TokenType.VAR, true); 953 break; 954 } 955 956 if (type == IDENT || isNonStrictModeIdent()) { 957 if (T(k + 1) == COLON) { 958 labelStatement(); 959 return; 960 } 961 if(allowPropertyFunction) { 962 final String ident = (String)getValue(); 963 final long propertyToken = token; 964 final int propertyLine = line; 965 if("get".equals(ident)) { 966 next(); 967 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); 968 return; 969 } else if("set".equals(ident)) { 970 next(); 971 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); 972 return; 973 } 974 } 975 } 976 977 expressionStatement(); 978 break; 979 } 980 } 981 982 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { 983 final FunctionNode fn = propertyFunction.functionNode; 984 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); 985 } 986 987 /** 988 * block : 989 * { StatementList? } 990 * 991 * see 12.1 992 * 993 * Parse a statement block. 994 */ 995 private void block() { 996 appendStatement(new BlockStatement(line, getBlock(true))); 997 } 998 999 /** 1000 * StatementList : 1001 * Statement 1002 * StatementList Statement 1003 * 1004 * See 12.1 1005 * 1006 * Parse a list of statements. 1007 */ 1008 private void statementList() { 1009 // Accumulate statements until end of list. */ 1010loop: 1011 while (type != EOF) { 1012 switch (type) { 1013 case EOF: 1014 case CASE: 1015 case DEFAULT: 1016 case RBRACE: 1017 break loop; 1018 default: 1019 break; 1020 } 1021 1022 // Get next statement. 1023 statement(); 1024 } 1025 } 1026 1027 /** 1028 * Make sure that in strict mode, the identifier name used is allowed. 1029 * 1030 * @param ident Identifier that is verified 1031 * @param contextString String used in error message to give context to the user 1032 */ 1033 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 1034 if (isStrictMode) { 1035 switch (ident.getName()) { 1036 case "eval": 1037 case "arguments": 1038 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1039 default: 1040 break; 1041 } 1042 1043 if (ident.isFutureStrictName()) { 1044 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1045 } 1046 } 1047 } 1048 1049 /** 1050 * VariableStatement : 1051 * var VariableDeclarationList ; 1052 * 1053 * VariableDeclarationList : 1054 * VariableDeclaration 1055 * VariableDeclarationList , VariableDeclaration 1056 * 1057 * VariableDeclaration : 1058 * Identifier Initializer? 1059 * 1060 * Initializer : 1061 * = AssignmentExpression 1062 * 1063 * See 12.2 1064 * 1065 * Parse a VAR statement. 1066 * @param isStatement True if a statement (not used in a FOR.) 1067 */ 1068 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) { 1069 return variableStatement(varType, isStatement, -1); 1070 } 1071 1072 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) { 1073 // VAR tested in caller. 1074 next(); 1075 1076 final List<VarNode> vars = new ArrayList<>(); 1077 int varFlags = 0; 1078 if (varType == LET) { 1079 varFlags |= VarNode.IS_LET; 1080 } else if (varType == CONST) { 1081 varFlags |= VarNode.IS_CONST; 1082 } 1083 1084 while (true) { 1085 // Get starting token. 1086 final int varLine = line; 1087 final long varToken = token; 1088 // Get name of var. 1089 final IdentNode name = getIdent(); 1090 verifyStrictIdent(name, "variable name"); 1091 1092 // Assume no init. 1093 Expression init = null; 1094 1095 // Look for initializer assignment. 1096 if (type == ASSIGN) { 1097 next(); 1098 1099 // Get initializer expression. Suppress IN if not statement. 1100 defaultNames.push(name); 1101 try { 1102 init = assignmentExpression(!isStatement); 1103 } finally { 1104 defaultNames.pop(); 1105 } 1106 } else if (varType == CONST) { 1107 throw error(AbstractParser.message("missing.const.assignment", name.getName())); 1108 } 1109 1110 // Allocate var node. 1111 final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name.setIsDeclaredHere(), init, varFlags); 1112 vars.add(var); 1113 appendStatement(var); 1114 1115 if (type != COMMARIGHT) { 1116 break; 1117 } 1118 next(); 1119 } 1120 1121 // If is a statement then handle end of line. 1122 if (isStatement) { 1123 endOfLine(); 1124 } 1125 1126 return vars; 1127 } 1128 1129 /** 1130 * EmptyStatement : 1131 * ; 1132 * 1133 * See 12.3 1134 * 1135 * Parse an empty statement. 1136 */ 1137 private void emptyStatement() { 1138 if (env._empty_statements) { 1139 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); 1140 } 1141 1142 // SEMICOLON checked in caller. 1143 next(); 1144 } 1145 1146 /** 1147 * ExpressionStatement : 1148 * Expression ; // [lookahead ~( or function )] 1149 * 1150 * See 12.4 1151 * 1152 * Parse an expression used in a statement block. 1153 */ 1154 private void expressionStatement() { 1155 // Lookahead checked in caller. 1156 final int expressionLine = line; 1157 final long expressionToken = token; 1158 1159 // Get expression and add as statement. 1160 final Expression expression = expression(); 1161 1162 ExpressionStatement expressionStatement = null; 1163 if (expression != null) { 1164 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); 1165 appendStatement(expressionStatement); 1166 } else { 1167 expect(null); 1168 } 1169 1170 endOfLine(); 1171 } 1172 1173 /** 1174 * IfStatement : 1175 * if ( Expression ) Statement else Statement 1176 * if ( Expression ) Statement 1177 * 1178 * See 12.5 1179 * 1180 * Parse an IF statement. 1181 */ 1182 private void ifStatement() { 1183 // Capture IF token. 1184 final int ifLine = line; 1185 final long ifToken = token; 1186 // IF tested in caller. 1187 next(); 1188 1189 expect(LPAREN); 1190 final Expression test = expression(); 1191 expect(RPAREN); 1192 final Block pass = getStatement(); 1193 1194 Block fail = null; 1195 if (type == ELSE) { 1196 next(); 1197 fail = getStatement(); 1198 } 1199 1200 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 1201 } 1202 1203 /** 1204 * ... IterationStatement: 1205 * ... 1206 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement 1207 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement 1208 * for ( LeftHandSideExpression in Expression ) Statement 1209 * for ( var VariableDeclaration[NoIn] in Expression ) Statement 1210 * 1211 * See 12.6 1212 * 1213 * Parse a FOR statement. 1214 */ 1215 private void forStatement() { 1216 final long forToken = token; 1217 final int forLine = line; 1218 // start position of this for statement. This is used 1219 // for sort order for variables declared in the initializer 1220 // part of this 'for' statement (if any). 1221 final int forStart = Token.descPosition(forToken); 1222 // When ES6 for-let is enabled we create a container block to capture the LET. 1223 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null; 1224 1225 // Create FOR node, capturing FOR token. 1226 final ParserContextLoopNode forNode = new ParserContextLoopNode(); 1227 lc.push(forNode); 1228 Block body = null; 1229 List<VarNode> vars = null; 1230 Expression init = null; 1231 JoinPredecessorExpression test = null; 1232 JoinPredecessorExpression modify = null; 1233 1234 int flags = 0; 1235 1236 try { 1237 // FOR tested in caller. 1238 next(); 1239 1240 // Nashorn extension: for each expression. 1241 // iterate property values rather than property names. 1242 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 1243 flags |= ForNode.IS_FOR_EACH; 1244 next(); 1245 } 1246 1247 expect(LPAREN); 1248 1249 1250 switch (type) { 1251 case VAR: 1252 // Var declaration captured in for outer block. 1253 vars = variableStatement(type, false, forStart); 1254 break; 1255 case SEMICOLON: 1256 break; 1257 default: 1258 if (useBlockScope() && (type == LET || type == CONST)) { 1259 if (type == LET) { 1260 flags |= ForNode.PER_ITERATION_SCOPE; 1261 } 1262 // LET/CONST declaration captured in container block created above. 1263 vars = variableStatement(type, false, forStart); 1264 break; 1265 } 1266 if (env._const_as_var && type == CONST) { 1267 // Var declaration captured in for outer block. 1268 vars = variableStatement(TokenType.VAR, false, forStart); 1269 break; 1270 } 1271 1272 init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 1273 break; 1274 } 1275 1276 switch (type) { 1277 case SEMICOLON: 1278 // for (init; test; modify) 1279 1280 // for each (init; test; modify) is invalid 1281 if ((flags & ForNode.IS_FOR_EACH) != 0) { 1282 throw error(AbstractParser.message("for.each.without.in"), token); 1283 } 1284 1285 expect(SEMICOLON); 1286 if (type != SEMICOLON) { 1287 test = joinPredecessorExpression(); 1288 } 1289 expect(SEMICOLON); 1290 if (type != RPAREN) { 1291 modify = joinPredecessorExpression(); 1292 } 1293 break; 1294 1295 case IN: 1296 flags |= ForNode.IS_FOR_IN; 1297 test = new JoinPredecessorExpression(); 1298 if (vars != null) { 1299 // for (var i in obj) 1300 if (vars.size() == 1) { 1301 init = new IdentNode(vars.get(0).getName()); 1302 } else { 1303 // for (var i, j in obj) is invalid 1304 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 1305 } 1306 1307 } else { 1308 // for (expr in obj) 1309 assert init != null : "for..in init expression can not be null here"; 1310 1311 // check if initial expression is a valid L-value 1312 if (!(init instanceof AccessNode || 1313 init instanceof IndexNode || 1314 init instanceof IdentNode)) { 1315 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1316 } 1317 1318 if (init instanceof IdentNode) { 1319 if (!checkIdentLValue((IdentNode)init)) { 1320 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1321 } 1322 verifyStrictIdent((IdentNode)init, "for-in iterator"); 1323 } 1324 } 1325 1326 next(); 1327 1328 // Get the collection expression. 1329 modify = joinPredecessorExpression(); 1330 break; 1331 1332 default: 1333 expect(SEMICOLON); 1334 break; 1335 } 1336 1337 expect(RPAREN); 1338 1339 // Set the for body. 1340 body = getStatement(); 1341 } finally { 1342 lc.pop(forNode); 1343 1344 if (vars != null) { 1345 for (final VarNode var : vars) { 1346 appendStatement(var); 1347 } 1348 } 1349 if (body != null) { 1350 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); 1351 } 1352 if (outer != null) { 1353 restoreBlock(outer); 1354 if (body != null) { 1355 appendStatement(new BlockStatement(forLine, new Block( 1356 outer.getToken(), 1357 body.getFinish(), 1358 outer.getStatements()))); 1359 } 1360 } 1361 } 1362 } 1363 1364 /** 1365 * ...IterationStatement : 1366 * ... 1367 * while ( Expression ) Statement 1368 * ... 1369 * 1370 * See 12.6 1371 * 1372 * Parse while statement. 1373 */ 1374 private void whileStatement() { 1375 // Capture WHILE token. 1376 final long whileToken = token; 1377 final int whileLine = line; 1378 // WHILE tested in caller. 1379 next(); 1380 1381 final ParserContextLoopNode whileNode = new ParserContextLoopNode(); 1382 lc.push(whileNode); 1383 1384 JoinPredecessorExpression test = null; 1385 Block body = null; 1386 1387 try { 1388 expect(LPAREN); 1389 test = joinPredecessorExpression(); 1390 expect(RPAREN); 1391 body = getStatement(); 1392 } finally { 1393 lc.pop(whileNode); 1394 } 1395 1396 if (body != null) { 1397 appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body)); 1398 } 1399 } 1400 1401 /** 1402 * ...IterationStatement : 1403 * ... 1404 * do Statement while( Expression ) ; 1405 * ... 1406 * 1407 * See 12.6 1408 * 1409 * Parse DO WHILE statement. 1410 */ 1411 private void doStatement() { 1412 // Capture DO token. 1413 final long doToken = token; 1414 int doLine = 0; 1415 // DO tested in the caller. 1416 next(); 1417 1418 final ParserContextLoopNode doWhileNode = new ParserContextLoopNode(); 1419 lc.push(doWhileNode); 1420 1421 Block body = null; 1422 JoinPredecessorExpression test = null; 1423 1424 try { 1425 // Get DO body. 1426 body = getStatement(); 1427 1428 expect(WHILE); 1429 expect(LPAREN); 1430 doLine = line; 1431 test = joinPredecessorExpression(); 1432 expect(RPAREN); 1433 1434 if (type == SEMICOLON) { 1435 endOfLine(); 1436 } 1437 } finally { 1438 lc.pop(doWhileNode); 1439 } 1440 1441 appendStatement(new WhileNode(doLine, doToken, finish, true, test, body)); 1442 } 1443 1444 /** 1445 * ContinueStatement : 1446 * continue Identifier? ; // [no LineTerminator here] 1447 * 1448 * See 12.7 1449 * 1450 * Parse CONTINUE statement. 1451 */ 1452 private void continueStatement() { 1453 // Capture CONTINUE token. 1454 final int continueLine = line; 1455 final long continueToken = token; 1456 // CONTINUE tested in caller. 1457 nextOrEOL(); 1458 1459 ParserContextLabelNode labelNode = null; 1460 1461 // SEMICOLON or label. 1462 switch (type) { 1463 case RBRACE: 1464 case SEMICOLON: 1465 case EOL: 1466 case EOF: 1467 break; 1468 1469 default: 1470 final IdentNode ident = getIdent(); 1471 labelNode = lc.findLabel(ident.getName()); 1472 1473 if (labelNode == null) { 1474 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1475 } 1476 1477 break; 1478 } 1479 1480 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1481 final ParserContextLoopNode targetNode = lc.getContinueTo(labelName); 1482 1483 if (targetNode == null) { 1484 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 1485 } 1486 1487 endOfLine(); 1488 1489 // Construct and add CONTINUE node. 1490 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); 1491 } 1492 1493 /** 1494 * BreakStatement : 1495 * break Identifier? ; // [no LineTerminator here] 1496 * 1497 * See 12.8 1498 * 1499 */ 1500 private void breakStatement() { 1501 // Capture BREAK token. 1502 final int breakLine = line; 1503 final long breakToken = token; 1504 // BREAK tested in caller. 1505 nextOrEOL(); 1506 1507 ParserContextLabelNode labelNode = null; 1508 1509 // SEMICOLON or label. 1510 switch (type) { 1511 case RBRACE: 1512 case SEMICOLON: 1513 case EOL: 1514 case EOF: 1515 break; 1516 1517 default: 1518 final IdentNode ident = getIdent(); 1519 labelNode = lc.findLabel(ident.getName()); 1520 1521 if (labelNode == null) { 1522 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1523 } 1524 1525 break; 1526 } 1527 1528 //either an explicit label - then get its node or just a "break" - get first breakable 1529 //targetNode is what we are breaking out from. 1530 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1531 final ParserContextBreakableNode targetNode = lc.getBreakable(labelName); 1532 if (targetNode == null) { 1533 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 1534 } 1535 1536 endOfLine(); 1537 1538 // Construct and add BREAK node. 1539 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); 1540 } 1541 1542 /** 1543 * ReturnStatement : 1544 * return Expression? ; // [no LineTerminator here] 1545 * 1546 * See 12.9 1547 * 1548 * Parse RETURN statement. 1549 */ 1550 private void returnStatement() { 1551 // check for return outside function 1552 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { 1553 throw error(AbstractParser.message("invalid.return")); 1554 } 1555 1556 // Capture RETURN token. 1557 final int returnLine = line; 1558 final long returnToken = token; 1559 // RETURN tested in caller. 1560 nextOrEOL(); 1561 1562 Expression expression = null; 1563 1564 // SEMICOLON or expression. 1565 switch (type) { 1566 case RBRACE: 1567 case SEMICOLON: 1568 case EOL: 1569 case EOF: 1570 break; 1571 1572 default: 1573 expression = expression(); 1574 break; 1575 } 1576 1577 endOfLine(); 1578 1579 // Construct and add RETURN node. 1580 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); 1581 } 1582 1583 /** 1584 * YieldStatement : 1585 * yield Expression? ; // [no LineTerminator here] 1586 * 1587 * JavaScript 1.8 1588 * 1589 * Parse YIELD statement. 1590 */ 1591 private void yieldStatement() { 1592 // Capture YIELD token. 1593 final int yieldLine = line; 1594 final long yieldToken = token; 1595 // YIELD tested in caller. 1596 nextOrEOL(); 1597 1598 Expression expression = null; 1599 1600 // SEMICOLON or expression. 1601 switch (type) { 1602 case RBRACE: 1603 case SEMICOLON: 1604 case EOL: 1605 case EOF: 1606 break; 1607 1608 default: 1609 expression = expression(); 1610 break; 1611 } 1612 1613 endOfLine(); 1614 1615 // Construct and add YIELD node. 1616 appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); 1617 } 1618 1619 /** 1620 * WithStatement : 1621 * with ( Expression ) Statement 1622 * 1623 * See 12.10 1624 * 1625 * Parse WITH statement. 1626 */ 1627 private void withStatement() { 1628 // Capture WITH token. 1629 final int withLine = line; 1630 final long withToken = token; 1631 // WITH tested in caller. 1632 next(); 1633 1634 // ECMA 12.10.1 strict mode restrictions 1635 if (isStrictMode) { 1636 throw error(AbstractParser.message("strict.no.with"), withToken); 1637 } 1638 1639 expect(LPAREN); 1640 final Expression expression = expression(); 1641 expect(RPAREN); 1642 final Block body = getStatement(); 1643 1644 appendStatement(new WithNode(withLine, withToken, finish, expression, body)); 1645 } 1646 1647 /** 1648 * SwitchStatement : 1649 * switch ( Expression ) CaseBlock 1650 * 1651 * CaseBlock : 1652 * { CaseClauses? } 1653 * { CaseClauses? DefaultClause CaseClauses } 1654 * 1655 * CaseClauses : 1656 * CaseClause 1657 * CaseClauses CaseClause 1658 * 1659 * CaseClause : 1660 * case Expression : StatementList? 1661 * 1662 * DefaultClause : 1663 * default : StatementList? 1664 * 1665 * See 12.11 1666 * 1667 * Parse SWITCH statement. 1668 */ 1669 private void switchStatement() { 1670 final int switchLine = line; 1671 final long switchToken = token; 1672 // SWITCH tested in caller. 1673 next(); 1674 1675 // Create and add switch statement. 1676 final ParserContextSwitchNode switchNode= new ParserContextSwitchNode(); 1677 lc.push(switchNode); 1678 1679 CaseNode defaultCase = null; 1680 // Prepare to accumulate cases. 1681 final List<CaseNode> cases = new ArrayList<>(); 1682 1683 Expression expression = null; 1684 1685 try { 1686 expect(LPAREN); 1687 expression = expression(); 1688 expect(RPAREN); 1689 1690 expect(LBRACE); 1691 1692 1693 while (type != RBRACE) { 1694 // Prepare for next case. 1695 Expression caseExpression = null; 1696 final long caseToken = token; 1697 1698 switch (type) { 1699 case CASE: 1700 next(); 1701 caseExpression = expression(); 1702 break; 1703 1704 case DEFAULT: 1705 if (defaultCase != null) { 1706 throw error(AbstractParser.message("duplicate.default.in.switch")); 1707 } 1708 next(); 1709 break; 1710 1711 default: 1712 // Force an error. 1713 expect(CASE); 1714 break; 1715 } 1716 1717 expect(COLON); 1718 1719 // Get CASE body. 1720 final Block statements = getBlock(false); 1721 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); 1722 1723 if (caseExpression == null) { 1724 defaultCase = caseNode; 1725 } 1726 1727 cases.add(caseNode); 1728 } 1729 1730 next(); 1731 } finally { 1732 lc.pop(switchNode); 1733 } 1734 1735 appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase)); 1736 } 1737 1738 /** 1739 * LabelledStatement : 1740 * Identifier : Statement 1741 * 1742 * See 12.12 1743 * 1744 * Parse label statement. 1745 */ 1746 private void labelStatement() { 1747 // Capture label token. 1748 final long labelToken = token; 1749 // Get label ident. 1750 final IdentNode ident = getIdent(); 1751 1752 expect(COLON); 1753 1754 if (lc.findLabel(ident.getName()) != null) { 1755 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 1756 } 1757 1758 final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName()); 1759 Block body = null; 1760 try { 1761 lc.push(labelNode); 1762 body = getStatement(); 1763 } finally { 1764 assert lc.peek() instanceof ParserContextLabelNode; 1765 lc.pop(labelNode); 1766 } 1767 1768 appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body)); 1769 } 1770 1771 /** 1772 * ThrowStatement : 1773 * throw Expression ; // [no LineTerminator here] 1774 * 1775 * See 12.13 1776 * 1777 * Parse throw statement. 1778 */ 1779 private void throwStatement() { 1780 // Capture THROW token. 1781 final int throwLine = line; 1782 final long throwToken = token; 1783 // THROW tested in caller. 1784 nextOrEOL(); 1785 1786 Expression expression = null; 1787 1788 // SEMICOLON or expression. 1789 switch (type) { 1790 case RBRACE: 1791 case SEMICOLON: 1792 case EOL: 1793 break; 1794 1795 default: 1796 expression = expression(); 1797 break; 1798 } 1799 1800 if (expression == null) { 1801 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 1802 } 1803 1804 endOfLine(); 1805 1806 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); 1807 } 1808 1809 /** 1810 * TryStatement : 1811 * try Block Catch 1812 * try Block Finally 1813 * try Block Catch Finally 1814 * 1815 * Catch : 1816 * catch( Identifier if Expression ) Block 1817 * catch( Identifier ) Block 1818 * 1819 * Finally : 1820 * finally Block 1821 * 1822 * See 12.14 1823 * 1824 * Parse TRY statement. 1825 */ 1826 private void tryStatement() { 1827 // Capture TRY token. 1828 final int tryLine = line; 1829 final long tryToken = token; 1830 // TRY tested in caller. 1831 next(); 1832 1833 // Container block needed to act as target for labeled break statements 1834 final int startLine = line; 1835 final ParserContextBlockNode outer = newBlock(); 1836 // Create try. 1837 1838 try { 1839 final Block tryBody = getBlock(true); 1840 final List<Block> catchBlocks = new ArrayList<>(); 1841 1842 while (type == CATCH) { 1843 final int catchLine = line; 1844 final long catchToken = token; 1845 next(); 1846 expect(LPAREN); 1847 final IdentNode exception = getIdent(); 1848 1849 // ECMA 12.4.1 strict mode restrictions 1850 verifyStrictIdent(exception, "catch argument"); 1851 1852 // Nashorn extension: catch clause can have optional 1853 // condition. So, a single try can have more than one 1854 // catch clause each with it's own condition. 1855 final Expression ifExpression; 1856 if (!env._no_syntax_extensions && type == IF) { 1857 next(); 1858 // Get the exception condition. 1859 ifExpression = expression(); 1860 } else { 1861 ifExpression = null; 1862 } 1863 1864 expect(RPAREN); 1865 1866 final ParserContextBlockNode catchBlock = newBlock(); 1867 try { 1868 // Get CATCH body. 1869 final Block catchBody = getBlock(true); 1870 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); 1871 appendStatement(catchNode); 1872 } finally { 1873 restoreBlock(catchBlock); 1874 catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags() | Block.IS_SYNTHETIC, catchBlock.getStatements())); 1875 } 1876 1877 // If unconditional catch then should to be the end. 1878 if (ifExpression == null) { 1879 break; 1880 } 1881 } 1882 1883 // Prepare to capture finally statement. 1884 Block finallyStatements = null; 1885 1886 if (type == FINALLY) { 1887 next(); 1888 finallyStatements = getBlock(true); 1889 } 1890 1891 // Need at least one catch or a finally. 1892 if (catchBlocks.isEmpty() && finallyStatements == null) { 1893 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 1894 } 1895 1896 final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements); 1897 // Add try. 1898 assert lc.peek() == outer; 1899 appendStatement(tryNode); 1900 } finally { 1901 restoreBlock(outer); 1902 } 1903 1904 appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags() | Block.IS_SYNTHETIC, outer.getStatements()))); 1905 } 1906 1907 /** 1908 * DebuggerStatement : 1909 * debugger ; 1910 * 1911 * See 12.15 1912 * 1913 * Parse debugger statement. 1914 */ 1915 private void debuggerStatement() { 1916 // Capture DEBUGGER token. 1917 final int debuggerLine = line; 1918 final long debuggerToken = token; 1919 // DEBUGGER tested in caller. 1920 next(); 1921 endOfLine(); 1922 appendStatement(new DebuggerNode(debuggerLine, debuggerToken, finish)); 1923 } 1924 1925 /** 1926 * PrimaryExpression : 1927 * this 1928 * Identifier 1929 * Literal 1930 * ArrayLiteral 1931 * ObjectLiteral 1932 * ( Expression ) 1933 * 1934 * See 11.1 1935 * 1936 * Parse primary expression. 1937 * @return Expression node. 1938 */ 1939 @SuppressWarnings("fallthrough") 1940 private Expression primaryExpression() { 1941 // Capture first token. 1942 final int primaryLine = line; 1943 final long primaryToken = token; 1944 1945 switch (type) { 1946 case THIS: 1947 final String name = type.getName(); 1948 next(); 1949 lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS); 1950 return new IdentNode(primaryToken, finish, name); 1951 case IDENT: 1952 final IdentNode ident = getIdent(); 1953 if (ident == null) { 1954 break; 1955 } 1956 detectSpecialProperty(ident); 1957 return ident; 1958 case OCTAL_LEGACY: 1959 if (isStrictMode) { 1960 throw error(AbstractParser.message("strict.no.octal"), token); 1961 } 1962 case STRING: 1963 case ESCSTRING: 1964 case DECIMAL: 1965 case HEXADECIMAL: 1966 case OCTAL: 1967 case BINARY_NUMBER: 1968 case FLOATING: 1969 case REGEX: 1970 case XML: 1971 return getLiteral(); 1972 case EXECSTRING: 1973 return execString(primaryLine, primaryToken); 1974 case FALSE: 1975 next(); 1976 return LiteralNode.newInstance(primaryToken, finish, false); 1977 case TRUE: 1978 next(); 1979 return LiteralNode.newInstance(primaryToken, finish, true); 1980 case NULL: 1981 next(); 1982 return LiteralNode.newInstance(primaryToken, finish); 1983 case LBRACKET: 1984 return arrayLiteral(); 1985 case LBRACE: 1986 return objectLiteral(); 1987 case LPAREN: 1988 next(); 1989 1990 final Expression expression = expression(); 1991 1992 expect(RPAREN); 1993 1994 return expression; 1995 1996 default: 1997 // In this context some operator tokens mark the start of a literal. 1998 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 1999 next(); 2000 return getLiteral(); 2001 } 2002 if (isNonStrictModeIdent()) { 2003 return getIdent(); 2004 } 2005 break; 2006 } 2007 2008 return null; 2009 } 2010 2011 /** 2012 * Convert execString to a call to $EXEC. 2013 * 2014 * @param primaryToken Original string token. 2015 * @return callNode to $EXEC. 2016 */ 2017 CallNode execString(final int primaryLine, final long primaryToken) { 2018 // Synthesize an ident to call $EXEC. 2019 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 2020 // Skip over EXECSTRING. 2021 next(); 2022 // Set up argument list for call. 2023 // Skip beginning of edit string expression. 2024 expect(LBRACE); 2025 // Add the following expression to arguments. 2026 final List<Expression> arguments = Collections.singletonList(expression()); 2027 // Skip ending of edit string expression. 2028 expect(RBRACE); 2029 2030 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2031 } 2032 2033 /** 2034 * ArrayLiteral : 2035 * [ Elision? ] 2036 * [ ElementList ] 2037 * [ ElementList , Elision? ] 2038 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2039 * 2040 * ElementList : Elision? AssignmentExpression 2041 * ElementList , Elision? AssignmentExpression 2042 * 2043 * Elision : 2044 * , 2045 * Elision , 2046 * 2047 * See 12.1.4 2048 * JavaScript 1.8 2049 * 2050 * Parse array literal. 2051 * @return Expression node. 2052 */ 2053 private LiteralNode<Expression[]> arrayLiteral() { 2054 // Capture LBRACKET token. 2055 final long arrayToken = token; 2056 // LBRACKET tested in caller. 2057 next(); 2058 2059 // Prepare to accumulate elements. 2060 final List<Expression> elements = new ArrayList<>(); 2061 // Track elisions. 2062 boolean elision = true; 2063loop: 2064 while (true) { 2065 switch (type) { 2066 case RBRACKET: 2067 next(); 2068 2069 break loop; 2070 2071 case COMMARIGHT: 2072 next(); 2073 2074 // If no prior expression 2075 if (elision) { 2076 elements.add(null); 2077 } 2078 2079 elision = true; 2080 2081 break; 2082 2083 default: 2084 if (!elision) { 2085 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2086 } 2087 // Add expression element. 2088 final Expression expression = assignmentExpression(false); 2089 2090 if (expression != null) { 2091 elements.add(expression); 2092 } else { 2093 expect(RBRACKET); 2094 } 2095 2096 elision = false; 2097 break; 2098 } 2099 } 2100 2101 return LiteralNode.newInstance(arrayToken, finish, elements); 2102 } 2103 2104 /** 2105 * ObjectLiteral : 2106 * { } 2107 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2108 * 2109 * PropertyNameAndValueList : 2110 * PropertyAssignment 2111 * PropertyNameAndValueList , PropertyAssignment 2112 * 2113 * See 11.1.5 2114 * 2115 * Parse an object literal. 2116 * @return Expression node. 2117 */ 2118 private ObjectNode objectLiteral() { 2119 // Capture LBRACE token. 2120 final long objectToken = token; 2121 // LBRACE tested in caller. 2122 next(); 2123 2124 // Object context. 2125 // Prepare to accumulate elements. 2126 final List<PropertyNode> elements = new ArrayList<>(); 2127 final Map<String, Integer> map = new HashMap<>(); 2128 2129 // Create a block for the object literal. 2130 boolean commaSeen = true; 2131loop: 2132 while (true) { 2133 switch (type) { 2134 case RBRACE: 2135 next(); 2136 break loop; 2137 2138 case COMMARIGHT: 2139 if (commaSeen) { 2140 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2141 } 2142 next(); 2143 commaSeen = true; 2144 break; 2145 2146 default: 2147 if (!commaSeen) { 2148 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2149 } 2150 2151 commaSeen = false; 2152 // Get and add the next property. 2153 final PropertyNode property = propertyAssignment(); 2154 final String key = property.getKeyName(); 2155 final Integer existing = map.get(key); 2156 2157 if (existing == null) { 2158 map.put(key, elements.size()); 2159 elements.add(property); 2160 break; 2161 } 2162 2163 final PropertyNode existingProperty = elements.get(existing); 2164 2165 // ECMA section 11.1.5 Object Initialiser 2166 // point # 4 on property assignment production 2167 final Expression value = property.getValue(); 2168 final FunctionNode getter = property.getGetter(); 2169 final FunctionNode setter = property.getSetter(); 2170 2171 final Expression prevValue = existingProperty.getValue(); 2172 final FunctionNode prevGetter = existingProperty.getGetter(); 2173 final FunctionNode prevSetter = existingProperty.getSetter(); 2174 2175 // ECMA 11.1.5 strict mode restrictions 2176 if (isStrictMode && value != null && prevValue != null) { 2177 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2178 } 2179 2180 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2181 final boolean isAccessor = getter != null || setter != null; 2182 2183 // data property redefined as accessor property 2184 if (prevValue != null && isAccessor) { 2185 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2186 } 2187 2188 // accessor property redefined as data 2189 if (isPrevAccessor && value != null) { 2190 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2191 } 2192 2193 if (isAccessor && isPrevAccessor) { 2194 if (getter != null && prevGetter != null || 2195 setter != null && prevSetter != null) { 2196 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2197 } 2198 } 2199 2200 if (value != null) { 2201 elements.add(property); 2202 } else if (getter != null) { 2203 elements.set(existing, existingProperty.setGetter(getter)); 2204 } else if (setter != null) { 2205 elements.set(existing, existingProperty.setSetter(setter)); 2206 } 2207 break; 2208 } 2209 } 2210 2211 return new ObjectNode(objectToken, finish, elements); 2212 } 2213 2214 /** 2215 * PropertyName : 2216 * IdentifierName 2217 * StringLiteral 2218 * NumericLiteral 2219 * 2220 * See 11.1.5 2221 * 2222 * @return PropertyName node 2223 */ 2224 @SuppressWarnings("fallthrough") 2225 private PropertyKey propertyName() { 2226 switch (type) { 2227 case IDENT: 2228 return getIdent().setIsPropertyName(); 2229 case OCTAL_LEGACY: 2230 if (isStrictMode) { 2231 throw error(AbstractParser.message("strict.no.octal"), token); 2232 } 2233 case STRING: 2234 case ESCSTRING: 2235 case DECIMAL: 2236 case HEXADECIMAL: 2237 case OCTAL: 2238 case BINARY_NUMBER: 2239 case FLOATING: 2240 return getLiteral(); 2241 default: 2242 return getIdentifierName().setIsPropertyName(); 2243 } 2244 } 2245 2246 /** 2247 * PropertyAssignment : 2248 * PropertyName : AssignmentExpression 2249 * get PropertyName ( ) { FunctionBody } 2250 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2251 * 2252 * PropertySetParameterList : 2253 * Identifier 2254 * 2255 * PropertyName : 2256 * IdentifierName 2257 * StringLiteral 2258 * NumericLiteral 2259 * 2260 * See 11.1.5 2261 * 2262 * Parse an object literal property. 2263 * @return Property or reference node. 2264 */ 2265 private PropertyNode propertyAssignment() { 2266 // Capture firstToken. 2267 final long propertyToken = token; 2268 final int functionLine = line; 2269 2270 PropertyKey propertyName; 2271 2272 if (type == IDENT) { 2273 // Get IDENT. 2274 final String ident = (String)expectValue(IDENT); 2275 2276 if (type != COLON) { 2277 final long getSetToken = propertyToken; 2278 2279 switch (ident) { 2280 case "get": 2281 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 2282 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); 2283 2284 case "set": 2285 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 2286 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); 2287 default: 2288 break; 2289 } 2290 } 2291 2292 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 2293 } else { 2294 propertyName = propertyName(); 2295 } 2296 2297 expect(COLON); 2298 2299 defaultNames.push(propertyName); 2300 try { 2301 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2302 } finally { 2303 defaultNames.pop(); 2304 } 2305 } 2306 2307 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 2308 final PropertyKey getIdent = propertyName(); 2309 final String getterName = getIdent.getPropertyName(); 2310 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2311 expect(LPAREN); 2312 expect(RPAREN); 2313 2314 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); 2315 lc.push(functionNode); 2316 2317 Block functionBody; 2318 2319 2320 try { 2321 functionBody = functionBody(functionNode); 2322 } finally { 2323 lc.pop(functionNode); 2324 } 2325 2326 final FunctionNode function = createFunctionNode( 2327 functionNode, 2328 getSetToken, 2329 getNameNode, 2330 Collections.<IdentNode>emptyList(), 2331 FunctionNode.Kind.GETTER, 2332 functionLine, 2333 functionBody); 2334 2335 return new PropertyFunction(getIdent, function); 2336 } 2337 2338 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 2339 final PropertyKey setIdent = propertyName(); 2340 final String setterName = setIdent.getPropertyName(); 2341 final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2342 expect(LPAREN); 2343 // be sloppy and allow missing setter parameter even though 2344 // spec does not permit it! 2345 final IdentNode argIdent; 2346 if (type == IDENT || isNonStrictModeIdent()) { 2347 argIdent = getIdent(); 2348 verifyStrictIdent(argIdent, "setter argument"); 2349 } else { 2350 argIdent = null; 2351 } 2352 expect(RPAREN); 2353 final List<IdentNode> parameters = new ArrayList<>(); 2354 if (argIdent != null) { 2355 parameters.add(argIdent); 2356 } 2357 2358 2359 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); 2360 lc.push(functionNode); 2361 2362 Block functionBody; 2363 try { 2364 functionBody = functionBody(functionNode); 2365 } finally { 2366 lc.pop(functionNode); 2367 } 2368 2369 2370 final FunctionNode function = createFunctionNode( 2371 functionNode, 2372 getSetToken, 2373 setNameNode, 2374 parameters, 2375 FunctionNode.Kind.SETTER, 2376 functionLine, 2377 functionBody); 2378 2379 return new PropertyFunction(setIdent, function); 2380 } 2381 2382 private static class PropertyFunction { 2383 final PropertyKey ident; 2384 final FunctionNode functionNode; 2385 2386 PropertyFunction(final PropertyKey ident, final FunctionNode function) { 2387 this.ident = ident; 2388 this.functionNode = function; 2389 } 2390 } 2391 2392 /** 2393 * LeftHandSideExpression : 2394 * NewExpression 2395 * CallExpression 2396 * 2397 * CallExpression : 2398 * MemberExpression Arguments 2399 * CallExpression Arguments 2400 * CallExpression [ Expression ] 2401 * CallExpression . IdentifierName 2402 * 2403 * See 11.2 2404 * 2405 * Parse left hand side expression. 2406 * @return Expression node. 2407 */ 2408 private Expression leftHandSideExpression() { 2409 int callLine = line; 2410 long callToken = token; 2411 2412 Expression lhs = memberExpression(); 2413 2414 if (type == LPAREN) { 2415 final List<Expression> arguments = optimizeList(argumentList()); 2416 2417 // Catch special functions. 2418 if (lhs instanceof IdentNode) { 2419 detectSpecialFunction((IdentNode)lhs); 2420 } 2421 2422 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2423 } 2424 2425loop: 2426 while (true) { 2427 // Capture token. 2428 callLine = line; 2429 callToken = token; 2430 2431 switch (type) { 2432 case LPAREN: 2433 // Get NEW or FUNCTION arguments. 2434 final List<Expression> arguments = optimizeList(argumentList()); 2435 2436 // Create call node. 2437 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2438 2439 break; 2440 2441 case LBRACKET: 2442 next(); 2443 2444 // Get array index. 2445 final Expression rhs = expression(); 2446 2447 expect(RBRACKET); 2448 2449 // Create indexing node. 2450 lhs = new IndexNode(callToken, finish, lhs, rhs); 2451 2452 break; 2453 2454 case PERIOD: 2455 next(); 2456 2457 final IdentNode property = getIdentifierName(); 2458 2459 // Create property access node. 2460 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2461 2462 break; 2463 2464 default: 2465 break loop; 2466 } 2467 } 2468 2469 return lhs; 2470 } 2471 2472 /** 2473 * NewExpression : 2474 * MemberExpression 2475 * new NewExpression 2476 * 2477 * See 11.2 2478 * 2479 * Parse new expression. 2480 * @return Expression node. 2481 */ 2482 private Expression newExpression() { 2483 final long newToken = token; 2484 // NEW is tested in caller. 2485 next(); 2486 2487 // Get function base. 2488 final int callLine = line; 2489 final Expression constructor = memberExpression(); 2490 if (constructor == null) { 2491 return null; 2492 } 2493 // Get arguments. 2494 ArrayList<Expression> arguments; 2495 2496 // Allow for missing arguments. 2497 if (type == LPAREN) { 2498 arguments = argumentList(); 2499 } else { 2500 arguments = new ArrayList<>(); 2501 } 2502 2503 // Nashorn extension: This is to support the following interface implementation 2504 // syntax: 2505 // 2506 // var r = new java.lang.Runnable() { 2507 // run: function() { println("run"); } 2508 // }; 2509 // 2510 // The object literal following the "new Constructor()" expression 2511 // is passed as an additional (last) argument to the constructor. 2512 if (!env._no_syntax_extensions && type == LBRACE) { 2513 arguments.add(objectLiteral()); 2514 } 2515 2516 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 2517 2518 return new UnaryNode(newToken, callNode); 2519 } 2520 2521 /** 2522 * MemberExpression : 2523 * PrimaryExpression 2524 * FunctionExpression 2525 * MemberExpression [ Expression ] 2526 * MemberExpression . IdentifierName 2527 * new MemberExpression Arguments 2528 * 2529 * See 11.2 2530 * 2531 * Parse member expression. 2532 * @return Expression node. 2533 */ 2534 private Expression memberExpression() { 2535 // Prepare to build operation. 2536 Expression lhs; 2537 2538 switch (type) { 2539 case NEW: 2540 // Get new expression. 2541 lhs = newExpression(); 2542 break; 2543 2544 case FUNCTION: 2545 // Get function expression. 2546 lhs = functionExpression(false, false); 2547 break; 2548 2549 default: 2550 // Get primary expression. 2551 lhs = primaryExpression(); 2552 break; 2553 } 2554 2555loop: 2556 while (true) { 2557 // Capture token. 2558 final long callToken = token; 2559 2560 switch (type) { 2561 case LBRACKET: { 2562 next(); 2563 2564 // Get array index. 2565 final Expression index = expression(); 2566 2567 expect(RBRACKET); 2568 2569 // Create indexing node. 2570 lhs = new IndexNode(callToken, finish, lhs, index); 2571 2572 break; 2573 } 2574 case PERIOD: { 2575 if (lhs == null) { 2576 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2577 } 2578 2579 next(); 2580 2581 final IdentNode property = getIdentifierName(); 2582 2583 // Create property access node. 2584 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2585 2586 break; 2587 } 2588 default: 2589 break loop; 2590 } 2591 } 2592 2593 return lhs; 2594 } 2595 2596 /** 2597 * Arguments : 2598 * ( ) 2599 * ( ArgumentList ) 2600 * 2601 * ArgumentList : 2602 * AssignmentExpression 2603 * ArgumentList , AssignmentExpression 2604 * 2605 * See 11.2 2606 * 2607 * Parse function call arguments. 2608 * @return Argument list. 2609 */ 2610 private ArrayList<Expression> argumentList() { 2611 // Prepare to accumulate list of arguments. 2612 final ArrayList<Expression> nodeList = new ArrayList<>(); 2613 // LPAREN tested in caller. 2614 next(); 2615 2616 // Track commas. 2617 boolean first = true; 2618 2619 while (type != RPAREN) { 2620 // Comma prior to every argument except the first. 2621 if (!first) { 2622 expect(COMMARIGHT); 2623 } else { 2624 first = false; 2625 } 2626 2627 // Get argument expression. 2628 nodeList.add(assignmentExpression(false)); 2629 } 2630 2631 expect(RPAREN); 2632 return nodeList; 2633 } 2634 2635 private static <T> List<T> optimizeList(final ArrayList<T> list) { 2636 switch(list.size()) { 2637 case 0: { 2638 return Collections.emptyList(); 2639 } 2640 case 1: { 2641 return Collections.singletonList(list.get(0)); 2642 } 2643 default: { 2644 list.trimToSize(); 2645 return list; 2646 } 2647 } 2648 } 2649 2650 /** 2651 * FunctionDeclaration : 2652 * function Identifier ( FormalParameterList? ) { FunctionBody } 2653 * 2654 * FunctionExpression : 2655 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2656 * 2657 * See 13 2658 * 2659 * Parse function declaration. 2660 * @param isStatement True if for is a statement. 2661 * 2662 * @return Expression node. 2663 */ 2664 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2665 final long functionToken = token; 2666 final int functionLine = line; 2667 // FUNCTION is tested in caller. 2668 next(); 2669 2670 IdentNode name = null; 2671 2672 if (type == IDENT || isNonStrictModeIdent()) { 2673 name = getIdent(); 2674 verifyStrictIdent(name, "function name"); 2675 } else if (isStatement) { 2676 // Nashorn extension: anonymous function statements. 2677 // Do not allow anonymous function statement if extensions 2678 // are now allowed. But if we are reparsing then anon function 2679 // statement is possible - because it was used as function 2680 // expression in surrounding code. 2681 if (env._no_syntax_extensions && reparsedFunction == null) { 2682 expect(IDENT); 2683 } 2684 } 2685 2686 // name is null, generate anonymous name 2687 boolean isAnonymous = false; 2688 if (name == null) { 2689 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); 2690 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2691 isAnonymous = true; 2692 } 2693 2694 expect(LPAREN); 2695 final List<IdentNode> parameters = formalParameterList(); 2696 expect(RPAREN); 2697 2698 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); 2699 lc.push(functionNode); 2700 Block functionBody = null; 2701 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" 2702 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". 2703 hideDefaultName(); 2704 try{ 2705 functionBody = functionBody(functionNode); 2706 } finally { 2707 defaultNames.pop(); 2708 lc.pop(functionNode); 2709 } 2710 2711 if (isStatement) { 2712 if (topLevel || useBlockScope()) { 2713 functionNode.setFlag(FunctionNode.IS_DECLARED); 2714 } else if (isStrictMode) { 2715 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2716 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2717 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2718 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2719 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2720 } 2721 if (isArguments(name)) { 2722 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); 2723 } 2724 } 2725 2726 if (isAnonymous) { 2727 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 2728 } 2729 2730 final int arity = parameters.size(); 2731 2732 final boolean strict = functionNode.isStrict(); 2733 if (arity > 1) { 2734 final HashSet<String> parametersSet = new HashSet<>(arity); 2735 2736 for (int i = arity - 1; i >= 0; i--) { 2737 final IdentNode parameter = parameters.get(i); 2738 String parameterName = parameter.getName(); 2739 2740 if (isArguments(parameterName)) { 2741 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2742 } 2743 2744 if (parametersSet.contains(parameterName)) { 2745 // redefinition of parameter name 2746 if (strict) { 2747 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2748 } 2749 // rename in non-strict mode 2750 parameterName = functionNode.uniqueName(parameterName); 2751 final long parameterToken = parameter.getToken(); 2752 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2753 } 2754 2755 parametersSet.add(parameterName); 2756 } 2757 } else if (arity == 1) { 2758 if (isArguments(parameters.get(0))) { 2759 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2760 } 2761 } 2762 2763 final FunctionNode function = createFunctionNode( 2764 functionNode, 2765 functionToken, 2766 name, 2767 parameters, 2768 FunctionNode.Kind.NORMAL, 2769 functionLine, 2770 functionBody); 2771 2772 if (isStatement) { 2773 if (isAnonymous) { 2774 appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function)); 2775 return function; 2776 } 2777 2778 // mark ES6 block functions as lexically scoped 2779 final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; 2780 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); 2781 if (topLevel) { 2782 functionDeclarations.add(varNode); 2783 } else if (useBlockScope()) { 2784 prependStatement(varNode); // Hoist to beginning of current block 2785 } else { 2786 appendStatement(varNode); 2787 } 2788 } 2789 2790 return function; 2791 } 2792 2793 private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { 2794 final String defaultFunctionName = getDefaultFunctionName(); 2795 if (isValidIdentifier(defaultFunctionName)) { 2796 if (isStatement) { 2797 // The name will be used as the LHS of a symbol assignment. We add the anonymous function 2798 // prefix to ensure that it can't clash with another variable. 2799 return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; 2800 } 2801 return defaultFunctionName; 2802 } 2803 return ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2804 } 2805 2806 private static boolean isValidIdentifier(final String name) { 2807 if(name == null || name.isEmpty()) { 2808 return false; 2809 } 2810 if(!Character.isJavaIdentifierStart(name.charAt(0))) { 2811 return false; 2812 } 2813 for(int i = 1; i < name.length(); ++i) { 2814 if(!Character.isJavaIdentifierPart(name.charAt(i))) { 2815 return false; 2816 } 2817 } 2818 return true; 2819 } 2820 2821 private String getDefaultFunctionName() { 2822 if(!defaultNames.isEmpty()) { 2823 final Object nameExpr = defaultNames.peek(); 2824 if(nameExpr instanceof PropertyKey) { 2825 markDefaultNameUsed(); 2826 return ((PropertyKey)nameExpr).getPropertyName(); 2827 } else if(nameExpr instanceof AccessNode) { 2828 markDefaultNameUsed(); 2829 return ((AccessNode)nameExpr).getProperty(); 2830 } 2831 } 2832 return null; 2833 } 2834 2835 private void markDefaultNameUsed() { 2836 defaultNames.pop(); 2837 hideDefaultName(); 2838 } 2839 2840 private void hideDefaultName() { 2841 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 2842 // from. Can't be null 2843 defaultNames.push(""); 2844 } 2845 2846 /** 2847 * FormalParameterList : 2848 * Identifier 2849 * FormalParameterList , Identifier 2850 * 2851 * See 13 2852 * 2853 * Parse function parameter list. 2854 * @return List of parameter nodes. 2855 */ 2856 private List<IdentNode> formalParameterList() { 2857 return formalParameterList(RPAREN); 2858 } 2859 2860 /** 2861 * Same as the other method of the same name - except that the end 2862 * token type expected is passed as argument to this method. 2863 * 2864 * FormalParameterList : 2865 * Identifier 2866 * FormalParameterList , Identifier 2867 * 2868 * See 13 2869 * 2870 * Parse function parameter list. 2871 * @return List of parameter nodes. 2872 */ 2873 private List<IdentNode> formalParameterList(final TokenType endType) { 2874 // Prepare to gather parameters. 2875 final ArrayList<IdentNode> parameters = new ArrayList<>(); 2876 // Track commas. 2877 boolean first = true; 2878 2879 while (type != endType) { 2880 // Comma prior to every argument except the first. 2881 if (!first) { 2882 expect(COMMARIGHT); 2883 } else { 2884 first = false; 2885 } 2886 2887 // Get and add parameter. 2888 final IdentNode ident = getIdent(); 2889 2890 // ECMA 13.1 strict mode restrictions 2891 verifyStrictIdent(ident, "function parameter"); 2892 2893 parameters.add(ident); 2894 } 2895 2896 parameters.trimToSize(); 2897 return parameters; 2898 } 2899 2900 /** 2901 * FunctionBody : 2902 * SourceElements? 2903 * 2904 * See 13 2905 * 2906 * Parse function body. 2907 * @return function node (body.) 2908 */ 2909 private Block functionBody(final ParserContextFunctionNode functionNode) { 2910 long lastToken = 0L; 2911 ParserContextBlockNode body = null; 2912 final long bodyToken = token; 2913 Block functionBody; 2914 int bodyFinish = 0; 2915 2916 final boolean parseBody; 2917 Object endParserState = null; 2918 try { 2919 // Create a new function block. 2920 body = newBlock(); 2921 assert functionNode != null; 2922 final int functionId = functionNode.getId(); 2923 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 2924 // Nashorn extension: expression closures 2925 if (!env._no_syntax_extensions && type != LBRACE) { 2926 /* 2927 * Example: 2928 * 2929 * function square(x) x * x; 2930 * print(square(3)); 2931 */ 2932 2933 // just expression as function body 2934 final Expression expr = assignmentExpression(true); 2935 lastToken = previousToken; 2936 functionNode.setLastToken(previousToken); 2937 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2938 // EOL uses length field to store the line number 2939 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 2940 // Only create the return node if we aren't skipping nested functions. Note that we aren't 2941 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 2942 // they don't end with a single well known token, so it'd be very hard to get correctly (see 2943 // the note below for reasoning on skipping happening before instead of after RBRACE for 2944 // details). 2945 if (parseBody) { 2946 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 2947 appendStatement(returnNode); 2948 } 2949 } else { 2950 expectDontAdvance(LBRACE); 2951 if (parseBody || !skipFunctionBody(functionNode)) { 2952 next(); 2953 // Gather the function elements. 2954 final List<Statement> prevFunctionDecls = functionDeclarations; 2955 functionDeclarations = new ArrayList<>(); 2956 try { 2957 sourceElements(false); 2958 addFunctionDeclarations(functionNode); 2959 } finally { 2960 functionDeclarations = prevFunctionDecls; 2961 } 2962 2963 lastToken = token; 2964 if (parseBody) { 2965 // Since the lexer can read ahead and lexify some number of tokens in advance and have 2966 // them buffered in the TokenStream, we need to produce a lexer state as it was just 2967 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 2968 // ahead) state. 2969 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 2970 2971 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 2972 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 2973 // state after it. The reason is that RBRACE is a well-known token that we can expect and 2974 // will never involve us getting into a weird lexer state, and as such is a great reparse 2975 // point. Typical example of a weird lexer state after RBRACE would be: 2976 // function this_is_skipped() { ... } "use strict"; 2977 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 2978 // of compensating for the possibility of a string literal (or similar) after RBRACE, 2979 // we'll rather just restart parsing from this well-known, friendly token instead. 2980 } 2981 } 2982 bodyFinish = finish; 2983 functionNode.setLastToken(token); 2984 expect(RBRACE); 2985 } 2986 } finally { 2987 restoreBlock(body); 2988 } 2989 2990 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 2991 2992 if (parseBody) { 2993 functionNode.setEndParserState(endParserState); 2994 } else if (!body.getStatements().isEmpty()){ 2995 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 2996 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 2997 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 2998 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 2999 // nested bodies early if we were supposed to skip 'em. 3000 body.setStatements(Collections.<Statement>emptyList()); 3001 } 3002 3003 if (reparsedFunction != null) { 3004 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 3005 // eagerly parsed the code. We're doing it because some flags would be set based on the 3006 // content of the function, or even content of its nested functions, most of which are normally 3007 // skipped during an on-demand compilation. 3008 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 3009 if (data != null) { 3010 // Data can be null if when we originally parsed the file, we removed the function declaration 3011 // as it was dead code. 3012 functionNode.setFlag(data.getFunctionFlags()); 3013 // This compensates for missing markEval() in case the function contains an inner function 3014 // that contains eval(), that now we didn't discover since we skipped the inner function. 3015 if (functionNode.hasNestedEval()) { 3016 assert functionNode.hasScopeBlock(); 3017 body.setFlag(Block.NEEDS_SCOPE); 3018 } 3019 } 3020 } 3021 functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements()); 3022 return functionBody; 3023 } 3024 3025 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { 3026 if (reparsedFunction == null) { 3027 // Not reparsing, so don't skip any function body. 3028 return false; 3029 } 3030 // Skip to the RBRACE of this function, and continue parsing from there. 3031 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 3032 if (data == null) { 3033 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 3034 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 3035 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 3036 return false; 3037 } 3038 final ParserState parserState = (ParserState)data.getEndParserState(); 3039 assert parserState != null; 3040 3041 stream.reset(); 3042 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6); 3043 line = parserState.line; 3044 linePosition = parserState.linePosition; 3045 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 3046 // the RBRACE. 3047 type = SEMICOLON; 3048 k = -1; 3049 next(); 3050 3051 return true; 3052 } 3053 3054 /** 3055 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 3056 * for resuming parsing after skipping a function body. 3057 */ 3058 private static class ParserState implements Serializable { 3059 private final int position; 3060 private final int line; 3061 private final int linePosition; 3062 3063 private static final long serialVersionUID = -2382565130754093694L; 3064 3065 ParserState(final int position, final int line, final int linePosition) { 3066 this.position = position; 3067 this.line = line; 3068 this.linePosition = linePosition; 3069 } 3070 3071 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) { 3072 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true); 3073 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 3074 return newLexer; 3075 } 3076 } 3077 3078 private void printAST(final FunctionNode functionNode) { 3079 if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { 3080 env.getErr().println(new ASTWriter(functionNode)); 3081 } 3082 3083 if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { 3084 env.getErr().println(new PrintVisitor(functionNode, true, false)); 3085 } 3086 } 3087 3088 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { 3089 VarNode lastDecl = null; 3090 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 3091 Statement decl = functionDeclarations.get(i); 3092 if (lastDecl == null && decl instanceof VarNode) { 3093 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 3094 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); 3095 } 3096 prependStatement(decl); 3097 } 3098 } 3099 3100 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 3101 if (earlyError) { 3102 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 3103 } 3104 final ArrayList<Expression> args = new ArrayList<>(); 3105 args.add(lhs); 3106 if (rhs == null) { 3107 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 3108 } else { 3109 args.add(rhs); 3110 } 3111 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 3112 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 3113 } 3114 3115 /** 3116 * PostfixExpression : 3117 * LeftHandSideExpression 3118 * LeftHandSideExpression ++ // [no LineTerminator here] 3119 * LeftHandSideExpression -- // [no LineTerminator here] 3120 * 3121 * See 11.3 3122 * 3123 * UnaryExpression : 3124 * PostfixExpression 3125 * delete UnaryExpression 3126 * void UnaryExpression 3127 * typeof UnaryExpression 3128 * ++ UnaryExpression 3129 * -- UnaryExpression 3130 * + UnaryExpression 3131 * - UnaryExpression 3132 * ~ UnaryExpression 3133 * ! UnaryExpression 3134 * 3135 * See 11.4 3136 * 3137 * Parse unary expression. 3138 * @return Expression node. 3139 */ 3140 private Expression unaryExpression() { 3141 final int unaryLine = line; 3142 final long unaryToken = token; 3143 3144 switch (type) { 3145 case DELETE: { 3146 next(); 3147 final Expression expr = unaryExpression(); 3148 if (expr instanceof BaseNode || expr instanceof IdentNode) { 3149 return new UnaryNode(unaryToken, expr); 3150 } 3151 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 3152 return LiteralNode.newInstance(unaryToken, finish, true); 3153 } 3154 case VOID: 3155 case TYPEOF: 3156 case ADD: 3157 case SUB: 3158 case BIT_NOT: 3159 case NOT: 3160 next(); 3161 final Expression expr = unaryExpression(); 3162 return new UnaryNode(unaryToken, expr); 3163 3164 case INCPREFIX: 3165 case DECPREFIX: 3166 final TokenType opType = type; 3167 next(); 3168 3169 final Expression lhs = leftHandSideExpression(); 3170 // ++, -- without operand.. 3171 if (lhs == null) { 3172 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3173 } 3174 3175 if (!(lhs instanceof AccessNode || 3176 lhs instanceof IndexNode || 3177 lhs instanceof IdentNode)) { 3178 return referenceError(lhs, null, env._early_lvalue_error); 3179 } 3180 3181 if (lhs instanceof IdentNode) { 3182 if (!checkIdentLValue((IdentNode)lhs)) { 3183 return referenceError(lhs, null, false); 3184 } 3185 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3186 } 3187 3188 return incDecExpression(unaryToken, opType, lhs, false); 3189 3190 default: 3191 break; 3192 } 3193 3194 Expression expression = leftHandSideExpression(); 3195 3196 if (last != EOL) { 3197 switch (type) { 3198 case INCPREFIX: 3199 case DECPREFIX: 3200 final TokenType opType = type; 3201 final Expression lhs = expression; 3202 // ++, -- without operand.. 3203 if (lhs == null) { 3204 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3205 } 3206 3207 if (!(lhs instanceof AccessNode || 3208 lhs instanceof IndexNode || 3209 lhs instanceof IdentNode)) { 3210 next(); 3211 return referenceError(lhs, null, env._early_lvalue_error); 3212 } 3213 if (lhs instanceof IdentNode) { 3214 if (!checkIdentLValue((IdentNode)lhs)) { 3215 next(); 3216 return referenceError(lhs, null, false); 3217 } 3218 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3219 } 3220 expression = incDecExpression(token, type, expression, true); 3221 next(); 3222 break; 3223 default: 3224 break; 3225 } 3226 } 3227 3228 if (expression == null) { 3229 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3230 } 3231 3232 return expression; 3233 } 3234 3235 /** 3236 * {@code 3237 * MultiplicativeExpression : 3238 * UnaryExpression 3239 * MultiplicativeExpression * UnaryExpression 3240 * MultiplicativeExpression / UnaryExpression 3241 * MultiplicativeExpression % UnaryExpression 3242 * 3243 * See 11.5 3244 * 3245 * AdditiveExpression : 3246 * MultiplicativeExpression 3247 * AdditiveExpression + MultiplicativeExpression 3248 * AdditiveExpression - MultiplicativeExpression 3249 * 3250 * See 11.6 3251 * 3252 * ShiftExpression : 3253 * AdditiveExpression 3254 * ShiftExpression << AdditiveExpression 3255 * ShiftExpression >> AdditiveExpression 3256 * ShiftExpression >>> AdditiveExpression 3257 * 3258 * See 11.7 3259 * 3260 * RelationalExpression : 3261 * ShiftExpression 3262 * RelationalExpression < ShiftExpression 3263 * RelationalExpression > ShiftExpression 3264 * RelationalExpression <= ShiftExpression 3265 * RelationalExpression >= ShiftExpression 3266 * RelationalExpression instanceof ShiftExpression 3267 * RelationalExpression in ShiftExpression // if !noIf 3268 * 3269 * See 11.8 3270 * 3271 * RelationalExpression 3272 * EqualityExpression == RelationalExpression 3273 * EqualityExpression != RelationalExpression 3274 * EqualityExpression === RelationalExpression 3275 * EqualityExpression !== RelationalExpression 3276 * 3277 * See 11.9 3278 * 3279 * BitwiseANDExpression : 3280 * EqualityExpression 3281 * BitwiseANDExpression & EqualityExpression 3282 * 3283 * BitwiseXORExpression : 3284 * BitwiseANDExpression 3285 * BitwiseXORExpression ^ BitwiseANDExpression 3286 * 3287 * BitwiseORExpression : 3288 * BitwiseXORExpression 3289 * BitwiseORExpression | BitwiseXORExpression 3290 * 3291 * See 11.10 3292 * 3293 * LogicalANDExpression : 3294 * BitwiseORExpression 3295 * LogicalANDExpression && BitwiseORExpression 3296 * 3297 * LogicalORExpression : 3298 * LogicalANDExpression 3299 * LogicalORExpression || LogicalANDExpression 3300 * 3301 * See 11.11 3302 * 3303 * ConditionalExpression : 3304 * LogicalORExpression 3305 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 3306 * 3307 * See 11.12 3308 * 3309 * AssignmentExpression : 3310 * ConditionalExpression 3311 * LeftHandSideExpression AssignmentOperator AssignmentExpression 3312 * 3313 * AssignmentOperator : 3314 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 3315 * 3316 * See 11.13 3317 * 3318 * Expression : 3319 * AssignmentExpression 3320 * Expression , AssignmentExpression 3321 * 3322 * See 11.14 3323 * } 3324 * 3325 * Parse expression. 3326 * @return Expression node. 3327 */ 3328 protected Expression expression() { 3329 // This method is protected so that subclass can get details 3330 // at expression start point! 3331 3332 // Include commas in expression parsing. 3333 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 3334 } 3335 3336 private JoinPredecessorExpression joinPredecessorExpression() { 3337 return new JoinPredecessorExpression(expression()); 3338 } 3339 3340 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 3341 // Get the precedence of the next operator. 3342 int precedence = type.getPrecedence(); 3343 Expression lhs = exprLhs; 3344 3345 // While greater precedence. 3346 while (type.isOperator(noIn) && precedence >= minPrecedence) { 3347 // Capture the operator token. 3348 final long op = token; 3349 3350 if (type == TERNARY) { 3351 // Skip operator. 3352 next(); 3353 3354 // Pass expression. Middle expression of a conditional expression can be a "in" 3355 // expression - even in the contexts where "in" is not permitted. 3356 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 3357 3358 expect(COLON); 3359 3360 // Fail expression. 3361 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3362 3363 // Build up node. 3364 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 3365 } else { 3366 // Skip operator. 3367 next(); 3368 3369 // Get the next primary expression. 3370 Expression rhs; 3371 final boolean isAssign = Token.descType(op) == ASSIGN; 3372 if(isAssign) { 3373 defaultNames.push(lhs); 3374 } 3375 try { 3376 rhs = unaryExpression(); 3377 // Get precedence of next operator. 3378 int nextPrecedence = type.getPrecedence(); 3379 3380 // Subtask greater precedence. 3381 while (type.isOperator(noIn) && 3382 (nextPrecedence > precedence || 3383 nextPrecedence == precedence && !type.isLeftAssociative())) { 3384 rhs = expression(rhs, nextPrecedence, noIn); 3385 nextPrecedence = type.getPrecedence(); 3386 } 3387 } finally { 3388 if(isAssign) { 3389 defaultNames.pop(); 3390 } 3391 } 3392 lhs = verifyAssignment(op, lhs, rhs); 3393 } 3394 3395 precedence = type.getPrecedence(); 3396 } 3397 3398 return lhs; 3399 } 3400 3401 protected Expression assignmentExpression(final boolean noIn) { 3402 // This method is protected so that subclass can get details 3403 // at assignment expression start point! 3404 3405 // Exclude commas in expression parsing. 3406 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3407 } 3408 3409 /** 3410 * Parse an end of line. 3411 */ 3412 private void endOfLine() { 3413 switch (type) { 3414 case SEMICOLON: 3415 case EOL: 3416 next(); 3417 break; 3418 case RPAREN: 3419 case RBRACKET: 3420 case RBRACE: 3421 case EOF: 3422 break; 3423 default: 3424 if (last != EOL) { 3425 expect(SEMICOLON); 3426 } 3427 break; 3428 } 3429 } 3430 3431 @Override 3432 public String toString() { 3433 return "'JavaScript Parsing'"; 3434 } 3435 3436 private static void markEval(final ParserContext lc) { 3437 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 3438 boolean flaggedCurrentFn = false; 3439 while (iter.hasNext()) { 3440 final ParserContextFunctionNode fn = iter.next(); 3441 if (!flaggedCurrentFn) { 3442 fn.setFlag(FunctionNode.HAS_EVAL); 3443 flaggedCurrentFn = true; 3444 } else { 3445 fn.setFlag(FunctionNode.HAS_NESTED_EVAL); 3446 } 3447 final ParserContextBlockNode body = lc.getFunctionBody(fn); 3448 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 3449 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 3450 // this method when the parser skips a nested function. 3451 body.setFlag(Block.NEEDS_SCOPE); 3452 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); 3453 } 3454 } 3455 3456 private void prependStatement(final Statement statement) { 3457 lc.prependStatementToCurrentNode(statement); 3458 } 3459 3460 private void appendStatement(final Statement statement) { 3461 lc.appendStatementToCurrentNode(statement); 3462 } 3463} 3464