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