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