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