Parser.java revision 1115:a723569d0559
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(); 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); 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); 864 } 865 866 /** 867 * @param topLevel does this statement occur at the "top level" of a script or a function? 868 */ 869 private void statement(final boolean topLevel, final boolean allowPropertyFunction) { 870 if (type == FUNCTION) { 871 // As per spec (ECMA section 12), function declarations as arbitrary statement 872 // is not "portable". Implementation can issue a warning or disallow the same. 873 functionExpression(true, topLevel); 874 return; 875 } 876 877 switch (type) { 878 case LBRACE: 879 block(); 880 break; 881 case VAR: 882 variableStatement(type, true); 883 break; 884 case SEMICOLON: 885 emptyStatement(); 886 break; 887 case IF: 888 ifStatement(); 889 break; 890 case FOR: 891 forStatement(); 892 break; 893 case WHILE: 894 whileStatement(); 895 break; 896 case DO: 897 doStatement(); 898 break; 899 case CONTINUE: 900 continueStatement(); 901 break; 902 case BREAK: 903 breakStatement(); 904 break; 905 case RETURN: 906 returnStatement(); 907 break; 908 case YIELD: 909 yieldStatement(); 910 break; 911 case WITH: 912 withStatement(); 913 break; 914 case SWITCH: 915 switchStatement(); 916 break; 917 case THROW: 918 throwStatement(); 919 break; 920 case TRY: 921 tryStatement(); 922 break; 923 case DEBUGGER: 924 debuggerStatement(); 925 break; 926 case RPAREN: 927 case RBRACKET: 928 case EOF: 929 expect(SEMICOLON); 930 break; 931 default: 932 if (useBlockScope() && (type == LET || type == CONST)) { 933 variableStatement(type, true); 934 break; 935 } 936 if (env._const_as_var && type == CONST) { 937 variableStatement(TokenType.VAR, true); 938 break; 939 } 940 941 if (type == IDENT || isNonStrictModeIdent()) { 942 if (T(k + 1) == COLON) { 943 labelStatement(); 944 return; 945 } 946 if(allowPropertyFunction) { 947 final String ident = (String)getValue(); 948 final long propertyToken = token; 949 final int propertyLine = line; 950 if("get".equals(ident)) { 951 next(); 952 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine)); 953 return; 954 } else if("set".equals(ident)) { 955 next(); 956 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine)); 957 return; 958 } 959 } 960 } 961 962 expressionStatement(); 963 break; 964 } 965 } 966 967 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) { 968 final FunctionNode fn = propertyFunction.functionNode; 969 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn)); 970 } 971 972 /** 973 * block : 974 * { StatementList? } 975 * 976 * see 12.1 977 * 978 * Parse a statement block. 979 */ 980 private void block() { 981 appendStatement(new BlockStatement(line, getBlock(true))); 982 } 983 984 /** 985 * StatementList : 986 * Statement 987 * StatementList Statement 988 * 989 * See 12.1 990 * 991 * Parse a list of statements. 992 */ 993 private void statementList() { 994 // Accumulate statements until end of list. */ 995loop: 996 while (type != EOF) { 997 switch (type) { 998 case EOF: 999 case CASE: 1000 case DEFAULT: 1001 case RBRACE: 1002 break loop; 1003 default: 1004 break; 1005 } 1006 1007 // Get next statement. 1008 statement(); 1009 } 1010 } 1011 1012 /** 1013 * Make sure that in strict mode, the identifier name used is allowed. 1014 * 1015 * @param ident Identifier that is verified 1016 * @param contextString String used in error message to give context to the user 1017 */ 1018 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 1019 if (isStrictMode) { 1020 switch (ident.getName()) { 1021 case "eval": 1022 case "arguments": 1023 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1024 default: 1025 break; 1026 } 1027 1028 if (ident.isFutureStrictName()) { 1029 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 1030 } 1031 } 1032 } 1033 1034 /** 1035 * VariableStatement : 1036 * var VariableDeclarationList ; 1037 * 1038 * VariableDeclarationList : 1039 * VariableDeclaration 1040 * VariableDeclarationList , VariableDeclaration 1041 * 1042 * VariableDeclaration : 1043 * Identifier Initializer? 1044 * 1045 * Initializer : 1046 * = AssignmentExpression 1047 * 1048 * See 12.2 1049 * 1050 * Parse a VAR statement. 1051 * @param isStatement True if a statement (not used in a FOR.) 1052 */ 1053 private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement) { 1054 // VAR tested in caller. 1055 next(); 1056 1057 final List<VarNode> vars = new ArrayList<>(); 1058 int varFlags = VarNode.IS_STATEMENT; 1059 if (varType == LET) { 1060 varFlags |= VarNode.IS_LET; 1061 } else if (varType == CONST) { 1062 varFlags |= VarNode.IS_CONST; 1063 } 1064 1065 while (true) { 1066 // Get starting token. 1067 final int varLine = line; 1068 final long varToken = token; 1069 // Get name of var. 1070 final IdentNode name = getIdent(); 1071 verifyStrictIdent(name, "variable name"); 1072 1073 // Assume no init. 1074 Expression init = null; 1075 1076 // Look for initializer assignment. 1077 if (type == ASSIGN) { 1078 next(); 1079 1080 // Get initializer expression. Suppress IN if not statement. 1081 defaultNames.push(name); 1082 try { 1083 init = assignmentExpression(!isStatement); 1084 } finally { 1085 defaultNames.pop(); 1086 } 1087 } else if (varType == CONST) { 1088 throw error(AbstractParser.message("missing.const.assignment", name.getName())); 1089 } 1090 1091 // Allocate var node. 1092 final VarNode var = new VarNode(varLine, varToken, finish, name.setIsDeclaredHere(), init, varFlags); 1093 vars.add(var); 1094 appendStatement(var); 1095 1096 if (type != COMMARIGHT) { 1097 break; 1098 } 1099 next(); 1100 } 1101 1102 // If is a statement then handle end of line. 1103 if (isStatement) { 1104 endOfLine(); 1105 } 1106 1107 return vars; 1108 } 1109 1110 /** 1111 * EmptyStatement : 1112 * ; 1113 * 1114 * See 12.3 1115 * 1116 * Parse an empty statement. 1117 */ 1118 private void emptyStatement() { 1119 if (env._empty_statements) { 1120 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token))); 1121 } 1122 1123 // SEMICOLON checked in caller. 1124 next(); 1125 } 1126 1127 /** 1128 * ExpressionStatement : 1129 * Expression ; // [lookahead ~( or function )] 1130 * 1131 * See 12.4 1132 * 1133 * Parse an expression used in a statement block. 1134 */ 1135 private void expressionStatement() { 1136 // Lookahead checked in caller. 1137 final int expressionLine = line; 1138 final long expressionToken = token; 1139 1140 // Get expression and add as statement. 1141 final Expression expression = expression(); 1142 1143 ExpressionStatement expressionStatement = null; 1144 if (expression != null) { 1145 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression); 1146 appendStatement(expressionStatement); 1147 } else { 1148 expect(null); 1149 } 1150 1151 endOfLine(); 1152 } 1153 1154 /** 1155 * IfStatement : 1156 * if ( Expression ) Statement else Statement 1157 * if ( Expression ) Statement 1158 * 1159 * See 12.5 1160 * 1161 * Parse an IF statement. 1162 */ 1163 private void ifStatement() { 1164 // Capture IF token. 1165 final int ifLine = line; 1166 final long ifToken = token; 1167 // IF tested in caller. 1168 next(); 1169 1170 expect(LPAREN); 1171 final Expression test = expression(); 1172 expect(RPAREN); 1173 final Block pass = getStatement(); 1174 1175 Block fail = null; 1176 if (type == ELSE) { 1177 next(); 1178 fail = getStatement(); 1179 } 1180 1181 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 1182 } 1183 1184 /** 1185 * ... IterationStatement: 1186 * ... 1187 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement 1188 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement 1189 * for ( LeftHandSideExpression in Expression ) Statement 1190 * for ( var VariableDeclaration[NoIn] in Expression ) Statement 1191 * 1192 * See 12.6 1193 * 1194 * Parse a FOR statement. 1195 */ 1196 private void forStatement() { 1197 final long forToken = token; 1198 final int forLine = line; 1199 // When ES6 for-let is enabled we create a container block to capture the LET. 1200 final int startLine = start; 1201 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null; 1202 1203 1204 // Create FOR node, capturing FOR token. 1205 final ParserContextLoopNode forNode = new ParserContextLoopNode(); 1206 lc.push(forNode); 1207 Block body = null; 1208 List<VarNode> vars = null; 1209 Expression init = null; 1210 JoinPredecessorExpression test = null; 1211 JoinPredecessorExpression modify = null; 1212 1213 int flags = 0; 1214 1215 try { 1216 // FOR tested in caller. 1217 next(); 1218 1219 // Nashorn extension: for each expression. 1220 // iterate property values rather than property names. 1221 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 1222 flags |= ForNode.IS_FOR_EACH; 1223 next(); 1224 } 1225 1226 expect(LPAREN); 1227 1228 1229 switch (type) { 1230 case VAR: 1231 // Var statements captured in for outer block. 1232 vars = variableStatement(type, false); 1233 break; 1234 case SEMICOLON: 1235 break; 1236 default: 1237 if (useBlockScope() && (type == LET || type == CONST)) { 1238 // LET/CONST captured in container block created above. 1239 vars = variableStatement(type, false); 1240 break; 1241 } 1242 if (env._const_as_var && type == CONST) { 1243 // Var statements captured in for outer block. 1244 vars = variableStatement(TokenType.VAR, false); 1245 break; 1246 } 1247 1248 init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 1249 break; 1250 } 1251 1252 switch (type) { 1253 case SEMICOLON: 1254 // for (init; test; modify) 1255 1256 // for each (init; test; modify) is invalid 1257 if ((flags & ForNode.IS_FOR_EACH) != 0) { 1258 throw error(AbstractParser.message("for.each.without.in"), token); 1259 } 1260 1261 expect(SEMICOLON); 1262 if (type != SEMICOLON) { 1263 test = joinPredecessorExpression(); 1264 } 1265 expect(SEMICOLON); 1266 if (type != RPAREN) { 1267 modify = joinPredecessorExpression(); 1268 } 1269 break; 1270 1271 case IN: 1272 flags |= ForNode.IS_FOR_IN; 1273 test = new JoinPredecessorExpression(); 1274 if (vars != null) { 1275 // for (var i in obj) 1276 if (vars.size() == 1) { 1277 init = new IdentNode(vars.get(0).getName()); 1278 } else { 1279 // for (var i, j in obj) is invalid 1280 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 1281 } 1282 1283 } else { 1284 // for (expr in obj) 1285 assert init != null : "for..in init expression can not be null here"; 1286 1287 // check if initial expression is a valid L-value 1288 if (!(init instanceof AccessNode || 1289 init instanceof IndexNode || 1290 init instanceof IdentNode)) { 1291 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1292 } 1293 1294 if (init instanceof IdentNode) { 1295 if (!checkIdentLValue((IdentNode)init)) { 1296 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 1297 } 1298 verifyStrictIdent((IdentNode)init, "for-in iterator"); 1299 } 1300 } 1301 1302 next(); 1303 1304 // Get the collection expression. 1305 modify = joinPredecessorExpression(); 1306 break; 1307 1308 default: 1309 expect(SEMICOLON); 1310 break; 1311 } 1312 1313 expect(RPAREN); 1314 1315 // Set the for body. 1316 body = getStatement(); 1317 } finally { 1318 lc.pop(forNode); 1319 if (vars != null) { 1320 for (final VarNode var : vars) { 1321 appendStatement(var); 1322 } 1323 } 1324 if (body != null) { 1325 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify)); 1326 } 1327 if (outer != null) { 1328 restoreBlock(outer); 1329 appendStatement(new BlockStatement(startLine, new Block( 1330 outer.getToken(), 1331 body.getFinish(), 1332 outer.getStatements()))); 1333 } 1334 } 1335 } 1336 1337 /** 1338 * ...IterationStatement : 1339 * ... 1340 * while ( Expression ) Statement 1341 * ... 1342 * 1343 * See 12.6 1344 * 1345 * Parse while statement. 1346 */ 1347 private void whileStatement() { 1348 // Capture WHILE token. 1349 final long whileToken = token; 1350 final int whileLine = line; 1351 // WHILE tested in caller. 1352 next(); 1353 1354 final ParserContextLoopNode whileNode = new ParserContextLoopNode(); 1355 lc.push(whileNode); 1356 1357 JoinPredecessorExpression test = null; 1358 Block body = null; 1359 1360 try { 1361 expect(LPAREN); 1362 test = joinPredecessorExpression(); 1363 expect(RPAREN); 1364 body = getStatement(); 1365 } finally { 1366 lc.pop(whileNode); 1367 if (body != null){ 1368 appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body)); 1369 } 1370 } 1371 } 1372 1373 /** 1374 * ...IterationStatement : 1375 * ... 1376 * do Statement while( Expression ) ; 1377 * ... 1378 * 1379 * See 12.6 1380 * 1381 * Parse DO WHILE statement. 1382 */ 1383 private void doStatement() { 1384 // Capture DO token. 1385 final long doToken = token; 1386 int doLine = 0; 1387 // DO tested in the caller. 1388 next(); 1389 1390 final ParserContextLoopNode doWhileNode = new ParserContextLoopNode(); 1391 lc.push(doWhileNode); 1392 1393 Block body = null; 1394 JoinPredecessorExpression test = null; 1395 1396 try { 1397 // Get DO body. 1398 body = getStatement(); 1399 1400 expect(WHILE); 1401 expect(LPAREN); 1402 doLine = line; 1403 test = joinPredecessorExpression(); 1404 expect(RPAREN); 1405 1406 if (type == SEMICOLON) { 1407 endOfLine(); 1408 } 1409 } finally { 1410 lc.pop(doWhileNode); 1411 appendStatement(new WhileNode(doLine, doToken, finish, true, test, body)); 1412 } 1413 } 1414 1415 /** 1416 * ContinueStatement : 1417 * continue Identifier? ; // [no LineTerminator here] 1418 * 1419 * See 12.7 1420 * 1421 * Parse CONTINUE statement. 1422 */ 1423 private void continueStatement() { 1424 // Capture CONTINUE token. 1425 final int continueLine = line; 1426 final long continueToken = token; 1427 // CONTINUE tested in caller. 1428 nextOrEOL(); 1429 1430 ParserContextLabelNode labelNode = null; 1431 1432 // SEMICOLON or label. 1433 switch (type) { 1434 case RBRACE: 1435 case SEMICOLON: 1436 case EOL: 1437 case EOF: 1438 break; 1439 1440 default: 1441 final IdentNode ident = getIdent(); 1442 labelNode = lc.findLabel(ident.getName()); 1443 1444 if (labelNode == null) { 1445 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1446 } 1447 1448 break; 1449 } 1450 1451 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1452 final ParserContextLoopNode targetNode = lc.getContinueTo(labelName); 1453 1454 if (targetNode == null) { 1455 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 1456 } 1457 1458 endOfLine(); 1459 1460 // Construct and add CONTINUE node. 1461 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName)); 1462 } 1463 1464 /** 1465 * BreakStatement : 1466 * break Identifier? ; // [no LineTerminator here] 1467 * 1468 * See 12.8 1469 * 1470 */ 1471 private void breakStatement() { 1472 // Capture BREAK token. 1473 final int breakLine = line; 1474 final long breakToken = token; 1475 // BREAK tested in caller. 1476 nextOrEOL(); 1477 1478 ParserContextLabelNode labelNode = null; 1479 1480 // SEMICOLON or label. 1481 switch (type) { 1482 case RBRACE: 1483 case SEMICOLON: 1484 case EOL: 1485 case EOF: 1486 break; 1487 1488 default: 1489 final IdentNode ident = getIdent(); 1490 labelNode = lc.findLabel(ident.getName()); 1491 1492 if (labelNode == null) { 1493 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1494 } 1495 1496 break; 1497 } 1498 1499 //either an explicit label - then get its node or just a "break" - get first breakable 1500 //targetNode is what we are breaking out from. 1501 final String labelName = labelNode == null ? null : labelNode.getLabelName(); 1502 final ParserContextBreakableNode targetNode = lc.getBreakable(labelName); 1503 if (targetNode == null) { 1504 throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 1505 } 1506 1507 endOfLine(); 1508 1509 // Construct and add BREAK node. 1510 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName)); 1511 } 1512 1513 /** 1514 * ReturnStatement : 1515 * return Expression? ; // [no LineTerminator here] 1516 * 1517 * See 12.9 1518 * 1519 * Parse RETURN statement. 1520 */ 1521 private void returnStatement() { 1522 // check for return outside function 1523 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { 1524 throw error(AbstractParser.message("invalid.return")); 1525 } 1526 1527 // Capture RETURN token. 1528 final int returnLine = line; 1529 final long returnToken = token; 1530 // RETURN tested in caller. 1531 nextOrEOL(); 1532 1533 Expression expression = null; 1534 1535 // SEMICOLON or expression. 1536 switch (type) { 1537 case RBRACE: 1538 case SEMICOLON: 1539 case EOL: 1540 case EOF: 1541 break; 1542 1543 default: 1544 expression = expression(); 1545 break; 1546 } 1547 1548 endOfLine(); 1549 1550 // Construct and add RETURN node. 1551 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression)); 1552 } 1553 1554 /** 1555 * YieldStatement : 1556 * yield Expression? ; // [no LineTerminator here] 1557 * 1558 * JavaScript 1.8 1559 * 1560 * Parse YIELD statement. 1561 */ 1562 private void yieldStatement() { 1563 // Capture YIELD token. 1564 final int yieldLine = line; 1565 final long yieldToken = token; 1566 // YIELD tested in caller. 1567 nextOrEOL(); 1568 1569 Expression expression = null; 1570 1571 // SEMICOLON or expression. 1572 switch (type) { 1573 case RBRACE: 1574 case SEMICOLON: 1575 case EOL: 1576 case EOF: 1577 break; 1578 1579 default: 1580 expression = expression(); 1581 break; 1582 } 1583 1584 endOfLine(); 1585 1586 // Construct and add YIELD node. 1587 appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression)); 1588 } 1589 1590 /** 1591 * WithStatement : 1592 * with ( Expression ) Statement 1593 * 1594 * See 12.10 1595 * 1596 * Parse WITH statement. 1597 */ 1598 private void withStatement() { 1599 // Capture WITH token. 1600 final int withLine = line; 1601 final long withToken = token; 1602 // WITH tested in caller. 1603 next(); 1604 1605 // ECMA 12.10.1 strict mode restrictions 1606 if (isStrictMode) { 1607 throw error(AbstractParser.message("strict.no.with"), withToken); 1608 } 1609 1610 Expression expression = null; 1611 Block body = null; 1612 try { 1613 expect(LPAREN); 1614 expression = expression(); 1615 expect(RPAREN); 1616 body = getStatement(); 1617 } finally { 1618 appendStatement(new WithNode(withLine, withToken, finish, expression, body)); 1619 } 1620 1621 } 1622 1623 /** 1624 * SwitchStatement : 1625 * switch ( Expression ) CaseBlock 1626 * 1627 * CaseBlock : 1628 * { CaseClauses? } 1629 * { CaseClauses? DefaultClause CaseClauses } 1630 * 1631 * CaseClauses : 1632 * CaseClause 1633 * CaseClauses CaseClause 1634 * 1635 * CaseClause : 1636 * case Expression : StatementList? 1637 * 1638 * DefaultClause : 1639 * default : StatementList? 1640 * 1641 * See 12.11 1642 * 1643 * Parse SWITCH statement. 1644 */ 1645 private void switchStatement() { 1646 final int switchLine = line; 1647 final long switchToken = token; 1648 // SWITCH tested in caller. 1649 next(); 1650 1651 // Create and add switch statement. 1652 final ParserContextSwitchNode switchNode= new ParserContextSwitchNode(); 1653 lc.push(switchNode); 1654 1655 CaseNode defaultCase = null; 1656 // Prepare to accumulate cases. 1657 final List<CaseNode> cases = new ArrayList<>(); 1658 1659 Expression expression = null; 1660 1661 try { 1662 expect(LPAREN); 1663 expression = expression(); 1664 expect(RPAREN); 1665 1666 expect(LBRACE); 1667 1668 1669 while (type != RBRACE) { 1670 // Prepare for next case. 1671 Expression caseExpression = null; 1672 final long caseToken = token; 1673 1674 switch (type) { 1675 case CASE: 1676 next(); 1677 caseExpression = expression(); 1678 break; 1679 1680 case DEFAULT: 1681 if (defaultCase != null) { 1682 throw error(AbstractParser.message("duplicate.default.in.switch")); 1683 } 1684 next(); 1685 break; 1686 1687 default: 1688 // Force an error. 1689 expect(CASE); 1690 break; 1691 } 1692 1693 expect(COLON); 1694 1695 // Get CASE body. 1696 final Block statements = getBlock(false); 1697 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements); 1698 1699 if (caseExpression == null) { 1700 defaultCase = caseNode; 1701 } 1702 1703 cases.add(caseNode); 1704 } 1705 1706 next(); 1707 } finally { 1708 lc.pop(switchNode); 1709 appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase)); 1710 } 1711 } 1712 1713 /** 1714 * LabelledStatement : 1715 * Identifier : Statement 1716 * 1717 * See 12.12 1718 * 1719 * Parse label statement. 1720 */ 1721 private void labelStatement() { 1722 // Capture label token. 1723 final long labelToken = token; 1724 // Get label ident. 1725 final IdentNode ident = getIdent(); 1726 1727 expect(COLON); 1728 1729 if (lc.findLabel(ident.getName()) != null) { 1730 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 1731 } 1732 1733 final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName()); 1734 Block body = null; 1735 try { 1736 lc.push(labelNode); 1737 body = getStatement(); 1738 } finally { 1739 assert lc.peek() instanceof ParserContextLabelNode; 1740 lc.pop(labelNode); 1741 if (ident != null){ 1742 appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body)); 1743 } 1744 } 1745 } 1746 1747 /** 1748 * ThrowStatement : 1749 * throw Expression ; // [no LineTerminator here] 1750 * 1751 * See 12.13 1752 * 1753 * Parse throw statement. 1754 */ 1755 private void throwStatement() { 1756 // Capture THROW token. 1757 final int throwLine = line; 1758 final long throwToken = token; 1759 // THROW tested in caller. 1760 nextOrEOL(); 1761 1762 Expression expression = null; 1763 1764 // SEMICOLON or expression. 1765 switch (type) { 1766 case RBRACE: 1767 case SEMICOLON: 1768 case EOL: 1769 break; 1770 1771 default: 1772 expression = expression(); 1773 break; 1774 } 1775 1776 if (expression == null) { 1777 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 1778 } 1779 1780 endOfLine(); 1781 1782 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false)); 1783 } 1784 1785 /** 1786 * TryStatement : 1787 * try Block Catch 1788 * try Block Finally 1789 * try Block Catch Finally 1790 * 1791 * Catch : 1792 * catch( Identifier if Expression ) Block 1793 * catch( Identifier ) Block 1794 * 1795 * Finally : 1796 * finally Block 1797 * 1798 * See 12.14 1799 * 1800 * Parse TRY statement. 1801 */ 1802 private void tryStatement() { 1803 // Capture TRY token. 1804 final int tryLine = line; 1805 final long tryToken = token; 1806 // TRY tested in caller. 1807 next(); 1808 1809 // Container block needed to act as target for labeled break statements 1810 final int startLine = line; 1811 final ParserContextBlockNode outer = newBlock(); 1812 // Create try. 1813 1814 try { 1815 final Block tryBody = getBlock(true); 1816 final List<Block> catchBlocks = new ArrayList<>(); 1817 1818 while (type == CATCH) { 1819 final int catchLine = line; 1820 final long catchToken = token; 1821 next(); 1822 expect(LPAREN); 1823 final IdentNode exception = getIdent(); 1824 1825 // ECMA 12.4.1 strict mode restrictions 1826 verifyStrictIdent(exception, "catch argument"); 1827 1828 // Nashorn extension: catch clause can have optional 1829 // condition. So, a single try can have more than one 1830 // catch clause each with it's own condition. 1831 final Expression ifExpression; 1832 if (!env._no_syntax_extensions && type == IF) { 1833 next(); 1834 // Get the exception condition. 1835 ifExpression = expression(); 1836 } else { 1837 ifExpression = null; 1838 } 1839 1840 expect(RPAREN); 1841 1842 final ParserContextBlockNode catchBlock = newBlock(); 1843 try { 1844 // Get CATCH body. 1845 final Block catchBody = getBlock(true); 1846 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false); 1847 appendStatement(catchNode); 1848 } finally { 1849 restoreBlock(catchBlock); 1850 catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags(), catchBlock.getStatements())); 1851 } 1852 1853 // If unconditional catch then should to be the end. 1854 if (ifExpression == null) { 1855 break; 1856 } 1857 } 1858 1859 // Prepare to capture finally statement. 1860 Block finallyStatements = null; 1861 1862 if (type == FINALLY) { 1863 next(); 1864 finallyStatements = getBlock(true); 1865 } 1866 1867 // Need at least one catch or a finally. 1868 if (catchBlocks.isEmpty() && finallyStatements == null) { 1869 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 1870 } 1871 1872 final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements); 1873 // Add try. 1874 assert lc.peek() == outer; 1875 appendStatement(tryNode); 1876 } finally { 1877 restoreBlock(outer); 1878 } 1879 1880 appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags(), outer.getStatements()))); 1881 } 1882 1883 /** 1884 * DebuggerStatement : 1885 * debugger ; 1886 * 1887 * See 12.15 1888 * 1889 * Parse debugger statement. 1890 */ 1891 private void debuggerStatement() { 1892 // Capture DEBUGGER token. 1893 final int debuggerLine = line; 1894 final long debuggerToken = token; 1895 // DEBUGGER tested in caller. 1896 next(); 1897 endOfLine(); 1898 appendStatement(new ExpressionStatement(debuggerLine, debuggerToken, finish, new RuntimeNode(debuggerToken, finish, RuntimeNode.Request.DEBUGGER, Collections.<Expression>emptyList()))); 1899 } 1900 1901 /** 1902 * PrimaryExpression : 1903 * this 1904 * Identifier 1905 * Literal 1906 * ArrayLiteral 1907 * ObjectLiteral 1908 * ( Expression ) 1909 * 1910 * See 11.1 1911 * 1912 * Parse primary expression. 1913 * @return Expression node. 1914 */ 1915 @SuppressWarnings("fallthrough") 1916 private Expression primaryExpression() { 1917 // Capture first token. 1918 final int primaryLine = line; 1919 final long primaryToken = token; 1920 1921 switch (type) { 1922 case THIS: 1923 final String name = type.getName(); 1924 next(); 1925 lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS); 1926 return new IdentNode(primaryToken, finish, name); 1927 case IDENT: 1928 final IdentNode ident = getIdent(); 1929 if (ident == null) { 1930 break; 1931 } 1932 detectSpecialProperty(ident); 1933 return ident; 1934 case OCTAL: 1935 if (isStrictMode) { 1936 throw error(AbstractParser.message("strict.no.octal"), token); 1937 } 1938 case STRING: 1939 case ESCSTRING: 1940 case DECIMAL: 1941 case HEXADECIMAL: 1942 case FLOATING: 1943 case REGEX: 1944 case XML: 1945 return getLiteral(); 1946 case EXECSTRING: 1947 return execString(primaryLine, primaryToken); 1948 case FALSE: 1949 next(); 1950 return LiteralNode.newInstance(primaryToken, finish, false); 1951 case TRUE: 1952 next(); 1953 return LiteralNode.newInstance(primaryToken, finish, true); 1954 case NULL: 1955 next(); 1956 return LiteralNode.newInstance(primaryToken, finish); 1957 case LBRACKET: 1958 return arrayLiteral(); 1959 case LBRACE: 1960 return objectLiteral(); 1961 case LPAREN: 1962 next(); 1963 1964 final Expression expression = expression(); 1965 1966 expect(RPAREN); 1967 1968 return expression; 1969 1970 default: 1971 // In this context some operator tokens mark the start of a literal. 1972 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) { 1973 next(); 1974 return getLiteral(); 1975 } 1976 if (isNonStrictModeIdent()) { 1977 return getIdent(); 1978 } 1979 break; 1980 } 1981 1982 return null; 1983 } 1984 1985 /** 1986 * Convert execString to a call to $EXEC. 1987 * 1988 * @param primaryToken Original string token. 1989 * @return callNode to $EXEC. 1990 */ 1991 CallNode execString(final int primaryLine, final long primaryToken) { 1992 // Synthesize an ident to call $EXEC. 1993 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME); 1994 // Skip over EXECSTRING. 1995 next(); 1996 // Set up argument list for call. 1997 // Skip beginning of edit string expression. 1998 expect(LBRACE); 1999 // Add the following expression to arguments. 2000 final List<Expression> arguments = Collections.singletonList(expression()); 2001 // Skip ending of edit string expression. 2002 expect(RBRACE); 2003 2004 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false); 2005 } 2006 2007 /** 2008 * ArrayLiteral : 2009 * [ Elision? ] 2010 * [ ElementList ] 2011 * [ ElementList , Elision? ] 2012 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ] 2013 * 2014 * ElementList : Elision? AssignmentExpression 2015 * ElementList , Elision? AssignmentExpression 2016 * 2017 * Elision : 2018 * , 2019 * Elision , 2020 * 2021 * See 12.1.4 2022 * JavaScript 1.8 2023 * 2024 * Parse array literal. 2025 * @return Expression node. 2026 */ 2027 private LiteralNode<Expression[]> arrayLiteral() { 2028 // Capture LBRACKET token. 2029 final long arrayToken = token; 2030 // LBRACKET tested in caller. 2031 next(); 2032 2033 // Prepare to accummulating elements. 2034 final List<Expression> elements = new ArrayList<>(); 2035 // Track elisions. 2036 boolean elision = true; 2037loop: 2038 while (true) { 2039 switch (type) { 2040 case RBRACKET: 2041 next(); 2042 2043 break loop; 2044 2045 case COMMARIGHT: 2046 next(); 2047 2048 // If no prior expression 2049 if (elision) { 2050 elements.add(null); 2051 } 2052 2053 elision = true; 2054 2055 break; 2056 2057 default: 2058 if (!elision) { 2059 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2060 } 2061 // Add expression element. 2062 final Expression expression = assignmentExpression(false); 2063 2064 if (expression != null) { 2065 elements.add(expression); 2066 } else { 2067 expect(RBRACKET); 2068 } 2069 2070 elision = false; 2071 break; 2072 } 2073 } 2074 2075 return LiteralNode.newInstance(arrayToken, finish, elements); 2076 } 2077 2078 /** 2079 * ObjectLiteral : 2080 * { } 2081 * { PropertyNameAndValueList } { PropertyNameAndValueList , } 2082 * 2083 * PropertyNameAndValueList : 2084 * PropertyAssignment 2085 * PropertyNameAndValueList , PropertyAssignment 2086 * 2087 * See 11.1.5 2088 * 2089 * Parse an object literal. 2090 * @return Expression node. 2091 */ 2092 private ObjectNode objectLiteral() { 2093 // Capture LBRACE token. 2094 final long objectToken = token; 2095 // LBRACE tested in caller. 2096 next(); 2097 2098 // Object context. 2099 // Prepare to accumulate elements. 2100 final List<PropertyNode> elements = new ArrayList<>(); 2101 final Map<String, Integer> map = new HashMap<>(); 2102 2103 // Create a block for the object literal. 2104 boolean commaSeen = true; 2105loop: 2106 while (true) { 2107 switch (type) { 2108 case RBRACE: 2109 next(); 2110 break loop; 2111 2112 case COMMARIGHT: 2113 if (commaSeen) { 2114 throw error(AbstractParser.message("expected.property.id", type.getNameOrType())); 2115 } 2116 next(); 2117 commaSeen = true; 2118 break; 2119 2120 default: 2121 if (!commaSeen) { 2122 throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 2123 } 2124 2125 commaSeen = false; 2126 // Get and add the next property. 2127 final PropertyNode property = propertyAssignment(); 2128 final String key = property.getKeyName(); 2129 final Integer existing = map.get(key); 2130 2131 if (existing == null) { 2132 map.put(key, elements.size()); 2133 elements.add(property); 2134 break; 2135 } 2136 2137 final PropertyNode existingProperty = elements.get(existing); 2138 2139 // ECMA section 11.1.5 Object Initialiser 2140 // point # 4 on property assignment production 2141 final Expression value = property.getValue(); 2142 final FunctionNode getter = property.getGetter(); 2143 final FunctionNode setter = property.getSetter(); 2144 2145 final Expression prevValue = existingProperty.getValue(); 2146 final FunctionNode prevGetter = existingProperty.getGetter(); 2147 final FunctionNode prevSetter = existingProperty.getSetter(); 2148 2149 // ECMA 11.1.5 strict mode restrictions 2150 if (isStrictMode && value != null && prevValue != null) { 2151 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2152 } 2153 2154 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 2155 final boolean isAccessor = getter != null || setter != null; 2156 2157 // data property redefined as accessor property 2158 if (prevValue != null && isAccessor) { 2159 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2160 } 2161 2162 // accessor property redefined as data 2163 if (isPrevAccessor && value != null) { 2164 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2165 } 2166 2167 if (isAccessor && isPrevAccessor) { 2168 if (getter != null && prevGetter != null || 2169 setter != null && prevSetter != null) { 2170 throw error(AbstractParser.message("property.redefinition", key), property.getToken()); 2171 } 2172 } 2173 2174 if (value != null) { 2175 elements.add(property); 2176 } else if (getter != null) { 2177 elements.set(existing, existingProperty.setGetter(getter)); 2178 } else if (setter != null) { 2179 elements.set(existing, existingProperty.setSetter(setter)); 2180 } 2181 break; 2182 } 2183 } 2184 2185 return new ObjectNode(objectToken, finish, elements); 2186 } 2187 2188 /** 2189 * PropertyName : 2190 * IdentifierName 2191 * StringLiteral 2192 * NumericLiteral 2193 * 2194 * See 11.1.5 2195 * 2196 * @return PropertyName node 2197 */ 2198 @SuppressWarnings("fallthrough") 2199 private PropertyKey propertyName() { 2200 switch (type) { 2201 case IDENT: 2202 return getIdent().setIsPropertyName(); 2203 case OCTAL: 2204 if (isStrictMode) { 2205 throw error(AbstractParser.message("strict.no.octal"), token); 2206 } 2207 case STRING: 2208 case ESCSTRING: 2209 case DECIMAL: 2210 case HEXADECIMAL: 2211 case FLOATING: 2212 return getLiteral(); 2213 default: 2214 return getIdentifierName().setIsPropertyName(); 2215 } 2216 } 2217 2218 /** 2219 * PropertyAssignment : 2220 * PropertyName : AssignmentExpression 2221 * get PropertyName ( ) { FunctionBody } 2222 * set PropertyName ( PropertySetParameterList ) { FunctionBody } 2223 * 2224 * PropertySetParameterList : 2225 * Identifier 2226 * 2227 * PropertyName : 2228 * IdentifierName 2229 * StringLiteral 2230 * NumericLiteral 2231 * 2232 * See 11.1.5 2233 * 2234 * Parse an object literal property. 2235 * @return Property or reference node. 2236 */ 2237 private PropertyNode propertyAssignment() { 2238 // Capture firstToken. 2239 final long propertyToken = token; 2240 final int functionLine = line; 2241 2242 PropertyKey propertyName; 2243 2244 if (type == IDENT) { 2245 // Get IDENT. 2246 final String ident = (String)expectValue(IDENT); 2247 2248 if (type != COLON) { 2249 final long getSetToken = propertyToken; 2250 2251 switch (ident) { 2252 case "get": 2253 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine); 2254 return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null); 2255 2256 case "set": 2257 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine); 2258 return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode); 2259 default: 2260 break; 2261 } 2262 } 2263 2264 propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName(); 2265 } else { 2266 propertyName = propertyName(); 2267 } 2268 2269 expect(COLON); 2270 2271 defaultNames.push(propertyName); 2272 try { 2273 return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null); 2274 } finally { 2275 defaultNames.pop(); 2276 } 2277 } 2278 2279 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) { 2280 final PropertyKey getIdent = propertyName(); 2281 final String getterName = getIdent.getPropertyName(); 2282 final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName)); 2283 expect(LPAREN); 2284 expect(RPAREN); 2285 2286 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList()); 2287 lc.push(functionNode); 2288 2289 final Block functionBody = functionBody(functionNode); 2290 2291 lc.pop(functionNode); 2292 2293 final FunctionNode function = createFunctionNode( 2294 functionNode, 2295 getSetToken, 2296 getNameNode, 2297 Collections.<IdentNode>emptyList(), 2298 FunctionNode.Kind.GETTER, 2299 functionLine, 2300 functionBody); 2301 2302 return new PropertyFunction(getIdent, function); 2303 } 2304 2305 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) { 2306 final PropertyKey setIdent = propertyName(); 2307 final String setterName = setIdent.getPropertyName(); 2308 final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName)); 2309 expect(LPAREN); 2310 // be sloppy and allow missing setter parameter even though 2311 // spec does not permit it! 2312 final IdentNode argIdent; 2313 if (type == IDENT || isNonStrictModeIdent()) { 2314 argIdent = getIdent(); 2315 verifyStrictIdent(argIdent, "setter argument"); 2316 } else { 2317 argIdent = null; 2318 } 2319 expect(RPAREN); 2320 final List<IdentNode> parameters = new ArrayList<>(); 2321 if (argIdent != null) { 2322 parameters.add(argIdent); 2323 } 2324 2325 2326 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters); 2327 lc.push(functionNode); 2328 2329 final Block functionBody = functionBody(functionNode); 2330 2331 lc.pop(functionNode); 2332 2333 final FunctionNode function = createFunctionNode( 2334 functionNode, 2335 getSetToken, 2336 setNameNode, 2337 parameters, 2338 FunctionNode.Kind.SETTER, 2339 functionLine, 2340 functionBody); 2341 2342 return new PropertyFunction(setIdent, function); 2343 } 2344 2345 private static class PropertyFunction { 2346 final PropertyKey ident; 2347 final FunctionNode functionNode; 2348 2349 PropertyFunction(final PropertyKey ident, final FunctionNode function) { 2350 this.ident = ident; 2351 this.functionNode = function; 2352 } 2353 } 2354 2355 /** 2356 * LeftHandSideExpression : 2357 * NewExpression 2358 * CallExpression 2359 * 2360 * CallExpression : 2361 * MemberExpression Arguments 2362 * CallExpression Arguments 2363 * CallExpression [ Expression ] 2364 * CallExpression . IdentifierName 2365 * 2366 * See 11.2 2367 * 2368 * Parse left hand side expression. 2369 * @return Expression node. 2370 */ 2371 private Expression leftHandSideExpression() { 2372 int callLine = line; 2373 long callToken = token; 2374 2375 Expression lhs = memberExpression(); 2376 2377 if (type == LPAREN) { 2378 final List<Expression> arguments = optimizeList(argumentList()); 2379 2380 // Catch special functions. 2381 if (lhs instanceof IdentNode) { 2382 detectSpecialFunction((IdentNode)lhs); 2383 } 2384 2385 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2386 } 2387 2388loop: 2389 while (true) { 2390 // Capture token. 2391 callLine = line; 2392 callToken = token; 2393 2394 switch (type) { 2395 case LPAREN: 2396 // Get NEW or FUNCTION arguments. 2397 final List<Expression> arguments = optimizeList(argumentList()); 2398 2399 // Create call node. 2400 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false); 2401 2402 break; 2403 2404 case LBRACKET: 2405 next(); 2406 2407 // Get array index. 2408 final Expression rhs = expression(); 2409 2410 expect(RBRACKET); 2411 2412 // Create indexing node. 2413 lhs = new IndexNode(callToken, finish, lhs, rhs); 2414 2415 break; 2416 2417 case PERIOD: 2418 next(); 2419 2420 final IdentNode property = getIdentifierName(); 2421 2422 // Create property access node. 2423 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2424 2425 break; 2426 2427 default: 2428 break loop; 2429 } 2430 } 2431 2432 return lhs; 2433 } 2434 2435 /** 2436 * NewExpression : 2437 * MemberExpression 2438 * new NewExpression 2439 * 2440 * See 11.2 2441 * 2442 * Parse new expression. 2443 * @return Expression node. 2444 */ 2445 private Expression newExpression() { 2446 final long newToken = token; 2447 // NEW is tested in caller. 2448 next(); 2449 2450 // Get function base. 2451 final int callLine = line; 2452 final Expression constructor = memberExpression(); 2453 if (constructor == null) { 2454 return null; 2455 } 2456 // Get arguments. 2457 ArrayList<Expression> arguments; 2458 2459 // Allow for missing arguments. 2460 if (type == LPAREN) { 2461 arguments = argumentList(); 2462 } else { 2463 arguments = new ArrayList<>(); 2464 } 2465 2466 // Nashorn extension: This is to support the following interface implementation 2467 // syntax: 2468 // 2469 // var r = new java.lang.Runnable() { 2470 // run: function() { println("run"); } 2471 // }; 2472 // 2473 // The object literal following the "new Constructor()" expresssion 2474 // is passed as an additional (last) argument to the constructor. 2475 if (!env._no_syntax_extensions && type == LBRACE) { 2476 arguments.add(objectLiteral()); 2477 } 2478 2479 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true); 2480 2481 return new UnaryNode(newToken, callNode); 2482 } 2483 2484 /** 2485 * MemberExpression : 2486 * PrimaryExpression 2487 * FunctionExpression 2488 * MemberExpression [ Expression ] 2489 * MemberExpression . IdentifierName 2490 * new MemberExpression Arguments 2491 * 2492 * See 11.2 2493 * 2494 * Parse member expression. 2495 * @return Expression node. 2496 */ 2497 private Expression memberExpression() { 2498 // Prepare to build operation. 2499 Expression lhs; 2500 2501 switch (type) { 2502 case NEW: 2503 // Get new expression. 2504 lhs = newExpression(); 2505 break; 2506 2507 case FUNCTION: 2508 // Get function expression. 2509 lhs = functionExpression(false, false); 2510 break; 2511 2512 default: 2513 // Get primary expression. 2514 lhs = primaryExpression(); 2515 break; 2516 } 2517 2518loop: 2519 while (true) { 2520 // Capture token. 2521 final long callToken = token; 2522 2523 switch (type) { 2524 case LBRACKET: 2525 next(); 2526 2527 // Get array index. 2528 final Expression index = expression(); 2529 2530 expect(RBRACKET); 2531 2532 // Create indexing node. 2533 lhs = new IndexNode(callToken, finish, lhs, index); 2534 2535 break; 2536 2537 case PERIOD: 2538 if (lhs == null) { 2539 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 2540 } 2541 2542 next(); 2543 2544 final IdentNode property = getIdentifierName(); 2545 2546 // Create property access node. 2547 lhs = new AccessNode(callToken, finish, lhs, property.getName()); 2548 2549 break; 2550 2551 default: 2552 break loop; 2553 } 2554 } 2555 2556 return lhs; 2557 } 2558 2559 /** 2560 * Arguments : 2561 * ( ) 2562 * ( ArgumentList ) 2563 * 2564 * ArgumentList : 2565 * AssignmentExpression 2566 * ArgumentList , AssignmentExpression 2567 * 2568 * See 11.2 2569 * 2570 * Parse function call arguments. 2571 * @return Argument list. 2572 */ 2573 private ArrayList<Expression> argumentList() { 2574 // Prepare to accumulate list of arguments. 2575 final ArrayList<Expression> nodeList = new ArrayList<>(); 2576 // LPAREN tested in caller. 2577 next(); 2578 2579 // Track commas. 2580 boolean first = true; 2581 2582 while (type != RPAREN) { 2583 // Comma prior to every argument except the first. 2584 if (!first) { 2585 expect(COMMARIGHT); 2586 } else { 2587 first = false; 2588 } 2589 2590 // Get argument expression. 2591 nodeList.add(assignmentExpression(false)); 2592 } 2593 2594 expect(RPAREN); 2595 return nodeList; 2596 } 2597 2598 private static <T> List<T> optimizeList(final ArrayList<T> list) { 2599 switch(list.size()) { 2600 case 0: { 2601 return Collections.emptyList(); 2602 } 2603 case 1: { 2604 return Collections.singletonList(list.get(0)); 2605 } 2606 default: { 2607 list.trimToSize(); 2608 return list; 2609 } 2610 } 2611 } 2612 2613 /** 2614 * FunctionDeclaration : 2615 * function Identifier ( FormalParameterList? ) { FunctionBody } 2616 * 2617 * FunctionExpression : 2618 * function Identifier? ( FormalParameterList? ) { FunctionBody } 2619 * 2620 * See 13 2621 * 2622 * Parse function declaration. 2623 * @param isStatement True if for is a statement. 2624 * 2625 * @return Expression node. 2626 */ 2627 private Expression functionExpression(final boolean isStatement, final boolean topLevel) { 2628 final long functionToken = token; 2629 final int functionLine = line; 2630 // FUNCTION is tested in caller. 2631 next(); 2632 2633 IdentNode name = null; 2634 2635 if (type == IDENT || isNonStrictModeIdent()) { 2636 name = getIdent(); 2637 verifyStrictIdent(name, "function name"); 2638 } else if (isStatement) { 2639 // Nashorn extension: anonymous function statements 2640 if (env._no_syntax_extensions) { 2641 expect(IDENT); 2642 } 2643 } 2644 2645 // name is null, generate anonymous name 2646 boolean isAnonymous = false; 2647 if (name == null) { 2648 final String tmpName = getDefaultValidFunctionName(functionLine); 2649 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 2650 isAnonymous = true; 2651 } 2652 2653 expect(LPAREN); 2654 final List<IdentNode> parameters = formalParameterList(); 2655 expect(RPAREN); 2656 2657 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters); 2658 lc.push(functionNode); 2659 Block functionBody = null; 2660 try{ 2661 functionBody = functionBody(functionNode); 2662 } finally { 2663 lc.pop(functionNode); 2664 } 2665 2666 if (isStatement) { 2667 if (topLevel || useBlockScope()) { 2668 functionNode.setFlag(FunctionNode.IS_DECLARED); 2669 } else if (isStrictMode) { 2670 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken); 2671 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) { 2672 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken); 2673 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) { 2674 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken); 2675 } 2676 if (isArguments(name)) { 2677 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS); 2678 } 2679 } 2680 2681 if (isAnonymous) { 2682 functionNode.setFlag(FunctionNode.IS_ANONYMOUS); 2683 } 2684 2685 final int arity = parameters.size(); 2686 2687 final boolean strict = functionNode.isStrict(); 2688 if (arity > 1) { 2689 final HashSet<String> parametersSet = new HashSet<>(arity); 2690 2691 for (int i = arity - 1; i >= 0; i--) { 2692 final IdentNode parameter = parameters.get(i); 2693 String parameterName = parameter.getName(); 2694 2695 if (isArguments(parameterName)) { 2696 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2697 } 2698 2699 if (parametersSet.contains(parameterName)) { 2700 // redefinition of parameter name 2701 if (strict) { 2702 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2703 } 2704 // rename in non-strict mode 2705 parameterName = functionNode.uniqueName(parameterName); 2706 final long parameterToken = parameter.getToken(); 2707 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 2708 } 2709 2710 parametersSet.add(parameterName); 2711 } 2712 } else if (arity == 1) { 2713 if (isArguments(parameters.get(0))) { 2714 functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS); 2715 } 2716 } 2717 2718 final FunctionNode function = createFunctionNode( 2719 functionNode, 2720 functionToken, 2721 name, 2722 parameters, 2723 FunctionNode.Kind.NORMAL, 2724 functionLine, 2725 functionBody); 2726 2727 if (isStatement) { 2728 int varFlags = VarNode.IS_STATEMENT; 2729 if (!topLevel && useBlockScope()) { 2730 // mark ES6 block functions as lexically scoped 2731 varFlags |= VarNode.IS_LET; 2732 } 2733 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags); 2734 if (topLevel) { 2735 functionDeclarations.add(varNode); 2736 } else if (useBlockScope()) { 2737 prependStatement(varNode); // Hoist to beginning of current block 2738 } else { 2739 appendStatement(varNode); 2740 } 2741 } 2742 2743 return function; 2744 } 2745 2746 private String getDefaultValidFunctionName(final int functionLine) { 2747 final String defaultFunctionName = getDefaultFunctionName(); 2748 return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine; 2749 } 2750 2751 private static boolean isValidIdentifier(final String name) { 2752 if(name == null || name.isEmpty()) { 2753 return false; 2754 } 2755 if(!Character.isJavaIdentifierStart(name.charAt(0))) { 2756 return false; 2757 } 2758 for(int i = 1; i < name.length(); ++i) { 2759 if(!Character.isJavaIdentifierPart(name.charAt(i))) { 2760 return false; 2761 } 2762 } 2763 return true; 2764 } 2765 2766 private String getDefaultFunctionName() { 2767 if(!defaultNames.isEmpty()) { 2768 final Object nameExpr = defaultNames.peek(); 2769 if(nameExpr instanceof PropertyKey) { 2770 markDefaultNameUsed(); 2771 return ((PropertyKey)nameExpr).getPropertyName(); 2772 } else if(nameExpr instanceof AccessNode) { 2773 markDefaultNameUsed(); 2774 return ((AccessNode)nameExpr).getProperty(); 2775 } 2776 } 2777 return null; 2778 } 2779 2780 private void markDefaultNameUsed() { 2781 defaultNames.pop(); 2782 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 2783 // from. Can't be null 2784 defaultNames.push(""); 2785 } 2786 2787 /** 2788 * FormalParameterList : 2789 * Identifier 2790 * FormalParameterList , Identifier 2791 * 2792 * See 13 2793 * 2794 * Parse function parameter list. 2795 * @return List of parameter nodes. 2796 */ 2797 private List<IdentNode> formalParameterList() { 2798 return formalParameterList(RPAREN); 2799 } 2800 2801 /** 2802 * Same as the other method of the same name - except that the end 2803 * token type expected is passed as argument to this method. 2804 * 2805 * FormalParameterList : 2806 * Identifier 2807 * FormalParameterList , Identifier 2808 * 2809 * See 13 2810 * 2811 * Parse function parameter list. 2812 * @return List of parameter nodes. 2813 */ 2814 private List<IdentNode> formalParameterList(final TokenType endType) { 2815 // Prepare to gather parameters. 2816 final ArrayList<IdentNode> parameters = new ArrayList<>(); 2817 // Track commas. 2818 boolean first = true; 2819 2820 while (type != endType) { 2821 // Comma prior to every argument except the first. 2822 if (!first) { 2823 expect(COMMARIGHT); 2824 } else { 2825 first = false; 2826 } 2827 2828 // Get and add parameter. 2829 final IdentNode ident = getIdent(); 2830 2831 // ECMA 13.1 strict mode restrictions 2832 verifyStrictIdent(ident, "function parameter"); 2833 2834 parameters.add(ident); 2835 } 2836 2837 parameters.trimToSize(); 2838 return parameters; 2839 } 2840 2841 /** 2842 * FunctionBody : 2843 * SourceElements? 2844 * 2845 * See 13 2846 * 2847 * Parse function body. 2848 * @return function node (body.) 2849 */ 2850 private Block functionBody(final ParserContextFunctionNode functionNode) { 2851 long lastToken = 0L; 2852 ParserContextBlockNode body = null; 2853 final long bodyToken = token; 2854 Block functionBody; 2855 int bodyFinish = 0; 2856 2857 2858 final boolean parseBody; 2859 Object endParserState = null; 2860 try { 2861 // Create a new function block. 2862 body = newBlock(); 2863 assert functionNode != null; 2864 final int functionId = functionNode.getId(); 2865 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId(); 2866 // Nashorn extension: expression closures 2867 if (!env._no_syntax_extensions && type != LBRACE) { 2868 /* 2869 * Example: 2870 * 2871 * function square(x) x * x; 2872 * print(square(3)); 2873 */ 2874 2875 // just expression as function body 2876 final Expression expr = assignmentExpression(true); 2877 lastToken = previousToken; 2878 functionNode.setLastToken(previousToken); 2879 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 2880 // EOL uses length field to store the line number 2881 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken)); 2882 // Only create the return node if we aren't skipping nested functions. Note that we aren't 2883 // skipping parsing of these extended functions; they're considered to be small anyway. Also, 2884 // they don't end with a single well known token, so it'd be very hard to get correctly (see 2885 // the note below for reasoning on skipping happening before instead of after RBRACE for 2886 // details). 2887 if (parseBody) { 2888 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr); 2889 appendStatement(returnNode); 2890 } 2891 } else { 2892 expectDontAdvance(LBRACE); 2893 if (parseBody || !skipFunctionBody(functionNode)) { 2894 next(); 2895 // Gather the function elements. 2896 final List<Statement> prevFunctionDecls = functionDeclarations; 2897 functionDeclarations = new ArrayList<>(); 2898 try { 2899 sourceElements(false); 2900 addFunctionDeclarations(functionNode); 2901 } finally { 2902 functionDeclarations = prevFunctionDecls; 2903 } 2904 2905 lastToken = token; 2906 if (parseBody) { 2907 // Since the lexer can read ahead and lexify some number of tokens in advance and have 2908 // them buffered in the TokenStream, we need to produce a lexer state as it was just 2909 // before it lexified RBRACE, and not whatever is its current (quite possibly well read 2910 // ahead) state. 2911 endParserState = new ParserState(Token.descPosition(token), line, linePosition); 2912 2913 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of 2914 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the 2915 // state after it. The reason is that RBRACE is a well-known token that we can expect and 2916 // will never involve us getting into a weird lexer state, and as such is a great reparse 2917 // point. Typical example of a weird lexer state after RBRACE would be: 2918 // function this_is_skipped() { ... } "use strict"; 2919 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead 2920 // of compensating for the possibility of a string literal (or similar) after RBRACE, 2921 // we'll rather just restart parsing from this well-known, friendly token instead. 2922 } 2923 } 2924 bodyFinish = finish; 2925 functionNode.setLastToken(token); 2926 expect(RBRACE); 2927 } 2928 } finally { 2929 restoreBlock(body); 2930 } 2931 2932 // NOTE: we can only do alterations to the function node after restoreFunctionNode. 2933 2934 if (parseBody) { 2935 functionNode.setEndParserState(endParserState); 2936 } else if (!body.getStatements().isEmpty()){ 2937 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see 2938 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to 2939 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as 2940 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away 2941 // nested bodies early if we were supposed to skip 'em. 2942 body.setStatements(Collections.<Statement>emptyList()); 2943 } 2944 2945 if (reparsedFunction != null) { 2946 // We restore the flags stored in the function's ScriptFunctionData that we got when we first 2947 // eagerly parsed the code. We're doing it because some flags would be set based on the 2948 // content of the function, or even content of its nested functions, most of which are normally 2949 // skipped during an on-demand compilation. 2950 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2951 if (data != null) { 2952 // Data can be null if when we originally parsed the file, we removed the function declaration 2953 // as it was dead code. 2954 functionNode.setFlag(data.getFunctionFlags()); 2955 // This compensates for missing markEval() in case the function contains an inner function 2956 // that contains eval(), that now we didn't discover since we skipped the inner function. 2957 if (functionNode.hasNestedEval()) { 2958 assert functionNode.hasScopeBlock(); 2959 body.setFlag(Block.NEEDS_SCOPE); 2960 } 2961 } 2962 } 2963 functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements()); 2964 return functionBody; 2965 } 2966 2967 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) { 2968 if (reparsedFunction == null) { 2969 // Not reparsing, so don't skip any function body. 2970 return false; 2971 } 2972 // Skip to the RBRACE of this function, and continue parsing from there. 2973 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId()); 2974 if (data == null) { 2975 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was 2976 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the 2977 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it. 2978 return false; 2979 } 2980 final ParserState parserState = (ParserState)data.getEndParserState(); 2981 assert parserState != null; 2982 2983 stream.reset(); 2984 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions); 2985 line = parserState.line; 2986 linePosition = parserState.linePosition; 2987 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before 2988 // the RBRACE. 2989 type = SEMICOLON; 2990 k = -1; 2991 next(); 2992 2993 return true; 2994 } 2995 2996 /** 2997 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer 2998 * for resuming parsing after skipping a function body. 2999 */ 3000 private static class ParserState implements Serializable { 3001 private final int position; 3002 private final int line; 3003 private final int linePosition; 3004 3005 private static final long serialVersionUID = -2382565130754093694L; 3006 3007 ParserState(final int position, final int line, final int linePosition) { 3008 this.position = position; 3009 this.line = line; 3010 this.linePosition = linePosition; 3011 } 3012 3013 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting) { 3014 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, true); 3015 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON)); 3016 return newLexer; 3017 } 3018 } 3019 3020 private void printAST(final FunctionNode functionNode) { 3021 if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) { 3022 env.getErr().println(new ASTWriter(functionNode)); 3023 } 3024 3025 if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) { 3026 env.getErr().println(new PrintVisitor(functionNode, true, false)); 3027 } 3028 } 3029 3030 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) { 3031 VarNode lastDecl = null; 3032 for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 3033 Statement decl = functionDeclarations.get(i); 3034 if (lastDecl == null && decl instanceof VarNode) { 3035 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 3036 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS); 3037 } 3038 prependStatement(decl); 3039 } 3040 } 3041 3042 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) { 3043 if (earlyError) { 3044 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 3045 } 3046 final ArrayList<Expression> args = new ArrayList<>(); 3047 args.add(lhs); 3048 if (rhs == null) { 3049 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish())); 3050 } else { 3051 args.add(rhs); 3052 } 3053 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString())); 3054 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 3055 } 3056 3057 /* 3058 * parse LHS [a, b, ..., c]. 3059 * 3060 * JavaScript 1.8. 3061 */ 3062 //private Node destructureExpression() { 3063 // return null; 3064 //} 3065 3066 /** 3067 * PostfixExpression : 3068 * LeftHandSideExpression 3069 * LeftHandSideExpression ++ // [no LineTerminator here] 3070 * LeftHandSideExpression -- // [no LineTerminator here] 3071 * 3072 * See 11.3 3073 * 3074 * UnaryExpression : 3075 * PostfixExpression 3076 * delete UnaryExpression 3077 * Node UnaryExpression 3078 * typeof UnaryExpression 3079 * ++ UnaryExpression 3080 * -- UnaryExpression 3081 * + UnaryExpression 3082 * - UnaryExpression 3083 * ~ UnaryExpression 3084 * ! UnaryExpression 3085 * 3086 * See 11.4 3087 * 3088 * Parse unary expression. 3089 * @return Expression node. 3090 */ 3091 private Expression unaryExpression() { 3092 final int unaryLine = line; 3093 final long unaryToken = token; 3094 3095 switch (type) { 3096 case DELETE: { 3097 next(); 3098 final Expression expr = unaryExpression(); 3099 if (expr instanceof BaseNode || expr instanceof IdentNode) { 3100 return new UnaryNode(unaryToken, expr); 3101 } 3102 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr)); 3103 return LiteralNode.newInstance(unaryToken, finish, true); 3104 } 3105 case VOID: 3106 case TYPEOF: 3107 case ADD: 3108 case SUB: 3109 case BIT_NOT: 3110 case NOT: 3111 next(); 3112 final Expression expr = unaryExpression(); 3113 return new UnaryNode(unaryToken, expr); 3114 3115 case INCPREFIX: 3116 case DECPREFIX: 3117 final TokenType opType = type; 3118 next(); 3119 3120 final Expression lhs = leftHandSideExpression(); 3121 // ++, -- without operand.. 3122 if (lhs == null) { 3123 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3124 } 3125 3126 if (!(lhs instanceof AccessNode || 3127 lhs instanceof IndexNode || 3128 lhs instanceof IdentNode)) { 3129 return referenceError(lhs, null, env._early_lvalue_error); 3130 } 3131 3132 if (lhs instanceof IdentNode) { 3133 if (!checkIdentLValue((IdentNode)lhs)) { 3134 return referenceError(lhs, null, false); 3135 } 3136 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3137 } 3138 3139 return incDecExpression(unaryToken, opType, lhs, false); 3140 3141 default: 3142 break; 3143 } 3144 3145 Expression expression = leftHandSideExpression(); 3146 3147 if (last != EOL) { 3148 switch (type) { 3149 case INCPREFIX: 3150 case DECPREFIX: 3151 final TokenType opType = type; 3152 final Expression lhs = expression; 3153 // ++, -- without operand.. 3154 if (lhs == null) { 3155 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType())); 3156 } 3157 3158 if (!(lhs instanceof AccessNode || 3159 lhs instanceof IndexNode || 3160 lhs instanceof IdentNode)) { 3161 next(); 3162 return referenceError(lhs, null, env._early_lvalue_error); 3163 } 3164 if (lhs instanceof IdentNode) { 3165 if (!checkIdentLValue((IdentNode)lhs)) { 3166 next(); 3167 return referenceError(lhs, null, false); 3168 } 3169 verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator"); 3170 } 3171 expression = incDecExpression(token, type, expression, true); 3172 next(); 3173 break; 3174 default: 3175 break; 3176 } 3177 } 3178 3179 if (expression == null) { 3180 throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 3181 } 3182 3183 return expression; 3184 } 3185 3186 /** 3187 * MultiplicativeExpression : 3188 * UnaryExpression 3189 * MultiplicativeExpression * UnaryExpression 3190 * MultiplicativeExpression / UnaryExpression 3191 * MultiplicativeExpression % UnaryExpression 3192 * 3193 * See 11.5 3194 * 3195 * AdditiveExpression : 3196 * MultiplicativeExpression 3197 * AdditiveExpression + MultiplicativeExpression 3198 * AdditiveExpression - MultiplicativeExpression 3199 * 3200 * See 11.6 3201 * 3202 * ShiftExpression : 3203 * AdditiveExpression 3204 * ShiftExpression << AdditiveExpression 3205 * ShiftExpression >> AdditiveExpression 3206 * ShiftExpression >>> AdditiveExpression 3207 * 3208 * See 11.7 3209 * 3210 * RelationalExpression : 3211 * ShiftExpression 3212 * RelationalExpression < ShiftExpression 3213 * RelationalExpression > ShiftExpression 3214 * RelationalExpression <= ShiftExpression 3215 * RelationalExpression >= ShiftExpression 3216 * RelationalExpression instanceof ShiftExpression 3217 * RelationalExpression in ShiftExpression // if !noIf 3218 * 3219 * See 11.8 3220 * 3221 * RelationalExpression 3222 * EqualityExpression == RelationalExpression 3223 * EqualityExpression != RelationalExpression 3224 * EqualityExpression === RelationalExpression 3225 * EqualityExpression !== RelationalExpression 3226 * 3227 * See 11.9 3228 * 3229 * BitwiseANDExpression : 3230 * EqualityExpression 3231 * BitwiseANDExpression & EqualityExpression 3232 * 3233 * BitwiseXORExpression : 3234 * BitwiseANDExpression 3235 * BitwiseXORExpression ^ BitwiseANDExpression 3236 * 3237 * BitwiseORExpression : 3238 * BitwiseXORExpression 3239 * BitwiseORExpression | BitwiseXORExpression 3240 * 3241 * See 11.10 3242 * 3243 * LogicalANDExpression : 3244 * BitwiseORExpression 3245 * LogicalANDExpression && BitwiseORExpression 3246 * 3247 * LogicalORExpression : 3248 * LogicalANDExpression 3249 * LogicalORExpression || LogicalANDExpression 3250 * 3251 * See 11.11 3252 * 3253 * ConditionalExpression : 3254 * LogicalORExpression 3255 * LogicalORExpression ? AssignmentExpression : AssignmentExpression 3256 * 3257 * See 11.12 3258 * 3259 * AssignmentExpression : 3260 * ConditionalExpression 3261 * LeftHandSideExpression AssignmentOperator AssignmentExpression 3262 * 3263 * AssignmentOperator : 3264 * = *= /= %= += -= <<= >>= >>>= &= ^= |= 3265 * 3266 * See 11.13 3267 * 3268 * Expression : 3269 * AssignmentExpression 3270 * Expression , AssignmentExpression 3271 * 3272 * See 11.14 3273 * 3274 * Parse expression. 3275 * @return Expression node. 3276 */ 3277 private Expression expression() { 3278 // TODO - Destructuring array. 3279 // Include commas in expression parsing. 3280 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 3281 } 3282 3283 private JoinPredecessorExpression joinPredecessorExpression() { 3284 return new JoinPredecessorExpression(expression()); 3285 } 3286 3287 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) { 3288 // Get the precedence of the next operator. 3289 int precedence = type.getPrecedence(); 3290 Expression lhs = exprLhs; 3291 3292 // While greater precedence. 3293 while (type.isOperator(noIn) && precedence >= minPrecedence) { 3294 // Capture the operator token. 3295 final long op = token; 3296 3297 if (type == TERNARY) { 3298 // Skip operator. 3299 next(); 3300 3301 // Pass expression. Middle expression of a conditional expression can be a "in" 3302 // expression - even in the contexts where "in" is not permitted. 3303 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false); 3304 3305 expect(COLON); 3306 3307 // Fail expression. 3308 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3309 3310 // Build up node. 3311 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr)); 3312 } else { 3313 // Skip operator. 3314 next(); 3315 3316 // Get the next primary expression. 3317 Expression rhs; 3318 final boolean isAssign = Token.descType(op) == ASSIGN; 3319 if(isAssign) { 3320 defaultNames.push(lhs); 3321 } 3322 try { 3323 rhs = unaryExpression(); 3324 // Get precedence of next operator. 3325 int nextPrecedence = type.getPrecedence(); 3326 3327 // Subtask greater precedence. 3328 while (type.isOperator(noIn) && 3329 (nextPrecedence > precedence || 3330 nextPrecedence == precedence && !type.isLeftAssociative())) { 3331 rhs = expression(rhs, nextPrecedence, noIn); 3332 nextPrecedence = type.getPrecedence(); 3333 } 3334 } finally { 3335 if(isAssign) { 3336 defaultNames.pop(); 3337 } 3338 } 3339 lhs = verifyAssignment(op, lhs, rhs); 3340 } 3341 3342 precedence = type.getPrecedence(); 3343 } 3344 3345 return lhs; 3346 } 3347 3348 private Expression assignmentExpression(final boolean noIn) { 3349 // TODO - Handle decompose. 3350 // Exclude commas in expression parsing. 3351 return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn); 3352 } 3353 3354 /** 3355 * Parse an end of line. 3356 */ 3357 private void endOfLine() { 3358 switch (type) { 3359 case SEMICOLON: 3360 case EOL: 3361 next(); 3362 break; 3363 case RPAREN: 3364 case RBRACKET: 3365 case RBRACE: 3366 case EOF: 3367 break; 3368 default: 3369 if (last != EOL) { 3370 expect(SEMICOLON); 3371 } 3372 break; 3373 } 3374 } 3375 3376 @Override 3377 public String toString() { 3378 return "'JavaScript Parsing'"; 3379 } 3380 3381 private static void markEval(final ParserContext lc) { 3382 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions(); 3383 boolean flaggedCurrentFn = false; 3384 while (iter.hasNext()) { 3385 final ParserContextFunctionNode fn = iter.next(); 3386 if (!flaggedCurrentFn) { 3387 fn.setFlag(FunctionNode.HAS_EVAL); 3388 flaggedCurrentFn = true; 3389 } else { 3390 fn.setFlag(FunctionNode.HAS_NESTED_EVAL); 3391 } 3392 final ParserContextBlockNode body = lc.getFunctionBody(fn); 3393 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip 3394 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking 3395 // this method when the parser skips a nested function. 3396 body.setFlag(Block.NEEDS_SCOPE); 3397 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK); 3398 } 3399 } 3400 3401 private void prependStatement(final Statement statement) { 3402 lc.prependStatementToCurrentNode(statement); 3403 } 3404 3405 private void appendStatement(final Statement statement) { 3406 lc.appendStatementToCurrentNode(statement); 3407 } 3408} 3409