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