Parser.java revision 1401:d7d4c84bd750
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, 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); 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); 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 preceeding 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: 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 FLOATING: 1967 case REGEX: 1968 case XML: 1969 return getLiteral(); 1970 case EXECSTRING: 1971 return execString(primaryLine, primaryToken); 1972 case FALSE: 1973 next(); 1974 return LiteralNode.newInstance(primaryToken, finish, false); 1975 case TRUE: 1976 next(); 1977 return LiteralNode.newInstance(primaryToken, finish, true); 1978 case NULL: 1979 next(); 1980 return LiteralNode.newInstance(primaryToken, finish); 1981 case LBRACKET: 1982 return arrayLiteral(); 1983 case LBRACE: 1984 return objectLiteral(); 1985 case LPAREN: 1986 next(); 1987 1988 final Expression expression = expression(); 1989 1990 expect(RPAREN); 1991 1992 return expression; 1993 1994 default: 1995 // In this context some operator tokens mark the start of a literal. 1996 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 1997 next(); 1998 return getLiteral(); 1999 } 2000 if (isNonStrictModeIdent()) { 2001 return getIdent(); 2002 } 2003 break; 2004 } 2005 2006 return null; 2007 } 2008 2009 /** 2010 * Convert execString to a call to $EXEC. 2011 * 2012 * @param primaryToken Original string token. 2013 * @return callNode to $EXEC. 2014 */ 2015 CallNode execString(final int primaryLine, final long primaryToken) { 2016 // Synthesize an ident to call $EXEC. 2017 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 2018 // Skip over EXECSTRING. 2019 next(); 2020 // Set up argument list for call. 2021 // Skip beginning of edit string expression. 2022 expect(LBRACE); 2023 // Add the following expression to arguments. 2024 final List<Expression> arguments = Collections.singletonList(expression()); 2025 // Skip ending of edit string expression. 2026 expect(RBRACE); 2027 2028 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2029 } 2030 2031 /** 2032 * ArrayLiteral : 2033 * [ Elision? ] 2034 * [ ElementList ] 2035 * [ ElementList , Elision? ] 2036 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2037 * 2038 * ElementList : Elision? AssignmentExpression 2039 * ElementList , Elision? AssignmentExpression 2040 * 2041 * Elision : 2042 * , 2043 * Elision , 2044 * 2045 * See 12.1.4 2046 * JavaScript 1.8 2047 * 2048 * Parse array literal. 2049 * @return Expression node. 2050 */ 2051 private LiteralNode<Expression[]> arrayLiteral() { 2052 // Capture LBRACKET token. 2053 final long arrayToken = token; 2054 // LBRACKET tested in caller. 2055 next(); 2056 2057 // Prepare to accumulate elements. 2058 final List<Expression> elements = new ArrayList<>(); 2059 // Track elisions. 2060 boolean elision = true; 2061loop: 2062 while (true) { 2063 switch (type) { 2064 case RBRACKET: 2065 next(); 2066 2067 break loop; 2068 2069 case COMMARIGHT: 2070 next(); 2071 2072 // If no prior expression 2073 if (elision) { 2074 elements.add(null); 2075 } 2076 2077 elision = true; 2078 2079 break; 2080 2081 default: 2082 if (!elision) { 2083 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2084 } 2085 // Add expression element. 2086 final Expression expression = assignmentExpression(false); 2087 2088 if (expression != null) { 2089 elements.add(expression); 2090 } else { 2091 expect(RBRACKET); 2092 } 2093 2094 elision = false; 2095 break; 2096 } 2097 } 2098 2099 return LiteralNode.newInstance(arrayToken, finish, elements); 2100 } 2101 2102 /** 2103 * ObjectLiteral : 2104 * { } 2105 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2106 * 2107 * PropertyNameAndValueList : 2108 * PropertyAssignment 2109 * PropertyNameAndValueList , PropertyAssignment 2110 * 2111 * See 11.1.5 2112 * 2113 * Parse an object literal. 2114 * @return Expression node. 2115 */ 2116 private ObjectNode objectLiteral() { 2117 // Capture LBRACE token. 2118 final long objectToken = token; 2119 // LBRACE tested in caller. 2120 next(); 2121 2122 // Object context. 2123 // Prepare to accumulate elements. 2124 final List<PropertyNode> elements = new ArrayList<>(); 2125 final Map<String, Integer> map = new HashMap<>(); 2126 2127 // Create a block for the object literal. 2128 boolean commaSeen = true; 2129loop: 2130 while (true) { 2131 switch (type) { 2132 case RBRACE: 2133 next(); 2134 break loop; 2135 2136 case COMMARIGHT: 2137 if (commaSeen) { 2138 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2139 } 2140 next(); 2141 commaSeen = true; 2142 break; 2143 2144 default: 2145 if (!commaSeen) { 2146 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2147 } 2148 2149 commaSeen = false; 2150 // Get and add the next property. 2151 final PropertyNode property = propertyAssignment(); 2152 final String key = property.getKeyName(); 2153 final Integer existing = map.get(key); 2154 2155 if (existing == null) { 2156 map.put(key, elements.size()); 2157 elements.add(property); 2158 break; 2159 } 2160 2161 final PropertyNode existingProperty = elements.get(existing); 2162 2163 // ECMA section 11.1.5 Object Initialiser 2164 // point # 4 on property assignment production 2165 final Expression value = property.getValue(); 2166 final FunctionNode getter = property.getGetter(); 2167 final FunctionNode setter = property.getSetter(); 2168 2169 final Expression prevValue = existingProperty.getValue(); 2170 final FunctionNode prevGetter = existingProperty.getGetter(); 2171 final FunctionNode prevSetter = existingProperty.getSetter(); 2172 2173 // ECMA 11.1.5 strict mode restrictions 2174 if (isStrictMode && value != null && prevValue != null) { 2175 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2176 } 2177 2178 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2179 final boolean isAccessor = getter != null || setter != null; 2180 2181 // data property redefined as accessor property 2182 if (prevValue != null && isAccessor) { 2183 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2184 } 2185 2186 // accessor property redefined as data 2187 if (isPrevAccessor && value != null) { 2188 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2189 } 2190 2191 if (isAccessor && isPrevAccessor) { 2192 if (getter != null && prevGetter != null || 2193 setter != null && prevSetter != null) { 2194 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2195 } 2196 } 2197 2198 if (value != null) { 2199 elements.add(property); 2200 } else if (getter != null) { 2201 elements.set(existing, existingProperty.setGetter(getter)); 2202 } else if (setter != null) { 2203 elements.set(existing, existingProperty.setSetter(setter)); 2204 } 2205 break; 2206 } 2207 } 2208 2209 return new ObjectNode(objectToken, finish, elements); 2210 } 2211 2212 /** 2213 * PropertyName : 2214 * IdentifierName 2215 * StringLiteral 2216 * NumericLiteral 2217 * 2218 * See 11.1.5 2219 * 2220 * @return PropertyName node 2221 */ 2222 @SuppressWarnings("fallthrough") 2223 private PropertyKey propertyName() { 2224 switch (type) { 2225 case IDENT: 2226 return getIdent().setIsPropertyName(); 2227 case OCTAL: 2228 if (isStrictMode) { 2229 throw error(AbstractParser.message("strict.no.octal"), token); 2230 } 2231 case STRING: 2232 case ESCSTRING: 2233 case DECIMAL: 2234 case HEXADECIMAL: 2235 case FLOATING: 2236 return getLiteral(); 2237 default: 2238 return getIdentifierName().setIsPropertyName(); 2239 } 2240 } 2241 2242 /** 2243 * PropertyAssignment : 2244 * PropertyName : AssignmentExpression 2245 * get PropertyName ( ) { FunctionBody } 2246 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2247 * 2248 * PropertySetParameterList : 2249 * Identifier 2250 * 2251 * PropertyName : 2252 * IdentifierName 2253 * StringLiteral 2254 * NumericLiteral 2255 * 2256 * See 11.1.5 2257 * 2258 * Parse an object literal property. 2259 * @return Property or reference node. 2260 */ 2261 private PropertyNode propertyAssignment() { 2262 // Capture firstToken. 2263 final long propertyToken = token; 2264 final int functionLine = line; 2265 2266 PropertyKey propertyName; 2267 2268 if (type == IDENT) { 2269 // Get IDENT. 2270 final String ident = (String)expectValue(IDENT); 2271 2272 if (type != COLON) { 2273 final long getSetToken = propertyToken; 2274 2275 switch (ident) { 2276 case "get": 2277 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 2278 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); 2279 2280 case "set": 2281 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 2282 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); 2283 default: 2284 break; 2285 } 2286 } 2287 2288 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 2289 } else { 2290 propertyName = propertyName(); 2291 } 2292 2293 expect(COLON); 2294 2295 defaultNames.push(propertyName); 2296 try { 2297 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2298 } finally { 2299 defaultNames.pop(); 2300 } 2301 } 2302 2303 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 2304 final PropertyKey getIdent = propertyName(); 2305 final String getterName = getIdent.getPropertyName(); 2306 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2307 expect(LPAREN); 2308 expect(RPAREN); 2309 2310 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); 2311 lc.push(functionNode); 2312 2313 Block functionBody; 2314 2315 2316 try { 2317 functionBody = functionBody(functionNode); 2318 } finally { 2319 lc.pop(functionNode); 2320 } 2321 2322 final FunctionNode function = createFunctionNode( 2323 functionNode, 2324 getSetToken, 2325 getNameNode, 2326 Collections.<IdentNode>emptyList(), 2327 FunctionNode.Kind.GETTER, 2328 functionLine, 2329 functionBody); 2330 2331 return new PropertyFunction(getIdent, function); 2332 } 2333 2334 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 2335 final PropertyKey setIdent = propertyName(); 2336 final String setterName = setIdent.getPropertyName(); 2337 final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2338 expect(LPAREN); 2339 // be sloppy and allow missing setter parameter even though 2340 // spec does not permit it! 2341 final IdentNode argIdent; 2342 if (type == IDENT || isNonStrictModeIdent()) { 2343 argIdent = getIdent(); 2344 verifyStrictIdent(argIdent, "setter argument"); 2345 } else { 2346 argIdent = null; 2347 } 2348 expect(RPAREN); 2349 final List<IdentNode> parameters = new ArrayList<>(); 2350 if (argIdent != null) { 2351 parameters.add(argIdent); 2352 } 2353 2354 2355 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); 2356 lc.push(functionNode); 2357 2358 Block functionBody; 2359 try { 2360 functionBody = functionBody(functionNode); 2361 } finally { 2362 lc.pop(functionNode); 2363 } 2364 2365 2366 final FunctionNode function = createFunctionNode( 2367 functionNode, 2368 getSetToken, 2369 setNameNode, 2370 parameters, 2371 FunctionNode.Kind.SETTER, 2372 functionLine, 2373 functionBody); 2374 2375 return new PropertyFunction(setIdent, function); 2376 } 2377 2378 private static class PropertyFunction { 2379 final PropertyKey ident; 2380 final FunctionNode functionNode; 2381 2382 PropertyFunction(final PropertyKey ident, final FunctionNode function) { 2383 this.ident = ident; 2384 this.functionNode = function; 2385 } 2386 } 2387 2388 /** 2389 * LeftHandSideExpression : 2390 * NewExpression 2391 * CallExpression 2392 * 2393 * CallExpression : 2394 * MemberExpression Arguments 2395 * CallExpression Arguments 2396 * CallExpression [ Expression ] 2397 * CallExpression . IdentifierName 2398 * 2399 * See 11.2 2400 * 2401 * Parse left hand side expression. 2402 * @return Expression node. 2403 */ 2404 private Expression leftHandSideExpression() { 2405 int callLine = line; 2406 long callToken = token; 2407 2408 Expression lhs = memberExpression(); 2409 2410 if (type == LPAREN) { 2411 final List<Expression> arguments = optimizeList(argumentList()); 2412 2413 // Catch special functions. 2414 if (lhs instanceof IdentNode) { 2415 detectSpecialFunction((IdentNode)lhs); 2416 } 2417 2418 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2419 } 2420 2421loop: 2422 while (true) { 2423 // Capture token. 2424 callLine = line; 2425 callToken = token; 2426 2427 switch (type) { 2428 case LPAREN: 2429 // Get NEW or FUNCTION arguments. 2430 final List<Expression> arguments = optimizeList(argumentList()); 2431 2432 // Create call node. 2433 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2434 2435 break; 2436 2437 case LBRACKET: 2438 next(); 2439 2440 // Get array index. 2441 final Expression rhs = expression(); 2442 2443 expect(RBRACKET); 2444 2445 // Create indexing node. 2446 lhs = new IndexNode(callToken, finish, lhs, rhs); 2447 2448 break; 2449 2450 case PERIOD: 2451 next(); 2452 2453 final IdentNode property = getIdentifierName(); 2454 2455 // Create property access node. 2456 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2457 2458 break; 2459 2460 default: 2461 break loop; 2462 } 2463 } 2464 2465 return lhs; 2466 } 2467 2468 /** 2469 * NewExpression : 2470 * MemberExpression 2471 * new NewExpression 2472 * 2473 * See 11.2 2474 * 2475 * Parse new expression. 2476 * @return Expression node. 2477 */ 2478 private Expression newExpression() { 2479 final long newToken = token; 2480 // NEW is tested in caller. 2481 next(); 2482 2483 // Get function base. 2484 final int callLine = line; 2485 final Expression constructor = memberExpression(); 2486 if (constructor == null) { 2487 return null; 2488 } 2489 // Get arguments. 2490 ArrayList<Expression> arguments; 2491 2492 // Allow for missing arguments. 2493 if (type == LPAREN) { 2494 arguments = argumentList(); 2495 } else { 2496 arguments = new ArrayList<>(); 2497 } 2498 2499 // Nashorn extension: This is to support the following interface implementation 2500 // syntax: 2501 // 2502 // var r = new java.lang.Runnable() { 2503 // run: function() { println("run"); } 2504 // }; 2505 // 2506 // The object literal following the "new Constructor()" expresssion 2507 // is passed as an additional (last) argument to the constructor. 2508 if (!env._no_syntax_extensions && type == LBRACE) { 2509 arguments.add(objectLiteral()); 2510 } 2511 2512 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 2513 2514 return new UnaryNode(newToken, callNode); 2515 } 2516 2517 /** 2518 * MemberExpression : 2519 * PrimaryExpression 2520 * FunctionExpression 2521 * MemberExpression [ Expression ] 2522 * MemberExpression . IdentifierName 2523 * new MemberExpression Arguments 2524 * 2525 * See 11.2 2526 * 2527 * Parse member expression. 2528 * @return Expression node. 2529 */ 2530 private Expression memberExpression() { 2531 // Prepare to build operation. 2532 Expression lhs; 2533 2534 switch (type) { 2535 case NEW: 2536 // Get new expression. 2537 lhs = newExpression(); 2538 break; 2539 2540 case FUNCTION: 2541 // Get function expression. 2542 lhs = functionExpression(false, false); 2543 break; 2544 2545 default: 2546 // Get primary expression. 2547 lhs = primaryExpression(); 2548 break; 2549 } 2550 2551loop: 2552 while (true) { 2553 // Capture token. 2554 final long callToken = token; 2555 2556 switch (type) { 2557 case LBRACKET: { 2558 next(); 2559 2560 // Get array index. 2561 final Expression index = expression(); 2562 2563 expect(RBRACKET); 2564 2565 // Create indexing node. 2566 lhs = new IndexNode(callToken, finish, lhs, index); 2567 2568 break; 2569 } 2570 case PERIOD: { 2571 if (lhs == null) { 2572 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2573 } 2574 2575 next(); 2576 2577 final IdentNode property = getIdentifierName(); 2578 2579 // Create property access node. 2580 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2581 2582 break; 2583 } 2584 default: 2585 break loop; 2586 } 2587 } 2588 2589 return lhs; 2590 } 2591 2592 /** 2593 * Arguments : 2594 * ( ) 2595 * ( ArgumentList ) 2596 * 2597 * ArgumentList : 2598 * AssignmentExpression 2599 * ArgumentList , AssignmentExpression 2600 * 2601 * See 11.2 2602 * 2603 * Parse function call arguments. 2604 * @return Argument list. 2605 */ 2606 private ArrayList<Expression> argumentList() { 2607 // Prepare to accumulate list of arguments. 2608 final ArrayList<Expression> nodeList = new ArrayList<>(); 2609 // LPAREN tested in caller. 2610 next(); 2611 2612 // Track commas. 2613 boolean first = true; 2614 2615 while (type != RPAREN) { 2616 // Comma prior to every argument except the first. 2617 if (!first) { 2618 expect(COMMARIGHT); 2619 } else { 2620 first = false; 2621 } 2622 2623 // Get argument expression. 2624 nodeList.add(assignmentExpression(false)); 2625 } 2626 2627 expect(RPAREN); 2628 return nodeList; 2629 } 2630 2631 private static <T> List<T> optimizeList(final ArrayList<T> list) { 2632 switch(list.size()) { 2633 case 0: { 2634 return Collections.emptyList(); 2635 } 2636 case 1: { 2637 return Collections.singletonList(list.get(0)); 2638 } 2639 default: { 2640 list.trimToSize(); 2641 return list; 2642 } 2643 } 2644 } 2645 2646 /** 2647 * FunctionDeclaration : 2648 * function Identifier ( FormalParameterList? ) { FunctionBody } 2649 * 2650 * FunctionExpression : 2651 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2652 * 2653 * See 13 2654 * 2655 * Parse function declaration. 2656 * @param isStatement True if for is a statement. 2657 * 2658 * @return Expression node. 2659 */ 2660 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2661 final long functionToken = token; 2662 final int functionLine = line; 2663 // FUNCTION is tested in caller. 2664 next(); 2665 2666 IdentNode name = null; 2667 2668 if (type == IDENT || isNonStrictModeIdent()) { 2669 name = getIdent(); 2670 verifyStrictIdent(name, "function name"); 2671 } else if (isStatement) { 2672 // Nashorn extension: anonymous function statements. 2673 // Do not allow anonymous function statement if extensions 2674 // are now allowed. But if we are reparsing then anon function 2675 // statement is possible - because it was used as function 2676 // expression in surrounding code. 2677 if (env._no_syntax_extensions && reparsedFunction == null) { 2678 expect(IDENT); 2679 } 2680 } 2681 2682 // name is null, generate anonymous name 2683 boolean isAnonymous = false; 2684 if (name == null) { 2685 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); 2686 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2687 isAnonymous = true; 2688 } 2689 2690 expect(LPAREN); 2691 final List<IdentNode> parameters = formalParameterList(); 2692 expect(RPAREN); 2693 2694 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); 2695 lc.push(functionNode); 2696 Block functionBody = null; 2697 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" 2698 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". 2699 hideDefaultName(); 2700 try{ 2701 functionBody = functionBody(functionNode); 2702 } finally { 2703 defaultNames.pop(); 2704 lc.pop(functionNode); 2705 } 2706 2707 if (isStatement) { 2708 if (topLevel || useBlockScope()) { 2709 functionNode.setFlag(FunctionNode.IS_DECLARED); 2710 } else if (isStrictMode) { 2711 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2712 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2713 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2714 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2715 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2716 } 2717 if (isArguments(name)) { 2718 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); 2719 } 2720 } 2721 2722 if (isAnonymous) { 2723 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 2724 } 2725 2726 final int arity = parameters.size(); 2727 2728 final boolean strict = functionNode.isStrict(); 2729 if (arity > 1) { 2730 final HashSet<String> parametersSet = new HashSet<>(arity); 2731 2732 for (int i = arity - 1; i >= 0; i--) { 2733 final IdentNode parameter = parameters.get(i); 2734 String parameterName = parameter.getName(); 2735 2736 if (isArguments(parameterName)) { 2737 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2738 } 2739 2740 if (parametersSet.contains(parameterName)) { 2741 // redefinition of parameter name 2742 if (strict) { 2743 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2744 } 2745 // rename in non-strict mode 2746 parameterName = functionNode.uniqueName(parameterName); 2747 final long parameterToken = parameter.getToken(); 2748 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2749 } 2750 2751 parametersSet.add(parameterName); 2752 } 2753 } else if (arity == 1) { 2754 if (isArguments(parameters.get(0))) { 2755 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2756 } 2757 } 2758 2759 final FunctionNode function = createFunctionNode( 2760 functionNode, 2761 functionToken, 2762 name, 2763 parameters, 2764 FunctionNode.Kind.NORMAL, 2765 functionLine, 2766 functionBody); 2767 2768 if (isStatement) { 2769 if (isAnonymous) { 2770 appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function)); 2771 return function; 2772 } 2773 2774 // mark ES6 block functions as lexically scoped 2775 final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET; 2776 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); 2777 if (topLevel) { 2778 functionDeclarations.add(varNode); 2779 } else if (useBlockScope()) { 2780 prependStatement(varNode); // Hoist to beginning of current block 2781 } else { 2782 appendStatement(varNode); 2783 } 2784 } 2785 2786 return function; 2787 } 2788 2789 private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { 2790 final String defaultFunctionName = getDefaultFunctionName(); 2791 if (isValidIdentifier(defaultFunctionName)) { 2792 if (isStatement) { 2793 // The name will be used as the LHS of a symbol assignment. We add the anonymous function 2794 // prefix to ensure that it can't clash with another variable. 2795 return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; 2796 } 2797 return defaultFunctionName; 2798 } 2799 return ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2800 } 2801 2802 private static boolean isValidIdentifier(final String name) { 2803 if(name == null || name.isEmpty()) { 2804 return false; 2805 } 2806 if(!Character.isJavaIdentifierStart(name.charAt(0))) { 2807 return false; 2808 } 2809 for(int i = 1; i < name.length(); ++i) { 2810 if(!Character.isJavaIdentifierPart(name.charAt(i))) { 2811 return false; 2812 } 2813 } 2814 return true; 2815 } 2816 2817 private String getDefaultFunctionName() { 2818 if(!defaultNames.isEmpty()) { 2819 final Object nameExpr = defaultNames.peek(); 2820 if(nameExpr instanceof PropertyKey) { 2821 markDefaultNameUsed(); 2822 return ((PropertyKey)nameExpr).getPropertyName(); 2823 } else if(nameExpr instanceof AccessNode) { 2824 markDefaultNameUsed(); 2825 return ((AccessNode)nameExpr).getProperty(); 2826 } 2827 } 2828 return null; 2829 } 2830 2831 private void markDefaultNameUsed() { 2832 defaultNames.pop(); 2833 hideDefaultName(); 2834 } 2835 2836 private void hideDefaultName() { 2837 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 2838 // from. Can't be null 2839 defaultNames.push(""); 2840 } 2841 2842 /** 2843 * FormalParameterList : 2844 * Identifier 2845 * FormalParameterList , Identifier 2846 * 2847 * See 13 2848 * 2849 * Parse function parameter list. 2850 * @return List of parameter nodes. 2851 */ 2852 private List<IdentNode> formalParameterList() { 2853 return formalParameterList(RPAREN); 2854 } 2855 2856 /** 2857 * Same as the other method of the same name - except that the end 2858 * token type expected is passed as argument to this method. 2859 * 2860 * FormalParameterList : 2861 * Identifier 2862 * FormalParameterList , Identifier 2863 * 2864 * See 13 2865 * 2866 * Parse function parameter list. 2867 * @return List of parameter nodes. 2868 */ 2869 private List<IdentNode> formalParameterList(final TokenType endType) { 2870 // Prepare to gather parameters. 2871 final ArrayList<IdentNode> parameters = new ArrayList<>(); 2872 // Track commas. 2873 boolean first = true; 2874 2875 while (type != endType) { 2876 // Comma prior to every argument except the first. 2877 if (!first) { 2878 expect(COMMARIGHT); 2879 } else { 2880 first = false; 2881 } 2882 2883 // Get and add parameter. 2884 final IdentNode ident = getIdent(); 2885 2886 // ECMA 13.1 strict mode restrictions 2887 verifyStrictIdent(ident, "function parameter"); 2888 2889 parameters.add(ident); 2890 } 2891 2892 parameters.trimToSize(); 2893 return parameters; 2894 } 2895 2896 /** 2897 * FunctionBody : 2898 * SourceElements? 2899 * 2900 * See 13 2901 * 2902 * Parse function body. 2903 * @return function node (body.) 2904 */ 2905 private Block functionBody(final ParserContextFunctionNode functionNode) { 2906 long lastToken = 0L; 2907 ParserContextBlockNode body = null; 2908 final long bodyToken = token; 2909 Block functionBody; 2910 int bodyFinish = 0; 2911 2912 final boolean parseBody; 2913 Object endParserState = null; 2914 try { 2915 // Create a new function block. 2916 body = newBlock(); 2917 assert functionNode != null; 2918 final int functionId = functionNode.getId(); 2919 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 2920 // Nashorn extension: expression closures 2921 if (!env._no_syntax_extensions && type != LBRACE) { 2922 /* 2923 * Example: 2924 * 2925 * function square(x) x * x; 2926 * print(square(3)); 2927 */ 2928 2929 // just expression as function body 2930 final Expression expr = assignmentExpression(true); 2931 lastToken = previousToken; 2932 functionNode.setLastToken(previousToken); 2933 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2934 // EOL uses length field to store the line number 2935 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 2936 // Only create the return node if we aren't skipping nested functions. Note that we aren't 2937 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 2938 // they don't end with a single well known token, so it'd be very hard to get correctly (see 2939 // the note below for reasoning on skipping happening before instead of after RBRACE for 2940 // details). 2941 if (parseBody) { 2942 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 2943 appendStatement(returnNode); 2944 } 2945 } else { 2946 expectDontAdvance(LBRACE); 2947 if (parseBody || !skipFunctionBody(functionNode)) { 2948 next(); 2949 // Gather the function elements. 2950 final List<Statement> prevFunctionDecls = functionDeclarations; 2951 functionDeclarations = new ArrayList<>(); 2952 try { 2953 sourceElements(false); 2954 addFunctionDeclarations(functionNode); 2955 } finally { 2956 functionDeclarations = prevFunctionDecls; 2957 } 2958 2959 lastToken = token; 2960 if (parseBody) { 2961 // Since the lexer can read ahead and lexify some number of tokens in advance and have 2962 // them buffered in the TokenStream, we need to produce a lexer state as it was just 2963 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 2964 // ahead) state. 2965 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 2966 2967 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 2968 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 2969 // state after it. The reason is that RBRACE is a well-known token that we can expect and 2970 // will never involve us getting into a weird lexer state, and as such is a great reparse 2971 // point. Typical example of a weird lexer state after RBRACE would be: 2972 // function this_is_skipped() { ... } "use strict"; 2973 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 2974 // of compensating for the possibility of a string literal (or similar) after RBRACE, 2975 // we'll rather just restart parsing from this well-known, friendly token instead. 2976 } 2977 } 2978 bodyFinish = finish; 2979 functionNode.setLastToken(token); 2980 expect(RBRACE); 2981 } 2982 } finally { 2983 restoreBlock(body); 2984 } 2985 2986 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 2987 2988 if (parseBody) { 2989 functionNode.setEndParserState(endParserState); 2990 } else if (!body.getStatements().isEmpty()){ 2991 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 2992 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 2993 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 2994 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 2995 // nested bodies early if we were supposed to skip 'em. 2996 body.setStatements(Collections.<Statement>emptyList()); 2997 } 2998 2999 if (reparsedFunction != null) { 3000 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 3001 // eagerly parsed the code. We're doing it because some flags would be set based on the 3002 // content of the function, or even content of its nested functions, most of which are normally 3003 // skipped during an on-demand compilation. 3004 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 3005 if (data != null) { 3006 // Data can be null if when we originally parsed the file, we removed the function declaration 3007 // as it was dead code. 3008 functionNode.setFlag(data.getFunctionFlags()); 3009 // This compensates for missing markEval() in case the function contains an inner function 3010 // that contains eval(), that now we didn't discover since we skipped the inner function. 3011 if (functionNode.hasNestedEval()) { 3012 assert functionNode.hasScopeBlock(); 3013 body.setFlag(Block.NEEDS_SCOPE); 3014 } 3015 } 3016 } 3017 functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements()); 3018 return functionBody; 3019 } 3020 3021 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { 3022 if (reparsedFunction == null) { 3023 // Not reparsing, so don't skip any function body. 3024 return false; 3025 } 3026 // Skip to the RBRACE of this function, and continue parsing from there. 3027 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 3028 if (data == null) { 3029 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 3030 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 3031 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 3032 return false; 3033 } 3034 final ParserState parserState = (ParserState)data.getEndParserState(); 3035 assert parserState != null; 3036 3037 stream.reset(); 3038 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions); 3039 line = parserState.line; 3040 linePosition = parserState.linePosition; 3041 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 3042 // the RBRACE. 3043 type = SEMICOLON; 3044 k = -1; 3045 next(); 3046 3047 return true; 3048 } 3049 3050 /** 3051 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 3052 * for resuming parsing after skipping a function body. 3053 */ 3054 private static class ParserState implements Serializable { 3055 private final int position; 3056 private final int line; 3057 private final int linePosition; 3058 3059 private static final long serialVersionUID = -2382565130754093694L; 3060 3061 ParserState(final int position, final int line, final int linePosition) { 3062 this.position = position; 3063 this.line = line; 3064 this.linePosition = linePosition; 3065 } 3066 3067 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) { 3068 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true); 3069 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 3070 return newLexer; 3071 } 3072 } 3073 3074 private void printAST(final FunctionNode functionNode) { 3075 if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { 3076 env.getErr().println(new ASTWriter(functionNode)); 3077 } 3078 3079 if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { 3080 env.getErr().println(new PrintVisitor(functionNode, true, false)); 3081 } 3082 } 3083 3084 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { 3085 VarNode lastDecl = null; 3086 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 3087 Statement decl = functionDeclarations.get(i); 3088 if (lastDecl == null && decl instanceof VarNode) { 3089 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 3090 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); 3091 } 3092 prependStatement(decl); 3093 } 3094 } 3095 3096 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 3097 if (earlyError) { 3098 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 3099 } 3100 final ArrayList<Expression> args = new ArrayList<>(); 3101 args.add(lhs); 3102 if (rhs == null) { 3103 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 3104 } else { 3105 args.add(rhs); 3106 } 3107 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 3108 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 3109 } 3110 3111 /** 3112 * PostfixExpression : 3113 * LeftHandSideExpression 3114 * LeftHandSideExpression ++ // [no LineTerminator here] 3115 * LeftHandSideExpression -- // [no LineTerminator here] 3116 * 3117 * See 11.3 3118 * 3119 * UnaryExpression : 3120 * PostfixExpression 3121 * delete UnaryExpression 3122 * void UnaryExpression 3123 * typeof UnaryExpression 3124 * ++ UnaryExpression 3125 * -- UnaryExpression 3126 * + UnaryExpression 3127 * - UnaryExpression 3128 * ~ UnaryExpression 3129 * ! UnaryExpression 3130 * 3131 * See 11.4 3132 * 3133 * Parse unary expression. 3134 * @return Expression node. 3135 */ 3136 private Expression unaryExpression() { 3137 final int unaryLine = line; 3138 final long unaryToken = token; 3139 3140 switch (type) { 3141 case DELETE: { 3142 next(); 3143 final Expression expr = unaryExpression(); 3144 if (expr instanceof BaseNode || expr instanceof IdentNode) { 3145 return new UnaryNode(unaryToken, expr); 3146 } 3147 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 3148 return LiteralNode.newInstance(unaryToken, finish, true); 3149 } 3150 case VOID: 3151 case TYPEOF: 3152 case ADD: 3153 case SUB: 3154 case BIT_NOT: 3155 case NOT: 3156 next(); 3157 final Expression expr = unaryExpression(); 3158 return new UnaryNode(unaryToken, expr); 3159 3160 case INCPREFIX: 3161 case DECPREFIX: 3162 final TokenType opType = type; 3163 next(); 3164 3165 final Expression lhs = leftHandSideExpression(); 3166 // ++, -- without operand.. 3167 if (lhs == null) { 3168 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3169 } 3170 3171 if (!(lhs instanceof AccessNode || 3172 lhs instanceof IndexNode || 3173 lhs instanceof IdentNode)) { 3174 return referenceError(lhs, null, env._early_lvalue_error); 3175 } 3176 3177 if (lhs instanceof IdentNode) { 3178 if (!checkIdentLValue((IdentNode)lhs)) { 3179 return referenceError(lhs, null, false); 3180 } 3181 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3182 } 3183 3184 return incDecExpression(unaryToken, opType, lhs, false); 3185 3186 default: 3187 break; 3188 } 3189 3190 Expression expression = leftHandSideExpression(); 3191 3192 if (last != EOL) { 3193 switch (type) { 3194 case INCPREFIX: 3195 case DECPREFIX: 3196 final TokenType opType = type; 3197 final Expression lhs = expression; 3198 // ++, -- without operand.. 3199 if (lhs == null) { 3200 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3201 } 3202 3203 if (!(lhs instanceof AccessNode || 3204 lhs instanceof IndexNode || 3205 lhs instanceof IdentNode)) { 3206 next(); 3207 return referenceError(lhs, null, env._early_lvalue_error); 3208 } 3209 if (lhs instanceof IdentNode) { 3210 if (!checkIdentLValue((IdentNode)lhs)) { 3211 next(); 3212 return referenceError(lhs, null, false); 3213 } 3214 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3215 } 3216 expression = incDecExpression(token, type, expression, true); 3217 next(); 3218 break; 3219 default: 3220 break; 3221 } 3222 } 3223 3224 if (expression == null) { 3225 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3226 } 3227 3228 return expression; 3229 } 3230 3231 /** 3232 * {@code 3233 * MultiplicativeExpression : 3234 * UnaryExpression 3235 * MultiplicativeExpression * UnaryExpression 3236 * MultiplicativeExpression / UnaryExpression 3237 * MultiplicativeExpression % UnaryExpression 3238 * 3239 * See 11.5 3240 * 3241 * AdditiveExpression : 3242 * MultiplicativeExpression 3243 * AdditiveExpression + MultiplicativeExpression 3244 * AdditiveExpression - MultiplicativeExpression 3245 * 3246 * See 11.6 3247 * 3248 * ShiftExpression : 3249 * AdditiveExpression 3250 * ShiftExpression << AdditiveExpression 3251 * ShiftExpression >> AdditiveExpression 3252 * ShiftExpression >>> AdditiveExpression 3253 * 3254 * See 11.7 3255 * 3256 * RelationalExpression : 3257 * ShiftExpression 3258 * RelationalExpression < ShiftExpression 3259 * RelationalExpression > ShiftExpression 3260 * RelationalExpression <= ShiftExpression 3261 * RelationalExpression >= ShiftExpression 3262 * RelationalExpression instanceof ShiftExpression 3263 * RelationalExpression in ShiftExpression // if !noIf 3264 * 3265 * See 11.8 3266 * 3267 * RelationalExpression 3268 * EqualityExpression == RelationalExpression 3269 * EqualityExpression != RelationalExpression 3270 * EqualityExpression === RelationalExpression 3271 * EqualityExpression !== RelationalExpression 3272 * 3273 * See 11.9 3274 * 3275 * BitwiseANDExpression : 3276 * EqualityExpression 3277 * BitwiseANDExpression & EqualityExpression 3278 * 3279 * BitwiseXORExpression : 3280 * BitwiseANDExpression 3281 * BitwiseXORExpression ^ BitwiseANDExpression 3282 * 3283 * BitwiseORExpression : 3284 * BitwiseXORExpression 3285 * BitwiseORExpression | BitwiseXORExpression 3286 * 3287 * See 11.10 3288 * 3289 * LogicalANDExpression : 3290 * BitwiseORExpression 3291 * LogicalANDExpression && BitwiseORExpression 3292 * 3293 * LogicalORExpression : 3294 * LogicalANDExpression 3295 * LogicalORExpression || LogicalANDExpression 3296 * 3297 * See 11.11 3298 * 3299 * ConditionalExpression : 3300 * LogicalORExpression 3301 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 3302 * 3303 * See 11.12 3304 * 3305 * AssignmentExpression : 3306 * ConditionalExpression 3307 * LeftHandSideExpression AssignmentOperator AssignmentExpression 3308 * 3309 * AssignmentOperator : 3310 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 3311 * 3312 * See 11.13 3313 * 3314 * Expression : 3315 * AssignmentExpression 3316 * Expression , AssignmentExpression 3317 * 3318 * See 11.14 3319 * } 3320 * 3321 * Parse expression. 3322 * @return Expression node. 3323 */ 3324 protected Expression expression() { 3325 // This method is protected so that subclass can get details 3326 // at expression start point! 3327 3328 // Include commas in expression parsing. 3329 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 3330 } 3331 3332 private JoinPredecessorExpression joinPredecessorExpression() { 3333 return new JoinPredecessorExpression(expression()); 3334 } 3335 3336 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 3337 // Get the precedence of the next operator. 3338 int precedence = type.getPrecedence(); 3339 Expression lhs = exprLhs; 3340 3341 // While greater precedence. 3342 while (type.isOperator(noIn) && precedence >= minPrecedence) { 3343 // Capture the operator token. 3344 final long op = token; 3345 3346 if (type == TERNARY) { 3347 // Skip operator. 3348 next(); 3349 3350 // Pass expression. Middle expression of a conditional expression can be a "in" 3351 // expression - even in the contexts where "in" is not permitted. 3352 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 3353 3354 expect(COLON); 3355 3356 // Fail expression. 3357 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3358 3359 // Build up node. 3360 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 3361 } else { 3362 // Skip operator. 3363 next(); 3364 3365 // Get the next primary expression. 3366 Expression rhs; 3367 final boolean isAssign = Token.descType(op) == ASSIGN; 3368 if(isAssign) { 3369 defaultNames.push(lhs); 3370 } 3371 try { 3372 rhs = unaryExpression(); 3373 // Get precedence of next operator. 3374 int nextPrecedence = type.getPrecedence(); 3375 3376 // Subtask greater precedence. 3377 while (type.isOperator(noIn) && 3378 (nextPrecedence > precedence || 3379 nextPrecedence == precedence && !type.isLeftAssociative())) { 3380 rhs = expression(rhs, nextPrecedence, noIn); 3381 nextPrecedence = type.getPrecedence(); 3382 } 3383 } finally { 3384 if(isAssign) { 3385 defaultNames.pop(); 3386 } 3387 } 3388 lhs = verifyAssignment(op, lhs, rhs); 3389 } 3390 3391 precedence = type.getPrecedence(); 3392 } 3393 3394 return lhs; 3395 } 3396 3397 protected Expression assignmentExpression(final boolean noIn) { 3398 // This method is protected so that subclass can get details 3399 // at assignment expression start point! 3400 3401 // Exclude commas in expression parsing. 3402 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3403 } 3404 3405 /** 3406 * Parse an end of line. 3407 */ 3408 private void endOfLine() { 3409 switch (type) { 3410 case SEMICOLON: 3411 case EOL: 3412 next(); 3413 break; 3414 case RPAREN: 3415 case RBRACKET: 3416 case RBRACE: 3417 case EOF: 3418 break; 3419 default: 3420 if (last != EOL) { 3421 expect(SEMICOLON); 3422 } 3423 break; 3424 } 3425 } 3426 3427 @Override 3428 public String toString() { 3429 return "'JavaScript Parsing'"; 3430 } 3431 3432 private static void markEval(final ParserContext lc) { 3433 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 3434 boolean flaggedCurrentFn = false; 3435 while (iter.hasNext()) { 3436 final ParserContextFunctionNode fn = iter.next(); 3437 if (!flaggedCurrentFn) { 3438 fn.setFlag(FunctionNode.HAS_EVAL); 3439 flaggedCurrentFn = true; 3440 } else { 3441 fn.setFlag(FunctionNode.HAS_NESTED_EVAL); 3442 } 3443 final ParserContextBlockNode body = lc.getFunctionBody(fn); 3444 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 3445 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 3446 // this method when the parser skips a nested function. 3447 body.setFlag(Block.NEEDS_SCOPE); 3448 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); 3449 } 3450 } 3451 3452 private void prependStatement(final Statement statement) { 3453 lc.prependStatementToCurrentNode(statement); 3454 } 3455 3456 private void appendStatement(final Statement statement) { 3457 lc.appendStatementToCurrentNode(statement); 3458 } 3459} 3460