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