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