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