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