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