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