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