1 /*
2 * Copyright (c) 2010, 2015, 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.ARROW;
32 import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
33 import static jdk.nashorn.internal.parser.TokenType.CASE;
34 import static jdk.nashorn.internal.parser.TokenType.CATCH;
35 import static jdk.nashorn.internal.parser.TokenType.CLASS;
36 import static jdk.nashorn.internal.parser.TokenType.COLON;
37 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
38 import static jdk.nashorn.internal.parser.TokenType.COMMENT;
39 import static jdk.nashorn.internal.parser.TokenType.CONST;
40 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
41 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
42 import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS;
43 import static jdk.nashorn.internal.parser.TokenType.ELSE;
44 import static jdk.nashorn.internal.parser.TokenType.EOF;
45 import static jdk.nashorn.internal.parser.TokenType.EOL;
46 import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT;
47 import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
48 import static jdk.nashorn.internal.parser.TokenType.EXPORT;
49 import static jdk.nashorn.internal.parser.TokenType.EXTENDS;
50 import static jdk.nashorn.internal.parser.TokenType.FINALLY;
51 import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
52 import static jdk.nashorn.internal.parser.TokenType.IDENT;
53 import static jdk.nashorn.internal.parser.TokenType.IF;
54 import static jdk.nashorn.internal.parser.TokenType.IMPORT;
55 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
56 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
57 import static jdk.nashorn.internal.parser.TokenType.LBRACKET;
58 import static jdk.nashorn.internal.parser.TokenType.LET;
59 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
60 import static jdk.nashorn.internal.parser.TokenType.MUL;
61 import static jdk.nashorn.internal.parser.TokenType.PERIOD;
62 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
63 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
64 import static jdk.nashorn.internal.parser.TokenType.RPAREN;
65 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
66 import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY;
67 import static jdk.nashorn.internal.parser.TokenType.STATIC;
68 import static jdk.nashorn.internal.parser.TokenType.STRING;
69 import static jdk.nashorn.internal.parser.TokenType.SUPER;
70 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE;
71 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD;
72 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE;
73 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL;
74 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
75 import static jdk.nashorn.internal.parser.TokenType.VAR;
76 import static jdk.nashorn.internal.parser.TokenType.VOID;
77 import static jdk.nashorn.internal.parser.TokenType.WHILE;
78 import static jdk.nashorn.internal.parser.TokenType.YIELD;
79 import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR;
80
81 import java.io.Serializable;
82 import java.util.ArrayDeque;
83 import java.util.ArrayList;
84 import java.util.Collections;
85 import java.util.Deque;
86 import java.util.HashMap;
87 import java.util.HashSet;
88 import java.util.Iterator;
89 import java.util.List;
90 import java.util.Map;
91 import java.util.Objects;
92 import java.util.function.Consumer;
93 import jdk.nashorn.internal.codegen.CompilerConstants;
94 import jdk.nashorn.internal.codegen.Namespace;
95 import jdk.nashorn.internal.ir.AccessNode;
96 import jdk.nashorn.internal.ir.BaseNode;
97 import jdk.nashorn.internal.ir.BinaryNode;
98 import jdk.nashorn.internal.ir.Block;
99 import jdk.nashorn.internal.ir.BlockStatement;
100 import jdk.nashorn.internal.ir.BreakNode;
101 import jdk.nashorn.internal.ir.CallNode;
102 import jdk.nashorn.internal.ir.CaseNode;
103 import jdk.nashorn.internal.ir.CatchNode;
104 import jdk.nashorn.internal.ir.ClassNode;
105 import jdk.nashorn.internal.ir.ContinueNode;
106 import jdk.nashorn.internal.ir.DebuggerNode;
107 import jdk.nashorn.internal.ir.EmptyNode;
108 import jdk.nashorn.internal.ir.ErrorNode;
109 import jdk.nashorn.internal.ir.Expression;
110 import jdk.nashorn.internal.ir.ExpressionList;
111 import jdk.nashorn.internal.ir.ExpressionStatement;
112 import jdk.nashorn.internal.ir.ForNode;
113 import jdk.nashorn.internal.ir.FunctionNode;
114 import jdk.nashorn.internal.ir.IdentNode;
115 import jdk.nashorn.internal.ir.IfNode;
116 import jdk.nashorn.internal.ir.IndexNode;
117 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
118 import jdk.nashorn.internal.ir.LabelNode;
119 import jdk.nashorn.internal.ir.LexicalContext;
120 import jdk.nashorn.internal.ir.LiteralNode;
121 import jdk.nashorn.internal.ir.Module;
122 import jdk.nashorn.internal.ir.Node;
123 import jdk.nashorn.internal.ir.ObjectNode;
124 import jdk.nashorn.internal.ir.PropertyKey;
125 import jdk.nashorn.internal.ir.PropertyNode;
126 import jdk.nashorn.internal.ir.ReturnNode;
127 import jdk.nashorn.internal.ir.RuntimeNode;
128 import jdk.nashorn.internal.ir.Statement;
129 import jdk.nashorn.internal.ir.SwitchNode;
130 import jdk.nashorn.internal.ir.TernaryNode;
131 import jdk.nashorn.internal.ir.ThrowNode;
132 import jdk.nashorn.internal.ir.TryNode;
133 import jdk.nashorn.internal.ir.UnaryNode;
134 import jdk.nashorn.internal.ir.VarNode;
135 import jdk.nashorn.internal.ir.WhileNode;
136 import jdk.nashorn.internal.ir.WithNode;
137 import jdk.nashorn.internal.ir.debug.ASTWriter;
138 import jdk.nashorn.internal.ir.debug.PrintVisitor;
139 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
140 import jdk.nashorn.internal.runtime.Context;
141 import jdk.nashorn.internal.runtime.ErrorManager;
142 import jdk.nashorn.internal.runtime.JSErrorType;
143 import jdk.nashorn.internal.runtime.ParserException;
144 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
145 import jdk.nashorn.internal.runtime.ScriptEnvironment;
146 import jdk.nashorn.internal.runtime.ScriptingFunctions;
147 import jdk.nashorn.internal.runtime.Source;
148 import jdk.nashorn.internal.runtime.Timing;
149 import jdk.nashorn.internal.runtime.linker.NameCodec;
150 import jdk.nashorn.internal.runtime.logging.DebugLogger;
151 import jdk.nashorn.internal.runtime.logging.Loggable;
152 import jdk.nashorn.internal.runtime.logging.Logger;
153
154 /**
155 * Builds the IR.
156 */
157 @Logger(name="parser")
158 public class Parser extends AbstractParser implements Loggable {
159 private static final String ARGUMENTS_NAME = CompilerConstants.ARGUMENTS_VAR.symbolName();
160
161 /** Current env. */
162 private final ScriptEnvironment env;
163
164 /** Is scripting mode. */
165 private final boolean scripting;
166
167 private List<Statement> functionDeclarations;
168
169 private final ParserContext lc;
170 private final Deque<Object> defaultNames;
171
172 /** Namespace for function names where not explicitly given */
173 private final Namespace namespace;
174
175 private final DebugLogger log;
176
177 /** to receive line information from Lexer when scanning multine literals. */
178 protected final Lexer.LineInfoReceiver lineInfoReceiver;
179
180 private RecompilableScriptFunctionData reparsedFunction;
181
182 /**
183 * Constructor
184 *
185 * @param env script environment
186 * @param source source to parse
187 * @param errors error manager
188 */
189 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors) {
190 this(env, source, errors, env._strict, null);
191 }
192
193 /**
194 * Constructor
195 *
196 * @param env script environment
197 * @param source source to parse
198 * @param errors error manager
199 * @param strict strict
200 * @param log debug logger if one is needed
201 */
202 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final DebugLogger log) {
203 this(env, source, errors, strict, 0, log);
204 }
205
206 /**
207 * Construct a parser.
208 *
209 * @param env script environment
210 * @param source source to parse
211 * @param errors error manager
212 * @param strict parser created with strict mode enabled.
213 * @param lineOffset line offset to start counting lines from
214 * @param log debug logger if one is needed
215 */
216 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict, final int lineOffset, final DebugLogger log) {
217 super(source, errors, strict, lineOffset);
218 this.lc = new ParserContext();
219 this.defaultNames = new ArrayDeque<>();
220 this.env = env;
221 this.namespace = new Namespace(env.getNamespace());
222 this.scripting = env._scripting;
223 if (this.scripting) {
224 this.lineInfoReceiver = new Lexer.LineInfoReceiver() {
225 @Override
226 public void lineInfo(final int receiverLine, final int receiverLinePosition) {
227 // update the parser maintained line information
228 Parser.this.line = receiverLine;
229 Parser.this.linePosition = receiverLinePosition;
230 }
231 };
232 } else {
233 // non-scripting mode script can't have multi-line literals
234 this.lineInfoReceiver = null;
235 }
236
237 this.log = log == null ? DebugLogger.DISABLED_LOGGER : log;
238 }
239
240 @Override
241 public DebugLogger getLogger() {
242 return log;
243 }
244
245 @Override
246 public DebugLogger initLogger(final Context context) {
247 return context.getLogger(this.getClass());
248 }
249
250 /**
251 * Sets the name for the first function. This is only used when reparsing anonymous functions to ensure they can
252 * preserve their already assigned name, as that name doesn't appear in their source text.
253 * @param name the name for the first parsed function.
254 */
255 public void setFunctionName(final String name) {
256 defaultNames.push(createIdentNode(0, 0, name));
257 }
258
259 /**
260 * Sets the {@link RecompilableScriptFunctionData} representing the function being reparsed (when this
261 * parser instance is used to reparse a previously parsed function, as part of its on-demand compilation).
262 * This will trigger various special behaviors, such as skipping nested function bodies.
263 * @param reparsedFunction the function being reparsed.
264 */
265 public void setReparsedFunction(final RecompilableScriptFunctionData reparsedFunction) {
266 this.reparsedFunction = reparsedFunction;
267 }
268
269 /**
270 * Execute parse and return the resulting function node.
271 * Errors will be thrown and the error manager will contain information
272 * if parsing should fail
273 *
274 * This is the default parse call, which will name the function node
275 * {code :program} {@link CompilerConstants#PROGRAM}
276 *
277 * @return function node resulting from successful parse
278 */
279 public FunctionNode parse() {
280 return parse(PROGRAM.symbolName(), 0, source.getLength(), false);
281 }
282
283 /**
284 * Set up first token. Skips opening EOL.
285 */
286 private void scanFirstToken() {
287 k = -1;
288 next();
289 }
290
291 /**
292 * Execute parse and return the resulting function node.
293 * Errors will be thrown and the error manager will contain information
294 * if parsing should fail
295 *
296 * This should be used to create one and only one function node
297 *
298 * @param scriptName name for the script, given to the parsed FunctionNode
299 * @param startPos start position in source
300 * @param len length of parse
301 * @param allowPropertyFunction if true, "get" and "set" are allowed as first tokens of the program, followed by
302 * a property getter or setter function. This is used when reparsing a function that can potentially be defined as a
303 * property getter or setter in an object literal.
304 *
305 * @return function node resulting from successful parse
306 */
307 public FunctionNode parse(final String scriptName, final int startPos, final int len, final boolean allowPropertyFunction) {
308 final boolean isTimingEnabled = env.isTimingEnabled();
309 final long t0 = isTimingEnabled ? System.nanoTime() : 0L;
310 log.info(this, " begin for '", scriptName, "'");
311
312 try {
313 stream = new TokenStream();
314 lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
315 lexer.line = lexer.pendingLine = lineOffset + 1;
316 line = lineOffset;
317
318 scanFirstToken();
319 // Begin parse.
320 return program(scriptName, allowPropertyFunction);
321 } catch (final Exception e) {
322 handleParseException(e);
323
324 return null;
325 } finally {
326 final String end = this + " end '" + scriptName + "'";
327 if (isTimingEnabled) {
328 env._timing.accumulateTime(toString(), System.nanoTime() - t0);
329 log.info(end, "' in ", Timing.toMillisPrint(System.nanoTime() - t0), " ms");
330 } else {
331 log.info(end);
332 }
333 }
334 }
335
336 /**
337 * Parse and return the resulting module.
338 * Errors will be thrown and the error manager will contain information
339 * if parsing should fail
340 *
341 * @param moduleName name for the module, given to the parsed FunctionNode
342 * @param startPos start position in source
343 * @param len length of parse
344 *
345 * @return function node resulting from successful parse
346 */
347 public FunctionNode parseModule(final String moduleName, final int startPos, final int len) {
348 try {
349 stream = new TokenStream();
350 lexer = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
351 lexer.line = lexer.pendingLine = lineOffset + 1;
352 line = lineOffset;
353
354 scanFirstToken();
355 // Begin parse.
356 return module(moduleName);
357 } catch (final Exception e) {
358 handleParseException(e);
359
360 return null;
361 }
362 }
363
364 /**
365 * Entry point for parsing a module.
366 *
367 * @param moduleName the module name
368 * @return the parsed module
369 */
370 public FunctionNode parseModule(final String moduleName) {
371 return parseModule(moduleName, 0, source.getLength());
372 }
373
374 /**
375 * Parse and return the list of function parameter list. A comma
376 * separated list of function parameter identifiers is expected to be parsed.
377 * Errors will be thrown and the error manager will contain information
378 * if parsing should fail. This method is used to check if parameter Strings
379 * passed to "Function" constructor is a valid or not.
380 *
381 * @return the list of IdentNodes representing the formal parameter list
382 */
383 public List<IdentNode> parseFormalParameterList() {
384 try {
385 stream = new TokenStream();
386 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
387
388 scanFirstToken();
389
390 return formalParameterList(TokenType.EOF, false);
391 } catch (final Exception e) {
392 handleParseException(e);
393 return null;
394 }
395 }
396
397 /**
398 * Execute parse and return the resulting function node.
399 * Errors will be thrown and the error manager will contain information
400 * if parsing should fail. This method is used to check if code String
401 * passed to "Function" constructor is a valid function body or not.
402 *
403 * @return function node resulting from successful parse
404 */
405 public FunctionNode parseFunctionBody() {
406 try {
407 stream = new TokenStream();
408 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
409 final int functionLine = line;
410
411 scanFirstToken();
412
413 // Make a fake token for the function.
414 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
415 // Set up the function to append elements.
416
417 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), PROGRAM.symbolName());
418 final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, FunctionNode.Kind.NORMAL, functionLine, Collections.<IdentNode>emptyList());
419 lc.push(function);
420
421 final ParserContextBlockNode body = newBlock();
422
423 functionDeclarations = new ArrayList<>();
424 sourceElements(false);
425 addFunctionDeclarations(function);
426 functionDeclarations = null;
427
428 restoreBlock(body);
429 body.setFlag(Block.NEEDS_SCOPE);
430
431 final Block functionBody = new Block(functionToken, source.getLength() - 1,
432 body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
433 lc.pop(function);
434
435 expect(EOF);
436
437 final FunctionNode functionNode = createFunctionNode(
438 function,
439 functionToken,
440 ident,
441 Collections.<IdentNode>emptyList(),
442 FunctionNode.Kind.NORMAL,
443 functionLine,
444 functionBody);
445 printAST(functionNode);
446 return functionNode;
447 } catch (final Exception e) {
448 handleParseException(e);
449 return null;
450 }
451 }
452
453 private void handleParseException(final Exception e) {
454 // Extract message from exception. The message will be in error
455 // message format.
456 String message = e.getMessage();
457
458 // If empty message.
459 if (message == null) {
460 message = e.toString();
461 }
462
463 // Issue message.
464 if (e instanceof ParserException) {
465 errors.error((ParserException)e);
466 } else {
467 errors.error(message);
468 }
469
470 if (env._dump_on_error) {
471 e.printStackTrace(env.getErr());
472 }
473 }
474
475 /**
476 * Skip to a good parsing recovery point.
477 */
478 private void recover(final Exception e) {
479 if (e != null) {
480 // Extract message from exception. The message will be in error
481 // message format.
482 String message = e.getMessage();
483
484 // If empty message.
485 if (message == null) {
486 message = e.toString();
487 }
488
489 // Issue message.
490 if (e instanceof ParserException) {
491 errors.error((ParserException)e);
492 } else {
493 errors.error(message);
494 }
495
496 if (env._dump_on_error) {
497 e.printStackTrace(env.getErr());
498 }
499 }
500
501 // Skip to a recovery point.
502 loop:
503 while (true) {
504 switch (type) {
505 case EOF:
506 // Can not go any further.
507 break loop;
508 case EOL:
509 case SEMICOLON:
510 case RBRACE:
511 // Good recovery points.
512 next();
513 break loop;
514 default:
515 // So we can recover after EOL.
516 nextOrEOL();
517 break;
518 }
519 }
520 }
521
522 /**
523 * Set up a new block.
524 *
525 * @return New block.
526 */
527 private ParserContextBlockNode newBlock() {
528 return lc.push(new ParserContextBlockNode(token));
529 }
530
531 private ParserContextFunctionNode createParserContextFunctionNode(final IdentNode ident, final long functionToken, final FunctionNode.Kind kind, final int functionLine, final List<IdentNode> parameters) {
532 // Build function name.
533 final StringBuilder sb = new StringBuilder();
534
535 final ParserContextFunctionNode parentFunction = lc.getCurrentFunction();
536 if (parentFunction != null && !parentFunction.isProgram()) {
537 sb.append(parentFunction.getName()).append('$');
538 }
539
540 assert ident.getName() != null;
541 sb.append(ident.getName());
542
543 final String name = namespace.uniqueName(sb.toString());
544 assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name;
545
546 int flags = 0;
547 if (isStrictMode) {
548 flags |= FunctionNode.IS_STRICT;
549 }
550 if (parentFunction == null) {
551 flags |= FunctionNode.IS_PROGRAM;
552 }
553
554 final ParserContextFunctionNode functionNode = new ParserContextFunctionNode(functionToken, ident, name, namespace, functionLine, kind, parameters);
555 functionNode.setFlag(flags);
556 return functionNode;
557 }
558
559 private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) {
560 // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody();
561 // Start new block.
562 final FunctionNode functionNode =
563 new FunctionNode(
564 source,
565 functionLine,
566 body.getToken(),
567 Token.descPosition(body.getToken()),
568 startToken,
569 function.getLastToken(),
570 namespace,
571 ident,
572 function.getName(),
573 parameters,
574 kind,
575 function.getFlags(),
576 body,
577 function.getEndParserState(),
578 function.getModule(),
579 function.getDebugFlags());
580
581 printAST(functionNode);
582
583 return functionNode;
584 }
585
586 /**
587 * Restore the current block.
588 */
589 private ParserContextBlockNode restoreBlock(final ParserContextBlockNode block) {
590 return lc.pop(block);
591 }
592
593 /**
594 * Get the statements in a block.
595 * @return Block statements.
596 */
597 private Block getBlock(final boolean needsBraces) {
598 final long blockToken = token;
599 final ParserContextBlockNode newBlock = newBlock();
600 try {
601 // Block opening brace.
602 if (needsBraces) {
603 expect(LBRACE);
604 }
605 // Accumulate block statements.
606 statementList();
607
608 } finally {
609 restoreBlock(newBlock);
610 }
611
612 // Block closing brace.
613 if (needsBraces) {
614 expect(RBRACE);
615 }
616
617 final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC);
618 return new Block(blockToken, finish, flags, newBlock.getStatements());
619 }
620
621 /**
622 * Get the statements in a case clause.
623 */
624 private List<Statement> caseStatementList() {
625 final ParserContextBlockNode newBlock = newBlock();
626 try {
627 statementList();
628 } finally {
629 restoreBlock(newBlock);
630 }
631 return newBlock.getStatements();
632 }
633
634 /**
635 * Get all the statements generated by a single statement.
636 * @return Statements.
637 */
638 private Block getStatement() {
639 return getStatement(false);
640 }
641
642 private Block getStatement(boolean labelledStatement) {
643 if (type == LBRACE) {
644 return getBlock(true);
645 }
646 // Set up new block. Captures first token.
647 final ParserContextBlockNode newBlock = newBlock();
648 try {
649 statement(false, false, true, labelledStatement);
650 } finally {
651 restoreBlock(newBlock);
652 }
653 return new Block(newBlock.getToken(), finish, newBlock.getFlags() | Block.IS_SYNTHETIC, newBlock.getStatements());
654 }
655
656 /**
657 * Detect calls to special functions.
658 * @param ident Called function.
659 */
660 private void detectSpecialFunction(final IdentNode ident) {
661 final String name = ident.getName();
662
663 if (EVAL.symbolName().equals(name)) {
664 markEval(lc);
665 } else if (SUPER.getName().equals(name)) {
666 assert ident.isDirectSuper();
667 markSuperCall(lc);
668 }
669 }
670
671 /**
672 * Detect use of special properties.
673 * @param ident Referenced property.
674 */
675 private void detectSpecialProperty(final IdentNode ident) {
676 if (isArguments(ident)) {
677 // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); }
678 getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS);
679 }
680 }
681
682 private boolean useBlockScope() {
683 return env._es6;
684 }
685
686 private boolean isES6() {
687 return env._es6;
688 }
689
690 private static boolean isArguments(final String name) {
691 return ARGUMENTS_NAME.equals(name);
692 }
693
694 static boolean isArguments(final IdentNode ident) {
695 return isArguments(ident.getName());
696 }
697
698 /**
699 * Tells whether a IdentNode can be used as L-value of an assignment
700 *
701 * @param ident IdentNode to be checked
702 * @return whether the ident can be used as L-value
703 */
704 private static boolean checkIdentLValue(final IdentNode ident) {
705 return ident.tokenType().getKind() != TokenKind.KEYWORD;
706 }
707
708 /**
709 * Verify an assignment expression.
710 * @param op Operation token.
711 * @param lhs Left hand side expression.
712 * @param rhs Right hand side expression.
713 * @return Verified expression.
714 */
715 private Expression verifyAssignment(final long op, final Expression lhs, final Expression rhs) {
716 final TokenType opType = Token.descType(op);
717
718 switch (opType) {
719 case ASSIGN:
720 case ASSIGN_ADD:
721 case ASSIGN_BIT_AND:
722 case ASSIGN_BIT_OR:
723 case ASSIGN_BIT_XOR:
724 case ASSIGN_DIV:
725 case ASSIGN_MOD:
726 case ASSIGN_MUL:
727 case ASSIGN_SAR:
728 case ASSIGN_SHL:
729 case ASSIGN_SHR:
730 case ASSIGN_SUB:
731 if (lhs instanceof IdentNode) {
732 if (!checkIdentLValue((IdentNode)lhs)) {
733 return referenceError(lhs, rhs, false);
734 }
735 verifyIdent((IdentNode)lhs, "assignment");
736 break;
737 } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) {
738 break;
739 } else if (opType == ASSIGN && isDestructuringLhs(lhs)) {
740 verifyDestructuringAssignmentPattern(lhs, "assignment");
741 break;
742 } else {
743 return referenceError(lhs, rhs, env._early_lvalue_error);
744 }
745 default:
746 break;
747 }
748
749 // Build up node.
750 if(BinaryNode.isLogical(opType)) {
751 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
752 }
753 return new BinaryNode(op, lhs, rhs);
754 }
755
756 private boolean isDestructuringLhs(Expression lhs) {
757 if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) {
758 return isES6();
759 }
760 return false;
761 }
762
763 private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) {
764 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
765 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
766 @Override
767 public boolean enterLiteralNode(LiteralNode<?> literalNode) {
768 if (literalNode.isArray()) {
769 boolean restElement = false;
770 for (Expression element : literalNode.getElementExpressions()) {
771 if (element != null) {
772 if (restElement) {
773 throw error(String.format("Unexpected element after rest element"), element.getToken());
774 }
775 if (element.isTokenType(SPREAD_ARRAY)) {
776 restElement = true;
777 Expression lvalue = ((UnaryNode) element).getExpression();
778 if (!checkValidLValue(lvalue, contextString)) {
779 throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken());
780 }
781 }
782 element.accept(this);
783 }
784 }
785 return false;
786 } else {
787 return enterDefault(literalNode);
788 }
789 }
790
791 @Override
792 public boolean enterObjectNode(ObjectNode objectNode) {
793 return true;
794 }
795
796 @Override
797 public boolean enterPropertyNode(PropertyNode propertyNode) {
798 if (propertyNode.getValue() != null) {
799 propertyNode.getValue().accept(this);
800 return false;
801 } else {
802 return enterDefault(propertyNode);
803 }
804 }
805
806 @Override
807 public boolean enterIdentNode(IdentNode identNode) {
808 verifyIdent(identNode, contextString);
809 if (!checkIdentLValue(identNode)) {
810 referenceError(identNode, null, true);
811 return false;
812 }
813 return false;
814 }
815
816 @Override
817 public boolean enterAccessNode(AccessNode accessNode) {
818 return false;
819 }
820
821 @Override
822 public boolean enterIndexNode(IndexNode indexNode) {
823 return false;
824 }
825
826 @Override
827 public boolean enterBinaryNode(BinaryNode binaryNode) {
828 if (binaryNode.isTokenType(ASSIGN)) {
829 binaryNode.lhs().accept(this);
830 // Initializer(rhs) can be any AssignmentExpression
831 return false;
832 } else {
833 return enterDefault(binaryNode);
834 }
835 }
836
837 @Override
838 public boolean enterUnaryNode(UnaryNode unaryNode) {
839 if (unaryNode.isTokenType(SPREAD_ARRAY)) {
840 // rest element
841 return true;
842 } else {
843 return enterDefault(unaryNode);
844 }
845 }
846
847 @Override
848 protected boolean enterDefault(Node node) {
849 throw error(String.format("unexpected node in AssignmentPattern: %s", node));
850 }
851 });
852 }
853
854 private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
855 final TokenType opType = Token.descType(op);
856
857 // Build up node.
858 if (BinaryNode.isLogical(opType)) {
859 return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
860 }
861 return new BinaryNode(op, lhs, rhs);
862 }
863
864
865 /**
866 * Reduce increment/decrement to simpler operations.
867 * @param firstToken First token.
868 * @param tokenType Operation token (INCPREFIX/DEC.)
869 * @param expression Left hand side expression.
870 * @param isPostfix Prefix or postfix.
871 * @return Reduced expression.
872 */
873 private static UnaryNode incDecExpression(final long firstToken, final TokenType tokenType, final Expression expression, final boolean isPostfix) {
874 if (isPostfix) {
875 return new UnaryNode(Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
876 }
877
878 return new UnaryNode(firstToken, expression);
879 }
880
881 /**
882 * -----------------------------------------------------------------------
883 *
884 * Grammar based on
885 *
886 * ECMAScript Language Specification
887 * ECMA-262 5th Edition / December 2009
888 *
889 * -----------------------------------------------------------------------
890 */
891
892 /**
893 * Program :
894 * SourceElements?
895 *
896 * See 14
897 *
898 * Parse the top level script.
899 */
900 private FunctionNode program(final String scriptName, final boolean allowPropertyFunction) {
901 // Make a pseudo-token for the script holding its start and length.
902 final long functionToken = Token.toDesc(FUNCTION, Token.descPosition(Token.withDelimiter(token)), source.getLength());
903 final int functionLine = line;
904
905 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), scriptName);
906 final ParserContextFunctionNode script = createParserContextFunctionNode(
907 ident,
908 functionToken,
909 FunctionNode.Kind.SCRIPT,
910 functionLine,
911 Collections.<IdentNode>emptyList());
912 lc.push(script);
913 final ParserContextBlockNode body = newBlock();
914
915 functionDeclarations = new ArrayList<>();
916 sourceElements(allowPropertyFunction);
917 addFunctionDeclarations(script);
918 functionDeclarations = null;
919
920 restoreBlock(body);
921 body.setFlag(Block.NEEDS_SCOPE);
922 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
923 lc.pop(script);
924 script.setLastToken(token);
925
926 expect(EOF);
927
928 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.SCRIPT, functionLine, programBody);
929 }
930
931 /**
932 * Directive value or null if statement is not a directive.
933 *
934 * @param stmt Statement to be checked
935 * @return Directive value if the given statement is a directive
936 */
937 private String getDirective(final Node stmt) {
938 if (stmt instanceof ExpressionStatement) {
939 final Node expr = ((ExpressionStatement)stmt).getExpression();
940 if (expr instanceof LiteralNode) {
941 final LiteralNode<?> lit = (LiteralNode<?>)expr;
942 final long litToken = lit.getToken();
943 final TokenType tt = Token.descType(litToken);
944 // A directive is either a string or an escape string
945 if (tt == TokenType.STRING || tt == TokenType.ESCSTRING) {
946 // Make sure that we don't unescape anything. Return as seen in source!
947 return source.getString(lit.getStart(), Token.descLength(litToken));
948 }
949 }
950 }
951
952 return null;
953 }
954
955 /**
956 * SourceElements :
957 * SourceElement
958 * SourceElements SourceElement
959 *
960 * See 14
961 *
962 * Parse the elements of the script or function.
963 */
964 private void sourceElements(final boolean shouldAllowPropertyFunction) {
965 List<Node> directiveStmts = null;
966 boolean checkDirective = true;
967 boolean allowPropertyFunction = shouldAllowPropertyFunction;
968 final boolean oldStrictMode = isStrictMode;
969
970
971 try {
972 // If is a script, then process until the end of the script.
973 while (type != EOF) {
974 // Break if the end of a code block.
975 if (type == RBRACE) {
976 break;
977 }
978
979 try {
980 // Get the next element.
981 statement(true, allowPropertyFunction, false, false);
982 allowPropertyFunction = false;
983
984 // check for directive prologues
985 if (checkDirective) {
986 // skip any debug statement like line number to get actual first line
987 final Statement lastStatement = lc.getLastStatement();
988
989 // get directive prologue, if any
990 final String directive = getDirective(lastStatement);
991
992 // If we have seen first non-directive statement,
993 // no more directive statements!!
994 checkDirective = directive != null;
995
996 if (checkDirective) {
997 if (!oldStrictMode) {
998 if (directiveStmts == null) {
999 directiveStmts = new ArrayList<>();
1000 }
1001 directiveStmts.add(lastStatement);
1002 }
1003
1004 // handle use strict directive
1005 if ("use strict".equals(directive)) {
1006 isStrictMode = true;
1007 final ParserContextFunctionNode function = lc.getCurrentFunction();
1008 function.setFlag(FunctionNode.IS_STRICT);
1009
1010 // We don't need to check these, if lexical environment is already strict
1011 if (!oldStrictMode && directiveStmts != null) {
1012 // check that directives preceding this one do not violate strictness
1013 for (final Node statement : directiveStmts) {
1014 // the get value will force unescape of preceding
1015 // escaped string directives
1016 getValue(statement.getToken());
1017 }
1018
1019 // verify that function name as well as parameter names
1020 // satisfy strict mode restrictions.
1021 verifyIdent(function.getIdent(), "function name");
1022 for (final IdentNode param : function.getParameters()) {
1023 verifyIdent(param, "function parameter");
1024 }
1025 }
1026 } else if (Context.DEBUG) {
1027 final int debugFlag = FunctionNode.getDirectiveFlag(directive);
1028 if (debugFlag != 0) {
1029 final ParserContextFunctionNode function = lc.getCurrentFunction();
1030 function.setDebugFlag(debugFlag);
1031 }
1032 }
1033 }
1034 }
1035 } catch (final Exception e) {
1036 final int errorLine = line;
1037 final long errorToken = token;
1038 //recover parsing
1039 recover(e);
1040 final ErrorNode errorExpr = new ErrorNode(errorToken, finish);
1041 final ExpressionStatement expressionStatement = new ExpressionStatement(errorLine, errorToken, finish, errorExpr);
1042 appendStatement(expressionStatement);
1043 }
1044
1045 // No backtracking from here on.
1046 stream.commit(k);
1047 }
1048 } finally {
1049 isStrictMode = oldStrictMode;
1050 }
1051 }
1052
1053 /**
1054 * Parse any of the basic statement types.
1055 *
1056 * Statement :
1057 * BlockStatement
1058 * VariableStatement
1059 * EmptyStatement
1060 * ExpressionStatement
1061 * IfStatement
1062 * BreakableStatement
1063 * ContinueStatement
1064 * BreakStatement
1065 * ReturnStatement
1066 * WithStatement
1067 * LabelledStatement
1068 * ThrowStatement
1069 * TryStatement
1070 * DebuggerStatement
1071 *
1072 * BreakableStatement :
1073 * IterationStatement
1074 * SwitchStatement
1075 *
1076 * BlockStatement :
1077 * Block
1078 *
1079 * Block :
1080 * { StatementList opt }
1081 *
1082 * StatementList :
1083 * StatementListItem
1084 * StatementList StatementListItem
1085 *
1086 * StatementItem :
1087 * Statement
1088 * Declaration
1089 *
1090 * Declaration :
1091 * HoistableDeclaration
1092 * ClassDeclaration
1093 * LexicalDeclaration
1094 *
1095 * HoistableDeclaration :
1096 * FunctionDeclaration
1097 * GeneratorDeclaration
1098 */
1099 private void statement() {
1100 statement(false, false, false, false);
1101 }
1102
1103 /**
1104 * @param topLevel does this statement occur at the "top level" of a script or a function?
1105 * @param allowPropertyFunction allow property "get" and "set" functions?
1106 * @param singleStatement are we in a single statement context?
1107 */
1108 private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) {
1109 switch (type) {
1110 case LBRACE:
1111 block();
1112 break;
1113 case VAR:
1114 variableStatement(type);
1115 break;
1116 case SEMICOLON:
1117 emptyStatement();
1118 break;
1119 case IF:
1120 ifStatement();
1121 break;
1122 case FOR:
1123 forStatement();
1124 break;
1125 case WHILE:
1126 whileStatement();
1127 break;
1128 case DO:
1129 doStatement();
1130 break;
1131 case CONTINUE:
1132 continueStatement();
1133 break;
1134 case BREAK:
1135 breakStatement();
1136 break;
1137 case RETURN:
1138 returnStatement();
1139 break;
1140 case WITH:
1141 withStatement();
1142 break;
1143 case SWITCH:
1144 switchStatement();
1145 break;
1146 case THROW:
1147 throwStatement();
1148 break;
1149 case TRY:
1150 tryStatement();
1151 break;
1152 case DEBUGGER:
1153 debuggerStatement();
1154 break;
1155 case RPAREN:
1156 case RBRACKET:
1157 case EOF:
1158 expect(SEMICOLON);
1159 break;
1160 case FUNCTION:
1161 // As per spec (ECMA section 12), function declarations as arbitrary statement
1162 // is not "portable". Implementation can issue a warning or disallow the same.
1163 if (singleStatement) {
1164 // ES6 B.3.2 Labelled Function Declarations
1165 // It is a Syntax Error if any strict mode source code matches this rule:
1166 // LabelledItem : FunctionDeclaration.
1167 if (!labelledStatement || isStrictMode) {
1168 throw error(AbstractParser.message("expected.stmt", "function declaration"), token);
1169 }
1170 }
1171 functionExpression(true, topLevel || labelledStatement);
1172 return;
1173 default:
1174 if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) {
1175 if (singleStatement) {
1176 throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
1177 }
1178 variableStatement(type);
1179 break;
1180 } else if (type == CLASS && isES6()) {
1181 if (singleStatement) {
1182 throw error(AbstractParser.message("expected.stmt", "class declaration"), token);
1183 }
1184 classDeclaration(false);
1185 break;
1186 }
1187 if (env._const_as_var && type == CONST) {
1188 variableStatement(TokenType.VAR);
1189 break;
1190 }
1191
1192 if (type == IDENT || isNonStrictModeIdent()) {
1193 if (T(k + 1) == COLON) {
1194 labelStatement();
1195 return;
1196 }
1197 if(allowPropertyFunction) {
1198 final String ident = (String)getValue();
1199 final long propertyToken = token;
1200 final int propertyLine = line;
1201 if ("get".equals(ident)) {
1202 next();
1203 addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
1204 return;
1205 } else if ("set".equals(ident)) {
1206 next();
1207 addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
1208 return;
1209 }
1210 }
1211 }
1212
1213 expressionStatement();
1214 break;
1215 }
1216 }
1217
1218 private void addPropertyFunctionStatement(final PropertyFunction propertyFunction) {
1219 final FunctionNode fn = propertyFunction.functionNode;
1220 functionDeclarations.add(new ExpressionStatement(fn.getLineNumber(), fn.getToken(), finish, fn));
1221 }
1222
1223 /**
1224 * ClassDeclaration[Yield, Default] :
1225 * class BindingIdentifier[?Yield] ClassTail[?Yield]
1226 * [+Default] class ClassTail[?Yield]
1227 */
1228 private ClassNode classDeclaration(boolean isDefault) {
1229 int classLineNumber = line;
1230
1231 ClassNode classExpression = classExpression(!isDefault);
1232
1233 if (!isDefault) {
1234 VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST);
1235 appendStatement(classVar);
1236 }
1237 return classExpression;
1238 }
1239
1240 /**
1241 * ClassExpression[Yield] :
1242 * class BindingIdentifier[?Yield]opt ClassTail[?Yield]
1243 */
1244 private ClassNode classExpression(boolean isStatement) {
1245 assert type == CLASS;
1246 int classLineNumber = line;
1247 long classToken = token;
1248 next();
1249
1250 IdentNode className = null;
1251 if (isStatement || type == IDENT) {
1252 className = getIdent();
1253 }
1254
1255 return classTail(classLineNumber, classToken, className);
1256 }
1257
1258 private static final class ClassElementKey {
1259 private final boolean isStatic;
1260 private final String propertyName;
1261
1262 private ClassElementKey(boolean isStatic, String propertyName) {
1263 this.isStatic = isStatic;
1264 this.propertyName = propertyName;
1265 }
1266
1267 @Override
1268 public int hashCode() {
1269 final int prime = 31;
1270 int result = 1;
1271 result = prime * result + (isStatic ? 1231 : 1237);
1272 result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
1273 return result;
1274 }
1275
1276 @Override
1277 public boolean equals(Object obj) {
1278 if (obj instanceof ClassElementKey) {
1279 ClassElementKey other = (ClassElementKey) obj;
1280 return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName);
1281 }
1282 return false;
1283 }
1284 }
1285
1286 /**
1287 * Parse ClassTail and ClassBody.
1288 *
1289 * ClassTail[Yield] :
1290 * ClassHeritage[?Yield]opt { ClassBody[?Yield]opt }
1291 * ClassHeritage[Yield] :
1292 * extends LeftHandSideExpression[?Yield]
1293 *
1294 * ClassBody[Yield] :
1295 * ClassElementList[?Yield]
1296 * ClassElementList[Yield] :
1297 * ClassElement[?Yield]
1298 * ClassElementList[?Yield] ClassElement[?Yield]
1299 * ClassElement[Yield] :
1300 * MethodDefinition[?Yield]
1301 * static MethodDefinition[?Yield]
1302 * ;
1303 */
1304 private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) {
1305 final boolean oldStrictMode = isStrictMode;
1306 isStrictMode = true;
1307 try {
1308 Expression classHeritage = null;
1309 if (type == EXTENDS) {
1310 next();
1311 classHeritage = leftHandSideExpression();
1312 }
1313
1314 expect(LBRACE);
1315
1316 PropertyNode constructor = null;
1317 final ArrayList<PropertyNode> classElements = new ArrayList<>();
1318 final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>();
1319 for (;;) {
1320 if (type == SEMICOLON) {
1321 next();
1322 continue;
1323 }
1324 if (type == RBRACE) {
1325 break;
1326 }
1327 final long classElementToken = token;
1328 boolean isStatic = false;
1329 if (type == STATIC) {
1330 isStatic = true;
1331 next();
1332 }
1333 boolean generator = false;
1334 if (isES6() && type == MUL) {
1335 generator = true;
1336 next();
1337 }
1338 final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator);
1339 if (classElement.isComputed()) {
1340 classElements.add(classElement);
1341 } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) {
1342 if (constructor == null) {
1343 constructor = classElement;
1344 } else {
1345 throw error(AbstractParser.message("multiple.constructors"), classElementToken);
1346 }
1347 } else {
1348 // Check for duplicate method definitions and combine accessor methods.
1349 // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names).
1350
1351 final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName());
1352 final Integer existing = keyToIndexMap.get(key);
1353
1354 if (existing == null) {
1355 keyToIndexMap.put(key, classElements.size());
1356 classElements.add(classElement);
1357 } else {
1358 final PropertyNode existingProperty = classElements.get(existing);
1359
1360 final Expression value = classElement.getValue();
1361 final FunctionNode getter = classElement.getGetter();
1362 final FunctionNode setter = classElement.getSetter();
1363
1364 if (value != null || existingProperty.getValue() != null) {
1365 keyToIndexMap.put(key, classElements.size());
1366 classElements.add(classElement);
1367 } else if (getter != null) {
1368 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
1369 classElements.set(existing, existingProperty.setGetter(getter));
1370 } else if (setter != null) {
1371 assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
1372 classElements.set(existing, existingProperty.setSetter(setter));
1373 }
1374 }
1375 }
1376 }
1377
1378 final long lastToken = token;
1379 expect(RBRACE);
1380
1381 if (constructor == null) {
1382 constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null);
1383 }
1384
1385 classElements.trimToSize();
1386 return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements);
1387 } finally {
1388 isStrictMode = oldStrictMode;
1389 }
1390 }
1391
1392 private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) {
1393 final int ctorFinish = finish;
1394 final List<Statement> statements;
1395 final List<IdentNode> parameters;
1396 final long identToken = Token.recast(classToken, TokenType.IDENT);
1397 if (subclass) {
1398 final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper();
1399 final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter();
1400 final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent);
1401 final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false);
1402 statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall));
1403 parameters = Collections.singletonList(argsIdent);
1404 } else {
1405 statements = Collections.emptyList();
1406 parameters = Collections.emptyList();
1407 }
1408
1409 final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements);
1410 final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor");
1411 final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters);
1412 function.setLastToken(lastToken);
1413
1414 function.setFlag(FunctionNode.ES6_IS_METHOD);
1415 function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR);
1416 if (subclass) {
1417 function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR);
1418 function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
1419 }
1420 if (className == null) {
1421 function.setFlag(FunctionNode.IS_ANONYMOUS);
1422 }
1423
1424 final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode(
1425 function,
1426 classToken,
1427 ctorName,
1428 parameters,
1429 FunctionNode.Kind.NORMAL,
1430 classLineNumber,
1431 body
1432 ), null, null, false, false);
1433 return constructor;
1434 }
1435
1436 private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) {
1437 final long methodToken = token;
1438 final int methodLine = line;
1439 final boolean computed = type == LBRACKET;
1440 final boolean isIdent = type == IDENT;
1441 final Expression propertyName = propertyName();
1442 int flags = FunctionNode.ES6_IS_METHOD;
1443 if (!computed) {
1444 final String name = ((PropertyKey)propertyName).getPropertyName();
1445 if (!generator && isIdent && type != LPAREN && name.equals("get")) {
1446 final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags);
1447 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
1448 return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed);
1449 } else if (!generator && isIdent && type != LPAREN && name.equals("set")) {
1450 final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags);
1451 verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
1452 return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed);
1453 } else {
1454 if (!isStatic && !generator && name.equals("constructor")) {
1455 flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR;
1456 if (subclass) {
1457 flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR;
1458 }
1459 }
1460 verifyAllowedMethodName(propertyName, isStatic, computed, generator, false);
1461 }
1462 }
1463 final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed);
1464 return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed);
1465 }
1466
1467 /**
1468 * ES6 14.5.1 Static Semantics: Early Errors.
1469 */
1470 private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) {
1471 if (!computed) {
1472 if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) {
1473 throw error(AbstractParser.message("generator.constructor"), key.getToken());
1474 }
1475 if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) {
1476 throw error(AbstractParser.message("accessor.constructor"), key.getToken());
1477 }
1478 if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) {
1479 throw error(AbstractParser.message("static.prototype.method"), key.getToken());
1480 }
1481 }
1482 }
1483
1484 /**
1485 * block :
1486 * { StatementList? }
1487 *
1488 * see 12.1
1489 *
1490 * Parse a statement block.
1491 */
1492 private void block() {
1493 appendStatement(new BlockStatement(line, getBlock(true)));
1494 }
1495
1496 /**
1497 * StatementList :
1498 * Statement
1499 * StatementList Statement
1500 *
1501 * See 12.1
1502 *
1503 * Parse a list of statements.
1504 */
1505 private void statementList() {
1506 // Accumulate statements until end of list. */
1507 loop:
1508 while (type != EOF) {
1509 switch (type) {
1510 case EOF:
1511 case CASE:
1512 case DEFAULT:
1513 case RBRACE:
1514 break loop;
1515 default:
1516 break;
1517 }
1518
1519 // Get next statement.
1520 statement();
1521 }
1522 }
1523
1524 /**
1525 * Make sure that the identifier name used is allowed.
1526 *
1527 * @param ident Identifier that is verified
1528 * @param contextString String used in error message to give context to the user
1529 */
1530 private void verifyIdent(final IdentNode ident, final String contextString) {
1531 verifyStrictIdent(ident, contextString);
1532 if (isES6()) {
1533 final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
1534 if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) {
1535 throw error(expectMessage(IDENT));
1536 }
1537 }
1538 }
1539
1540 /**
1541 * Make sure that in strict mode, the identifier name used is allowed.
1542 *
1543 * @param ident Identifier that is verified
1544 * @param contextString String used in error message to give context to the user
1545 */
1546 private void verifyStrictIdent(final IdentNode ident, final String contextString) {
1547 if (isStrictMode) {
1548 switch (ident.getName()) {
1549 case "eval":
1550 case "arguments":
1551 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1552 default:
1553 break;
1554 }
1555
1556 if (ident.isFutureStrictName()) {
1557 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
1558 }
1559 }
1560 }
1561
1562 /*
1563 * VariableStatement :
1564 * var VariableDeclarationList ;
1565 *
1566 * VariableDeclarationList :
1567 * VariableDeclaration
1568 * VariableDeclarationList , VariableDeclaration
1569 *
1570 * VariableDeclaration :
1571 * Identifier Initializer?
1572 *
1573 * Initializer :
1574 * = AssignmentExpression
1575 *
1576 * See 12.2
1577 *
1578 * Parse a VAR statement.
1579 * @param isStatement True if a statement (not used in a FOR.)
1580 */
1581 private void variableStatement(final TokenType varType) {
1582 variableDeclarationList(varType, true, -1);
1583 }
1584
1585 private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) {
1586 // VAR tested in caller.
1587 assert varType == VAR || varType == LET || varType == CONST;
1588 next();
1589
1590 final List<Expression> bindings = new ArrayList<>();
1591 int varFlags = 0;
1592 if (varType == LET) {
1593 varFlags |= VarNode.IS_LET;
1594 } else if (varType == CONST) {
1595 varFlags |= VarNode.IS_CONST;
1596 }
1597
1598 Expression missingAssignment = null;
1599 while (true) {
1600 // Get starting token.
1601 final int varLine = line;
1602 final long varToken = token;
1603 // Get name of var.
1604 if (type == YIELD && inGeneratorFunction()) {
1605 expect(IDENT);
1606 }
1607
1608 final String contextString = "variable name";
1609 Expression binding = bindingIdentifierOrPattern(contextString);
1610 final boolean isDestructuring = !(binding instanceof IdentNode);
1611 if (isDestructuring) {
1612 final int finalVarFlags = varFlags;
1613 verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() {
1614 public void accept(final IdentNode identNode) {
1615 verifyIdent(identNode, contextString);
1616 final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags);
1617 appendStatement(var);
1618 }
1619 });
1620 }
1621
1622 // Assume no init.
1623 Expression init = null;
1624
1625 // Look for initializer assignment.
1626 if (type == ASSIGN) {
1627 next();
1628
1629 // Get initializer expression. Suppress IN if not statement.
1630 if (!isDestructuring) {
1631 defaultNames.push(binding);
1632 }
1633 try {
1634 init = assignmentExpression(!isStatement);
1635 } finally {
1636 if (!isDestructuring) {
1637 defaultNames.pop();
1638 }
1639 }
1640 } else if (isStatement) {
1641 if (isDestructuring) {
1642 throw error(AbstractParser.message("missing.destructuring.assignment"), token);
1643 } else if (varType == CONST) {
1644 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName()));
1645 }
1646 // else, if we are in a for loop, delay checking until we know the kind of loop
1647 }
1648
1649 if (!isDestructuring) {
1650 assert init != null || varType != CONST || !isStatement;
1651 final IdentNode ident = (IdentNode)binding;
1652 if (!isStatement && ident.getName().equals("let")) {
1653 throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1
1654 }
1655 // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
1656 final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident;
1657 binding = name;
1658 final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags);
1659 appendStatement(var);
1660 if (init == null && varType == CONST) {
1661 if (missingAssignment == null) {
1662 missingAssignment = binding;
1663 }
1664 }
1665 } else {
1666 assert init != null || !isStatement;
1667 binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init);
1668 if (isStatement) {
1669 appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding));
1670 } else if (init == null) {
1671 if (missingAssignment == null) {
1672 missingAssignment = binding;
1673 }
1674 }
1675 }
1676 bindings.add(binding);
1677
1678 if (type != COMMARIGHT) {
1679 break;
1680 }
1681 next();
1682 }
1683
1684 // If is a statement then handle end of line.
1685 if (isStatement) {
1686 endOfLine();
1687 } else {
1688 if (type == SEMICOLON) {
1689 // late check for missing assignment, now we know it's a for (init; test; modify) loop
1690 if (missingAssignment != null) {
1691 if (missingAssignment instanceof IdentNode) {
1692 throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName()));
1693 } else {
1694 throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken());
1695 }
1696 }
1697 }
1698 }
1699
1700 return bindings;
1701 }
1702
1703 private boolean isBindingIdentifier() {
1704 return type == IDENT || isNonStrictModeIdent();
1705 }
1706
1707 private IdentNode bindingIdentifier(final String contextString) {
1708 final IdentNode name = getIdent();
1709 verifyIdent(name, contextString);
1710 return name;
1711 }
1712
1713 private Expression bindingPattern() {
1714 if (type == LBRACKET) {
1715 return arrayLiteral();
1716 } else if (type == LBRACE) {
1717 return objectLiteral();
1718 } else {
1719 throw error(AbstractParser.message("expected.binding"));
1720 }
1721 }
1722
1723 private Expression bindingIdentifierOrPattern(final String contextString) {
1724 if (isBindingIdentifier() || !isES6()) {
1725 return bindingIdentifier(contextString);
1726 } else {
1727 return bindingPattern();
1728 }
1729 }
1730
1731 /**
1732 * Verify destructuring variable declaration binding pattern and extract bound variable declarations.
1733 */
1734 private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) {
1735 assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
1736 pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
1737 @Override
1738 public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
1739 if (literalNode.isArray()) {
1740 boolean restElement = false;
1741 for (final Expression element : literalNode.getElementExpressions()) {
1742 if (restElement) {
1743 throw error(String.format("Unexpected element after rest element"), element.getToken());
1744 }
1745 if (element != null) {
1746 if (element.isTokenType(SPREAD_ARRAY)) {
1747 restElement = true;
1748 if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) {
1749 throw error(String.format("Expected a valid binding identifier"), element.getToken());
1750
1751 }
1752 }
1753 element.accept(this);
1754 }
1755 }
1756 return false;
1757 } else {
1758 return enterDefault(literalNode);
1759 }
1760 }
1761
1762 @Override
1763 public boolean enterObjectNode(final ObjectNode objectNode) {
1764 return true;
1765 }
1766
1767 @Override
1768 public boolean enterPropertyNode(final PropertyNode propertyNode) {
1769 if (propertyNode.getValue() != null) {
1770 propertyNode.getValue().accept(this);
1771 return false;
1772 } else {
1773 return enterDefault(propertyNode);
1774 }
1775 }
1776
1777 @Override
1778 public boolean enterIdentNode(final IdentNode identNode) {
1779 identifierCallback.accept(identNode);
1780 return false;
1781 }
1782
1783 @Override
1784 public boolean enterBinaryNode(final BinaryNode binaryNode) {
1785 if (binaryNode.isTokenType(ASSIGN)) {
1786 binaryNode.lhs().accept(this);
1787 // Initializer(rhs) can be any AssignmentExpression
1788 return false;
1789 } else {
1790 return enterDefault(binaryNode);
1791 }
1792 }
1793
1794 @Override
1795 public boolean enterUnaryNode(final UnaryNode unaryNode) {
1796 if (unaryNode.isTokenType(SPREAD_ARRAY)) {
1797 // rest element
1798 return true;
1799 } else {
1800 return enterDefault(unaryNode);
1801 }
1802 }
1803
1804 @Override
1805 protected boolean enterDefault(final Node node) {
1806 throw error(String.format("unexpected node in BindingPattern: %s", node));
1807 }
1808 });
1809 }
1810
1811 /**
1812 * EmptyStatement :
1813 * ;
1814 *
1815 * See 12.3
1816 *
1817 * Parse an empty statement.
1818 */
1819 private void emptyStatement() {
1820 if (env._empty_statements) {
1821 appendStatement(new EmptyNode(line, token, Token.descPosition(token) + Token.descLength(token)));
1822 }
1823
1824 // SEMICOLON checked in caller.
1825 next();
1826 }
1827
1828 /**
1829 * ExpressionStatement :
1830 * Expression ; // [lookahead ~( or function )]
1831 *
1832 * See 12.4
1833 *
1834 * Parse an expression used in a statement block.
1835 */
1836 private void expressionStatement() {
1837 // Lookahead checked in caller.
1838 final int expressionLine = line;
1839 final long expressionToken = token;
1840
1841 // Get expression and add as statement.
1842 final Expression expression = expression();
1843
1844 ExpressionStatement expressionStatement = null;
1845 if (expression != null) {
1846 expressionStatement = new ExpressionStatement(expressionLine, expressionToken, finish, expression);
1847 appendStatement(expressionStatement);
1848 } else {
1849 expect(null);
1850 }
1851
1852 endOfLine();
1853 }
1854
1855 /**
1856 * IfStatement :
1857 * if ( Expression ) Statement else Statement
1858 * if ( Expression ) Statement
1859 *
1860 * See 12.5
1861 *
1862 * Parse an IF statement.
1863 */
1864 private void ifStatement() {
1865 // Capture IF token.
1866 final int ifLine = line;
1867 final long ifToken = token;
1868 // IF tested in caller.
1869 next();
1870
1871 expect(LPAREN);
1872 final Expression test = expression();
1873 expect(RPAREN);
1874 final Block pass = getStatement();
1875
1876 Block fail = null;
1877 if (type == ELSE) {
1878 next();
1879 fail = getStatement();
1880 }
1881
1882 appendStatement(new IfNode(ifLine, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1883 }
1884
1885 /**
1886 * ... IterationStatement:
1887 * ...
1888 * for ( Expression[NoIn]?; Expression? ; Expression? ) Statement
1889 * for ( var VariableDeclarationList[NoIn]; Expression? ; Expression? ) Statement
1890 * for ( LeftHandSideExpression in Expression ) Statement
1891 * for ( var VariableDeclaration[NoIn] in Expression ) Statement
1892 *
1893 * See 12.6
1894 *
1895 * Parse a FOR statement.
1896 */
1897 @SuppressWarnings("fallthrough")
1898 private void forStatement() {
1899 final long forToken = token;
1900 final int forLine = line;
1901 // start position of this for statement. This is used
1902 // for sort order for variables declared in the initializer
1903 // part of this 'for' statement (if any).
1904 final int forStart = Token.descPosition(forToken);
1905 // When ES6 for-let is enabled we create a container block to capture the LET.
1906 final ParserContextBlockNode outer = useBlockScope() ? newBlock() : null;
1907
1908 // Create FOR node, capturing FOR token.
1909 final ParserContextLoopNode forNode = new ParserContextLoopNode();
1910 lc.push(forNode);
1911 Block body = null;
1912 List<Expression> vars = null;
1913 Expression init = null;
1914 JoinPredecessorExpression test = null;
1915 JoinPredecessorExpression modify = null;
1916
1917 int flags = 0;
1918 boolean isForOf = false;
1919
1920 try {
1921 // FOR tested in caller.
1922 next();
1923
1924 // Nashorn extension: for each expression.
1925 // iterate property values rather than property names.
1926 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1927 flags |= ForNode.IS_FOR_EACH;
1928 next();
1929 }
1930
1931 expect(LPAREN);
1932
1933 switch (type) {
1934 case VAR:
1935 // Var declaration captured in for outer block.
1936 vars = variableDeclarationList(type, false, forStart);
1937 break;
1938 case SEMICOLON:
1939 break;
1940 default:
1941 if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) {
1942 flags |= ForNode.PER_ITERATION_SCOPE;
1943 // LET/CONST declaration captured in container block created above.
1944 vars = variableDeclarationList(type, false, forStart);
1945 break;
1946 }
1947 if (env._const_as_var && type == CONST) {
1948 // Var declaration captured in for outer block.
1949 vars = variableDeclarationList(TokenType.VAR, false, forStart);
1950 break;
1951 }
1952
1953 init = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
1954 break;
1955 }
1956
1957 switch (type) {
1958 case SEMICOLON:
1959 // for (init; test; modify)
1960
1961 // for each (init; test; modify) is invalid
1962 if ((flags & ForNode.IS_FOR_EACH) != 0) {
1963 throw error(AbstractParser.message("for.each.without.in"), token);
1964 }
1965
1966 expect(SEMICOLON);
1967 if (type != SEMICOLON) {
1968 test = joinPredecessorExpression();
1969 }
1970 expect(SEMICOLON);
1971 if (type != RPAREN) {
1972 modify = joinPredecessorExpression();
1973 }
1974 break;
1975
1976 case IDENT:
1977 if (env._es6 && "of".equals(getValue())) {
1978 isForOf = true;
1979 // fall through
1980 } else {
1981 expect(SEMICOLON); // fail with expected message
1982 break;
1983 }
1984 case IN:
1985
1986 flags |= isForOf ? ForNode.IS_FOR_OF : ForNode.IS_FOR_IN;
1987 test = new JoinPredecessorExpression();
1988 if (vars != null) {
1989 // for (var i in obj)
1990 if (vars.size() == 1) {
1991 init = new IdentNode((IdentNode)vars.get(0));
1992 if (init.isTokenType(ASSIGN)) {
1993 throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken());
1994 }
1995 assert init instanceof IdentNode || isDestructuringLhs(init);
1996 } else {
1997 // for (var i, j in obj) is invalid
1998 throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken());
1999 }
2000 } else {
2001 // for (expr in obj)
2002 assert init != null : "for..in/of init expression can not be null here";
2003
2004 // check if initial expression is a valid L-value
2005 if (!(init instanceof AccessNode ||
2006 init instanceof IndexNode ||
2007 init instanceof IdentNode)) {
2008 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
2009 }
2010
2011 if (init instanceof IdentNode) {
2012 if (!checkIdentLValue((IdentNode)init)) {
2013 throw error(AbstractParser.message("not.lvalue.for.in.loop", isForOf ? "of" : "in"), init.getToken());
2014 }
2015 verifyStrictIdent((IdentNode)init, isForOf ? "for-of iterator" : "for-in iterator");
2016 }
2017 }
2018
2019 next();
2020
2021 // For-of only allows AssignmentExpression.
2022 modify = isForOf ? new JoinPredecessorExpression(assignmentExpression(false)) : joinPredecessorExpression();
2023 break;
2024
2025 default:
2026 expect(SEMICOLON);
2027 break;
2028 }
2029
2030 expect(RPAREN);
2031
2032 // Set the for body.
2033 body = getStatement();
2034 } finally {
2035 lc.pop(forNode);
2036
2037 for (final Statement var : forNode.getStatements()) {
2038 assert var instanceof VarNode;
2039 appendStatement(var);
2040 }
2041 if (body != null) {
2042 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
2043 }
2044 if (outer != null) {
2045 restoreBlock(outer);
2046 if (body != null) {
2047 appendStatement(new BlockStatement(forLine, new Block(
2048 outer.getToken(),
2049 body.getFinish(),
2050 outer.getStatements())));
2051 }
2052 }
2053 }
2054 }
2055
2056 private boolean checkValidLValue(final Expression init, final String contextString) {
2057 if (init instanceof IdentNode) {
2058 if (!checkIdentLValue((IdentNode)init)) {
2059 return false;
2060 }
2061 verifyIdent((IdentNode)init, contextString);
2062 return true;
2063 } else if (init instanceof AccessNode || init instanceof IndexNode) {
2064 return true;
2065 } else if (isDestructuringLhs(init)) {
2066 verifyDestructuringAssignmentPattern(init, contextString);
2067 return true;
2068 } else {
2069 return false;
2070 }
2071 }
2072
2073 private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) {
2074 assert type == LET;
2075 for (int i = 1;; i++) {
2076 TokenType t = T(k + i);
2077 switch (t) {
2078 case EOL:
2079 case COMMENT:
2080 continue;
2081 case IDENT:
2082 if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) {
2083 return false;
2084 }
2085 // fall through
2086 case LBRACKET:
2087 case LBRACE:
2088 return true;
2089 default:
2090 // accept future strict tokens in non-strict mode (including LET)
2091 if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) {
2092 return true;
2093 }
2094 return false;
2095 }
2096 }
2097 }
2098
2099 /**
2100 * ...IterationStatement :
2101 * ...
2102 * while ( Expression ) Statement
2103 * ...
2104 *
2105 * See 12.6
2106 *
2107 * Parse while statement.
2108 */
2109 private void whileStatement() {
2110 // Capture WHILE token.
2111 final long whileToken = token;
2112 final int whileLine = line;
2113 // WHILE tested in caller.
2114 next();
2115
2116 final ParserContextLoopNode whileNode = new ParserContextLoopNode();
2117 lc.push(whileNode);
2118
2119 JoinPredecessorExpression test = null;
2120 Block body = null;
2121
2122 try {
2123 expect(LPAREN);
2124 test = joinPredecessorExpression();
2125 expect(RPAREN);
2126 body = getStatement();
2127 } finally {
2128 lc.pop(whileNode);
2129 }
2130
2131 if (body != null) {
2132 appendStatement(new WhileNode(whileLine, whileToken, body.getFinish(), false, test, body));
2133 }
2134 }
2135
2136 /**
2137 * ...IterationStatement :
2138 * ...
2139 * do Statement while( Expression ) ;
2140 * ...
2141 *
2142 * See 12.6
2143 *
2144 * Parse DO WHILE statement.
2145 */
2146 private void doStatement() {
2147 // Capture DO token.
2148 final long doToken = token;
2149 int doLine = 0;
2150 // DO tested in the caller.
2151 next();
2152
2153 final ParserContextLoopNode doWhileNode = new ParserContextLoopNode();
2154 lc.push(doWhileNode);
2155
2156 Block body = null;
2157 JoinPredecessorExpression test = null;
2158
2159 try {
2160 // Get DO body.
2161 body = getStatement();
2162
2163 expect(WHILE);
2164 expect(LPAREN);
2165 doLine = line;
2166 test = joinPredecessorExpression();
2167 expect(RPAREN);
2168
2169 if (type == SEMICOLON) {
2170 endOfLine();
2171 }
2172 } finally {
2173 lc.pop(doWhileNode);
2174 }
2175
2176 appendStatement(new WhileNode(doLine, doToken, finish, true, test, body));
2177 }
2178
2179 /**
2180 * ContinueStatement :
2181 * continue Identifier? ; // [no LineTerminator here]
2182 *
2183 * See 12.7
2184 *
2185 * Parse CONTINUE statement.
2186 */
2187 private void continueStatement() {
2188 // Capture CONTINUE token.
2189 final int continueLine = line;
2190 final long continueToken = token;
2191 // CONTINUE tested in caller.
2192 nextOrEOL();
2193
2194 ParserContextLabelNode labelNode = null;
2195
2196 // SEMICOLON or label.
2197 switch (type) {
2198 case RBRACE:
2199 case SEMICOLON:
2200 case EOL:
2201 case EOF:
2202 break;
2203
2204 default:
2205 final IdentNode ident = getIdent();
2206 labelNode = lc.findLabel(ident.getName());
2207
2208 if (labelNode == null) {
2209 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
2210 }
2211
2212 break;
2213 }
2214
2215 final String labelName = labelNode == null ? null : labelNode.getLabelName();
2216 final ParserContextLoopNode targetNode = lc.getContinueTo(labelName);
2217
2218 if (targetNode == null) {
2219 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
2220 }
2221
2222 endOfLine();
2223
2224 // Construct and add CONTINUE node.
2225 appendStatement(new ContinueNode(continueLine, continueToken, finish, labelName));
2226 }
2227
2228 /**
2229 * BreakStatement :
2230 * break Identifier? ; // [no LineTerminator here]
2231 *
2232 * See 12.8
2233 *
2234 */
2235 private void breakStatement() {
2236 // Capture BREAK token.
2237 final int breakLine = line;
2238 final long breakToken = token;
2239 // BREAK tested in caller.
2240 nextOrEOL();
2241
2242 ParserContextLabelNode labelNode = null;
2243
2244 // SEMICOLON or label.
2245 switch (type) {
2246 case RBRACE:
2247 case SEMICOLON:
2248 case EOL:
2249 case EOF:
2250 break;
2251
2252 default:
2253 final IdentNode ident = getIdent();
2254 labelNode = lc.findLabel(ident.getName());
2255
2256 if (labelNode == null) {
2257 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
2258 }
2259
2260 break;
2261 }
2262
2263 //either an explicit label - then get its node or just a "break" - get first breakable
2264 //targetNode is what we are breaking out from.
2265 final String labelName = labelNode == null ? null : labelNode.getLabelName();
2266 final ParserContextBreakableNode targetNode = lc.getBreakable(labelName);
2267 if (targetNode == null) {
2268 throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
2269 }
2270
2271 endOfLine();
2272
2273 // Construct and add BREAK node.
2274 appendStatement(new BreakNode(breakLine, breakToken, finish, labelName));
2275 }
2276
2277 /**
2278 * ReturnStatement :
2279 * return Expression? ; // [no LineTerminator here]
2280 *
2281 * See 12.9
2282 *
2283 * Parse RETURN statement.
2284 */
2285 private void returnStatement() {
2286 // check for return outside function
2287 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) {
2288 throw error(AbstractParser.message("invalid.return"));
2289 }
2290
2291 // Capture RETURN token.
2292 final int returnLine = line;
2293 final long returnToken = token;
2294 // RETURN tested in caller.
2295 nextOrEOL();
2296
2297 Expression expression = null;
2298
2299 // SEMICOLON or expression.
2300 switch (type) {
2301 case RBRACE:
2302 case SEMICOLON:
2303 case EOL:
2304 case EOF:
2305 break;
2306
2307 default:
2308 expression = expression();
2309 break;
2310 }
2311
2312 endOfLine();
2313
2314 // Construct and add RETURN node.
2315 appendStatement(new ReturnNode(returnLine, returnToken, finish, expression));
2316 }
2317
2318 /**
2319 * Parse YieldExpression.
2320 *
2321 * YieldExpression[In] :
2322 * yield
2323 * yield [no LineTerminator here] AssignmentExpression[?In, Yield]
2324 * yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
2325 */
2326 private Expression yieldExpression(final boolean noIn) {
2327 assert inGeneratorFunction();
2328 // Capture YIELD token.
2329 long yieldToken = token;
2330 // YIELD tested in caller.
2331 assert type == YIELD;
2332 nextOrEOL();
2333
2334 Expression expression = null;
2335
2336 boolean yieldAsterisk = false;
2337 if (type == MUL) {
2338 yieldAsterisk = true;
2339 yieldToken = Token.recast(yieldToken, YIELD_STAR);
2340 next();
2341 }
2342
2343 switch (type) {
2344 case RBRACE:
2345 case SEMICOLON:
2346 case EOL:
2347 case EOF:
2348 case COMMARIGHT:
2349 case RPAREN:
2350 case RBRACKET:
2351 case COLON:
2352 if (!yieldAsterisk) {
2353 // treat (yield) as (yield void 0)
2354 expression = newUndefinedLiteral(yieldToken, finish);
2355 if (type == EOL) {
2356 next();
2357 }
2358 break;
2359 } else {
2360 // AssignmentExpression required, fall through
2361 }
2362
2363 default:
2364 expression = assignmentExpression(noIn);
2365 break;
2366 }
2367
2368 // Construct and add YIELD node.
2369 return new UnaryNode(yieldToken, expression);
2370 }
2371
2372 private static UnaryNode newUndefinedLiteral(final long token, final int finish) {
2373 return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0));
2374 }
2375
2376 /**
2377 * WithStatement :
2378 * with ( Expression ) Statement
2379 *
2380 * See 12.10
2381 *
2382 * Parse WITH statement.
2383 */
2384 private void withStatement() {
2385 // Capture WITH token.
2386 final int withLine = line;
2387 final long withToken = token;
2388 // WITH tested in caller.
2389 next();
2390
2391 // ECMA 12.10.1 strict mode restrictions
2392 if (isStrictMode) {
2393 throw error(AbstractParser.message("strict.no.with"), withToken);
2394 }
2395
2396 expect(LPAREN);
2397 final Expression expression = expression();
2398 expect(RPAREN);
2399 final Block body = getStatement();
2400
2401 appendStatement(new WithNode(withLine, withToken, finish, expression, body));
2402 }
2403
2404 /**
2405 * SwitchStatement :
2406 * switch ( Expression ) CaseBlock
2407 *
2408 * CaseBlock :
2409 * { CaseClauses? }
2410 * { CaseClauses? DefaultClause CaseClauses }
2411 *
2412 * CaseClauses :
2413 * CaseClause
2414 * CaseClauses CaseClause
2415 *
2416 * CaseClause :
2417 * case Expression : StatementList?
2418 *
2419 * DefaultClause :
2420 * default : StatementList?
2421 *
2422 * See 12.11
2423 *
2424 * Parse SWITCH statement.
2425 */
2426 private void switchStatement() {
2427 final int switchLine = line;
2428 final long switchToken = token;
2429
2430 // Block to capture variables declared inside the switch statement.
2431 final ParserContextBlockNode switchBlock = newBlock();
2432
2433 // SWITCH tested in caller.
2434 next();
2435
2436 // Create and add switch statement.
2437 final ParserContextSwitchNode switchNode = new ParserContextSwitchNode();
2438 lc.push(switchNode);
2439
2440 CaseNode defaultCase = null;
2441 // Prepare to accumulate cases.
2442 final List<CaseNode> cases = new ArrayList<>();
2443
2444 Expression expression = null;
2445
2446 try {
2447 expect(LPAREN);
2448 expression = expression();
2449 expect(RPAREN);
2450
2451 expect(LBRACE);
2452
2453
2454 while (type != RBRACE) {
2455 // Prepare for next case.
2456 Expression caseExpression = null;
2457 final long caseToken = token;
2458
2459 switch (type) {
2460 case CASE:
2461 next();
2462 caseExpression = expression();
2463 break;
2464
2465 case DEFAULT:
2466 if (defaultCase != null) {
2467 throw error(AbstractParser.message("duplicate.default.in.switch"));
2468 }
2469 next();
2470 break;
2471
2472 default:
2473 // Force an error.
2474 expect(CASE);
2475 break;
2476 }
2477
2478 expect(COLON);
2479
2480 // Get CASE body.
2481 final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList();
2482 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
2483
2484 if (caseExpression == null) {
2485 defaultCase = caseNode;
2486 }
2487
2488 cases.add(caseNode);
2489 }
2490
2491 next();
2492 } finally {
2493 lc.pop(switchNode);
2494 restoreBlock(switchBlock);
2495 }
2496
2497 final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase);
2498 appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement)));
2499 }
2500
2501 /**
2502 * LabelledStatement :
2503 * Identifier : Statement
2504 *
2505 * See 12.12
2506 *
2507 * Parse label statement.
2508 */
2509 private void labelStatement() {
2510 // Capture label token.
2511 final long labelToken = token;
2512 // Get label ident.
2513 final IdentNode ident = getIdent();
2514
2515 expect(COLON);
2516
2517 if (lc.findLabel(ident.getName()) != null) {
2518 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
2519 }
2520
2521 final ParserContextLabelNode labelNode = new ParserContextLabelNode(ident.getName());
2522 Block body = null;
2523 try {
2524 lc.push(labelNode);
2525 body = getStatement(true);
2526 } finally {
2527 assert lc.peek() instanceof ParserContextLabelNode;
2528 lc.pop(labelNode);
2529 }
2530
2531 appendStatement(new LabelNode(line, labelToken, finish, ident.getName(), body));
2532 }
2533
2534 /**
2535 * ThrowStatement :
2536 * throw Expression ; // [no LineTerminator here]
2537 *
2538 * See 12.13
2539 *
2540 * Parse throw statement.
2541 */
2542 private void throwStatement() {
2543 // Capture THROW token.
2544 final int throwLine = line;
2545 final long throwToken = token;
2546 // THROW tested in caller.
2547 nextOrEOL();
2548
2549 Expression expression = null;
2550
2551 // SEMICOLON or expression.
2552 switch (type) {
2553 case RBRACE:
2554 case SEMICOLON:
2555 case EOL:
2556 break;
2557
2558 default:
2559 expression = expression();
2560 break;
2561 }
2562
2563 if (expression == null) {
2564 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2565 }
2566
2567 endOfLine();
2568
2569 appendStatement(new ThrowNode(throwLine, throwToken, finish, expression, false));
2570 }
2571
2572 /**
2573 * TryStatement :
2574 * try Block Catch
2575 * try Block Finally
2576 * try Block Catch Finally
2577 *
2578 * Catch :
2579 * catch( Identifier if Expression ) Block
2580 * catch( Identifier ) Block
2581 *
2582 * Finally :
2583 * finally Block
2584 *
2585 * See 12.14
2586 *
2587 * Parse TRY statement.
2588 */
2589 private void tryStatement() {
2590 // Capture TRY token.
2591 final int tryLine = line;
2592 final long tryToken = token;
2593 // TRY tested in caller.
2594 next();
2595
2596 // Container block needed to act as target for labeled break statements
2597 final int startLine = line;
2598 final ParserContextBlockNode outer = newBlock();
2599 // Create try.
2600
2601 try {
2602 final Block tryBody = getBlock(true);
2603 final List<Block> catchBlocks = new ArrayList<>();
2604
2605 while (type == CATCH) {
2606 final int catchLine = line;
2607 final long catchToken = token;
2608 next();
2609 expect(LPAREN);
2610 final IdentNode exception = getIdent();
2611
2612 // ECMA 12.4.1 strict mode restrictions
2613 verifyStrictIdent(exception, "catch argument");
2614
2615 // Nashorn extension: catch clause can have optional
2616 // condition. So, a single try can have more than one
2617 // catch clause each with it's own condition.
2618 final Expression ifExpression;
2619 if (!env._no_syntax_extensions && type == IF) {
2620 next();
2621 // Get the exception condition.
2622 ifExpression = expression();
2623 } else {
2624 ifExpression = null;
2625 }
2626
2627 expect(RPAREN);
2628
2629 final ParserContextBlockNode catchBlock = newBlock();
2630 try {
2631 // Get CATCH body.
2632 final Block catchBody = getBlock(true);
2633 final CatchNode catchNode = new CatchNode(catchLine, catchToken, finish, exception, ifExpression, catchBody, false);
2634 appendStatement(catchNode);
2635 } finally {
2636 restoreBlock(catchBlock);
2637 catchBlocks.add(new Block(catchBlock.getToken(), finish, catchBlock.getFlags() | Block.IS_SYNTHETIC, catchBlock.getStatements()));
2638 }
2639
2640 // If unconditional catch then should to be the end.
2641 if (ifExpression == null) {
2642 break;
2643 }
2644 }
2645
2646 // Prepare to capture finally statement.
2647 Block finallyStatements = null;
2648
2649 if (type == FINALLY) {
2650 next();
2651 finallyStatements = getBlock(true);
2652 }
2653
2654 // Need at least one catch or a finally.
2655 if (catchBlocks.isEmpty() && finallyStatements == null) {
2656 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
2657 }
2658
2659 final TryNode tryNode = new TryNode(tryLine, tryToken, finish, tryBody, catchBlocks, finallyStatements);
2660 // Add try.
2661 assert lc.peek() == outer;
2662 appendStatement(tryNode);
2663 } finally {
2664 restoreBlock(outer);
2665 }
2666
2667 appendStatement(new BlockStatement(startLine, new Block(tryToken, finish, outer.getFlags() | Block.IS_SYNTHETIC, outer.getStatements())));
2668 }
2669
2670 /**
2671 * DebuggerStatement :
2672 * debugger ;
2673 *
2674 * See 12.15
2675 *
2676 * Parse debugger statement.
2677 */
2678 private void debuggerStatement() {
2679 // Capture DEBUGGER token.
2680 final int debuggerLine = line;
2681 final long debuggerToken = token;
2682 // DEBUGGER tested in caller.
2683 next();
2684 endOfLine();
2685 appendStatement(new DebuggerNode(debuggerLine, debuggerToken, finish));
2686 }
2687
2688 /**
2689 * PrimaryExpression :
2690 * this
2691 * IdentifierReference
2692 * Literal
2693 * ArrayLiteral
2694 * ObjectLiteral
2695 * RegularExpressionLiteral
2696 * TemplateLiteral
2697 * CoverParenthesizedExpressionAndArrowParameterList
2698 *
2699 * CoverParenthesizedExpressionAndArrowParameterList :
2700 * ( Expression )
2701 * ( )
2702 * ( ... BindingIdentifier )
2703 * ( Expression , ... BindingIdentifier )
2704 *
2705 * Parse primary expression.
2706 * @return Expression node.
2707 */
2708 @SuppressWarnings("fallthrough")
2709 private Expression primaryExpression() {
2710 // Capture first token.
2711 final int primaryLine = line;
2712 final long primaryToken = token;
2713
2714 switch (type) {
2715 case THIS:
2716 final String name = type.getName();
2717 next();
2718 markThis(lc);
2719 return new IdentNode(primaryToken, finish, name);
2720 case IDENT:
2721 final IdentNode ident = getIdent();
2722 if (ident == null) {
2723 break;
2724 }
2725 detectSpecialProperty(ident);
2726 return ident;
2727 case OCTAL_LEGACY:
2728 if (isStrictMode) {
2729 throw error(AbstractParser.message("strict.no.octal"), token);
2730 }
2731 case STRING:
2732 case ESCSTRING:
2733 case DECIMAL:
2734 case HEXADECIMAL:
2735 case OCTAL:
2736 case BINARY_NUMBER:
2737 case FLOATING:
2738 case REGEX:
2739 case XML:
2740 return getLiteral();
2741 case EXECSTRING:
2742 return execString(primaryLine, primaryToken);
2743 case FALSE:
2744 next();
2745 return LiteralNode.newInstance(primaryToken, finish, false);
2746 case TRUE:
2747 next();
2748 return LiteralNode.newInstance(primaryToken, finish, true);
2749 case NULL:
2750 next();
2751 return LiteralNode.newInstance(primaryToken, finish);
2752 case LBRACKET:
2753 return arrayLiteral();
2754 case LBRACE:
2755 return objectLiteral();
2756 case LPAREN:
2757 next();
2758
2759 if (isES6()) {
2760 if (type == RPAREN) {
2761 // ()
2762 nextOrEOL();
2763 expectDontAdvance(ARROW);
2764 return new ExpressionList(primaryToken, finish, Collections.emptyList());
2765 } else if (type == ELLIPSIS) {
2766 // (...rest)
2767 final IdentNode restParam = formalParameterList(false).get(0);
2768 expectDontAdvance(RPAREN);
2769 nextOrEOL();
2770 expectDontAdvance(ARROW);
2771 return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam));
2772 }
2773 }
2774
2775 final Expression expression = expression();
2776
2777 expect(RPAREN);
2778
2779 return expression;
2780 case TEMPLATE:
2781 case TEMPLATE_HEAD:
2782 return templateLiteral();
2783
2784 default:
2785 // In this context some operator tokens mark the start of a literal.
2786 if (lexer.scanLiteral(primaryToken, type, lineInfoReceiver)) {
2787 next();
2788 return getLiteral();
2789 }
2790 if (isNonStrictModeIdent()) {
2791 return getIdent();
2792 }
2793 break;
2794 }
2795
2796 return null;
2797 }
2798
2799 /**
2800 * Convert execString to a call to $EXEC.
2801 *
2802 * @param primaryToken Original string token.
2803 * @return callNode to $EXEC.
2804 */
2805 CallNode execString(final int primaryLine, final long primaryToken) {
2806 // Synthesize an ident to call $EXEC.
2807 final IdentNode execIdent = new IdentNode(primaryToken, finish, ScriptingFunctions.EXEC_NAME);
2808 // Skip over EXECSTRING.
2809 next();
2810 // Set up argument list for call.
2811 // Skip beginning of edit string expression.
2812 expect(LBRACE);
2813 // Add the following expression to arguments.
2814 final List<Expression> arguments = Collections.singletonList(expression());
2815 // Skip ending of edit string expression.
2816 expect(RBRACE);
2817
2818 return new CallNode(primaryLine, primaryToken, finish, execIdent, arguments, false);
2819 }
2820
2821 /**
2822 * ArrayLiteral :
2823 * [ Elision? ]
2824 * [ ElementList ]
2825 * [ ElementList , Elision? ]
2826 * [ expression for (LeftHandExpression in expression) ( (if ( Expression ) )? ]
2827 *
2828 * ElementList : Elision? AssignmentExpression
2829 * ElementList , Elision? AssignmentExpression
2830 *
2831 * Elision :
2832 * ,
2833 * Elision ,
2834 *
2835 * See 12.1.4
2836 * JavaScript 1.8
2837 *
2838 * Parse array literal.
2839 * @return Expression node.
2840 */
2841 private LiteralNode<Expression[]> arrayLiteral() {
2842 // Capture LBRACKET token.
2843 final long arrayToken = token;
2844 // LBRACKET tested in caller.
2845 next();
2846
2847 // Prepare to accumulate elements.
2848 final List<Expression> elements = new ArrayList<>();
2849 // Track elisions.
2850 boolean elision = true;
2851 loop:
2852 while (true) {
2853 long spreadToken = 0;
2854 switch (type) {
2855 case RBRACKET:
2856 next();
2857
2858 break loop;
2859
2860 case COMMARIGHT:
2861 next();
2862
2863 // If no prior expression
2864 if (elision) {
2865 elements.add(null);
2866 }
2867
2868 elision = true;
2869
2870 break;
2871
2872 case ELLIPSIS:
2873 if (isES6()) {
2874 spreadToken = token;
2875 next();
2876 }
2877 // fall through
2878
2879 default:
2880 if (!elision) {
2881 throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2882 }
2883
2884 // Add expression element.
2885 Expression expression = assignmentExpression(false);
2886 if (expression != null) {
2887 if (spreadToken != 0) {
2888 expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression);
2889 }
2890 elements.add(expression);
2891 } else {
2892 expect(RBRACKET);
2893 }
2894
2895 elision = false;
2896 break;
2897 }
2898 }
2899
2900 return LiteralNode.newInstance(arrayToken, finish, elements);
2901 }
2902
2903 /**
2904 * ObjectLiteral :
2905 * { }
2906 * { PropertyNameAndValueList } { PropertyNameAndValueList , }
2907 *
2908 * PropertyNameAndValueList :
2909 * PropertyAssignment
2910 * PropertyNameAndValueList , PropertyAssignment
2911 *
2912 * See 11.1.5
2913 *
2914 * Parse an object literal.
2915 * @return Expression node.
2916 */
2917 private ObjectNode objectLiteral() {
2918 // Capture LBRACE token.
2919 final long objectToken = token;
2920 // LBRACE tested in caller.
2921 next();
2922
2923 // Object context.
2924 // Prepare to accumulate elements.
2925 final List<PropertyNode> elements = new ArrayList<>();
2926 final Map<String, Integer> map = new HashMap<>();
2927
2928 // Create a block for the object literal.
2929 boolean commaSeen = true;
2930 loop:
2931 while (true) {
2932 switch (type) {
2933 case RBRACE:
2934 next();
2935 break loop;
2936
2937 case COMMARIGHT:
2938 if (commaSeen) {
2939 throw error(AbstractParser.message("expected.property.id", type.getNameOrType()));
2940 }
2941 next();
2942 commaSeen = true;
2943 break;
2944
2945 default:
2946 if (!commaSeen) {
2947 throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2948 }
2949
2950 commaSeen = false;
2951 // Get and add the next property.
2952 final PropertyNode property = propertyAssignment();
2953
2954 if (property.isComputed()) {
2955 elements.add(property);
2956 break;
2957 }
2958
2959 final String key = property.getKeyName();
2960 final Integer existing = map.get(key);
2961
2962 if (existing == null) {
2963 map.put(key, elements.size());
2964 elements.add(property);
2965 break;
2966 }
2967
2968 final PropertyNode existingProperty = elements.get(existing);
2969
2970 // ECMA section 11.1.5 Object Initialiser
2971 // point # 4 on property assignment production
2972 final Expression value = property.getValue();
2973 final FunctionNode getter = property.getGetter();
2974 final FunctionNode setter = property.getSetter();
2975
2976 final Expression prevValue = existingProperty.getValue();
2977 final FunctionNode prevGetter = existingProperty.getGetter();
2978 final FunctionNode prevSetter = existingProperty.getSetter();
2979
2980 if (!isES6()) {
2981 checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter);
2982 } else {
2983 if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() &&
2984 existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) {
2985 throw error(AbstractParser.message("multiple.proto.key"), property.getToken());
2986 }
2987 }
2988
2989 if (value != null || prevValue != null) {
2990 map.put(key, elements.size());
2991 elements.add(property);
2992 } else if (getter != null) {
2993 assert prevGetter != null || prevSetter != null;
2994 elements.set(existing, existingProperty.setGetter(getter));
2995 } else if (setter != null) {
2996 assert prevGetter != null || prevSetter != null;
2997 elements.set(existing, existingProperty.setSetter(setter));
2998 }
2999 break;
3000 }
3001 }
3002
3003 return new ObjectNode(objectToken, finish, elements);
3004 }
3005
3006 private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) {
3007 // ECMA 11.1.5 strict mode restrictions
3008 if (isStrictMode && value != null && prevValue != null) {
3009 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3010 }
3011
3012 final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
3013 final boolean isAccessor = getter != null || setter != null;
3014
3015 // data property redefined as accessor property
3016 if (prevValue != null && isAccessor) {
3017 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3018 }
3019
3020 // accessor property redefined as data
3021 if (isPrevAccessor && value != null) {
3022 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3023 }
3024
3025 if (isAccessor && isPrevAccessor) {
3026 if (getter != null && prevGetter != null ||
3027 setter != null && prevSetter != null) {
3028 throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
3029 }
3030 }
3031 }
3032
3033 /**
3034 * LiteralPropertyName :
3035 * IdentifierName
3036 * StringLiteral
3037 * NumericLiteral
3038 *
3039 * @return PropertyName node
3040 */
3041 @SuppressWarnings("fallthrough")
3042 private PropertyKey literalPropertyName() {
3043 switch (type) {
3044 case IDENT:
3045 return getIdent().setIsPropertyName();
3046 case OCTAL_LEGACY:
3047 if (isStrictMode) {
3048 throw error(AbstractParser.message("strict.no.octal"), token);
3049 }
3050 case STRING:
3051 case ESCSTRING:
3052 case DECIMAL:
3053 case HEXADECIMAL:
3054 case OCTAL:
3055 case BINARY_NUMBER:
3056 case FLOATING:
3057 return getLiteral();
3058 default:
3059 return getIdentifierName().setIsPropertyName();
3060 }
3061 }
3062
3063 /**
3064 * ComputedPropertyName :
3065 * AssignmentExpression
3066 *
3067 * @return PropertyName node
3068 */
3069 private Expression computedPropertyName() {
3070 expect(LBRACKET);
3071 Expression expression = assignmentExpression(false);
3072 expect(RBRACKET);
3073 return expression;
3074 }
3075
3076 /**
3077 * PropertyName :
3078 * LiteralPropertyName
3079 * ComputedPropertyName
3080 *
3081 * @return PropertyName node
3082 */
3083 private Expression propertyName() {
3084 if (type == LBRACKET && isES6()) {
3085 return computedPropertyName();
3086 } else {
3087 return (Expression)literalPropertyName();
3088 }
3089 }
3090
3091 /**
3092 * PropertyAssignment :
3093 * PropertyName : AssignmentExpression
3094 * get PropertyName ( ) { FunctionBody }
3095 * set PropertyName ( PropertySetParameterList ) { FunctionBody }
3096 *
3097 * PropertySetParameterList :
3098 * Identifier
3099 *
3100 * PropertyName :
3101 * IdentifierName
3102 * StringLiteral
3103 * NumericLiteral
3104 *
3105 * See 11.1.5
3106 *
3107 * Parse an object literal property.
3108 * @return Property or reference node.
3109 */
3110 private PropertyNode propertyAssignment() {
3111 // Capture firstToken.
3112 final long propertyToken = token;
3113 final int functionLine = line;
3114
3115 final Expression propertyName;
3116 final boolean isIdentifier;
3117
3118 boolean generator = false;
3119 if (type == MUL && isES6()) {
3120 generator = true;
3121 next();
3122 }
3123
3124 final boolean computed = type == LBRACKET;
3125 if (type == IDENT) {
3126 // Get IDENT.
3127 final String ident = (String)expectValue(IDENT);
3128
3129 if (type != COLON && (type != LPAREN || !isES6())) {
3130 final long getSetToken = propertyToken;
3131
3132 switch (ident) {
3133 case "get":
3134 final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine);
3135 return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed);
3136
3137 case "set":
3138 final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine);
3139 return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed);
3140 default:
3141 break;
3142 }
3143 }
3144
3145 isIdentifier = true;
3146 IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
3147 if (type == COLON && ident.equals("__proto__")) {
3148 identNode = identNode.setIsProtoPropertyName();
3149 }
3150 propertyName = identNode;
3151 } else {
3152 isIdentifier = isNonStrictModeIdent();
3153 propertyName = propertyName();
3154 }
3155
3156 Expression propertyValue;
3157
3158 if (generator) {
3159 expectDontAdvance(LPAREN);
3160 }
3161
3162 if (type == LPAREN && isES6()) {
3163 propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode;
3164 } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) {
3165 propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName());
3166 if (type == ASSIGN && isES6()) {
3167 // TODO if not destructuring, this is a SyntaxError
3168 final long assignToken = token;
3169 next();
3170 final Expression rhs = assignmentExpression(false);
3171 propertyValue = verifyAssignment(assignToken, propertyValue, rhs);
3172 }
3173 } else {
3174 expect(COLON);
3175
3176 defaultNames.push(propertyName);
3177 try {
3178 propertyValue = assignmentExpression(false);
3179 } finally {
3180 defaultNames.pop();
3181 }
3182 }
3183
3184 return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed);
3185 }
3186
3187 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) {
3188 return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
3189 }
3190
3191 private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) {
3192 final boolean computed = type == LBRACKET;
3193 final Expression propertyName = propertyName();
3194 final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
3195 final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName));
3196 expect(LPAREN);
3197 expect(RPAREN);
3198
3199 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
3200 functionNode.setFlag(flags);
3201 if (computed) {
3202 functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3203 }
3204 lc.push(functionNode);
3205
3206 Block functionBody;
3207
3208
3209 try {
3210 functionBody = functionBody(functionNode);
3211 } finally {
3212 lc.pop(functionNode);
3213 }
3214
3215 final FunctionNode function = createFunctionNode(
3216 functionNode,
3217 getSetToken,
3218 getNameNode,
3219 Collections.<IdentNode>emptyList(),
3220 FunctionNode.Kind.GETTER,
3221 functionLine,
3222 functionBody);
3223
3224 return new PropertyFunction(propertyName, function, computed);
3225 }
3226
3227 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
3228 return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
3229 }
3230
3231 private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) {
3232 final boolean computed = type == LBRACKET;
3233 final Expression propertyName = propertyName();
3234 final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
3235 final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName));
3236 expect(LPAREN);
3237 // be sloppy and allow missing setter parameter even though
3238 // spec does not permit it!
3239 final IdentNode argIdent;
3240 if (isBindingIdentifier()) {
3241 argIdent = getIdent();
3242 verifyIdent(argIdent, "setter argument");
3243 } else {
3244 argIdent = null;
3245 }
3246 expect(RPAREN);
3247 final List<IdentNode> parameters = new ArrayList<>();
3248 if (argIdent != null) {
3249 parameters.add(argIdent);
3250 }
3251
3252
3253 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
3254 functionNode.setFlag(flags);
3255 if (computed) {
3256 functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3257 }
3258 lc.push(functionNode);
3259
3260 Block functionBody;
3261 try {
3262 functionBody = functionBody(functionNode);
3263 } finally {
3264 lc.pop(functionNode);
3265 }
3266
3267
3268 final FunctionNode function = createFunctionNode(
3269 functionNode,
3270 getSetToken,
3271 setNameNode,
3272 parameters,
3273 FunctionNode.Kind.SETTER,
3274 functionLine,
3275 functionBody);
3276
3277 return new PropertyFunction(propertyName, function, computed);
3278 }
3279
3280 private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) {
3281 final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false);
3282 final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName);
3283
3284 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
3285 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null);
3286 functionNode.setFlag(flags);
3287 if (computed) {
3288 functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3289 }
3290 lc.push(functionNode);
3291
3292 try {
3293 final ParserContextBlockNode parameterBlock = newBlock();
3294 final List<IdentNode> parameters;
3295 try {
3296 expect(LPAREN);
3297 parameters = formalParameterList(generator);
3298 functionNode.setParameters(parameters);
3299 expect(RPAREN);
3300 } finally {
3301 restoreBlock(parameterBlock);
3302 }
3303
3304 Block functionBody = functionBody(functionNode);
3305
3306 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
3307
3308 final FunctionNode function = createFunctionNode(
3309 functionNode,
3310 methodToken,
3311 methodNameNode,
3312 parameters,
3313 functionKind,
3314 methodLine,
3315 functionBody);
3316 return new PropertyFunction(key, function, computed);
3317 } finally {
3318 lc.pop(functionNode);
3319 }
3320 }
3321
3322 private static class PropertyFunction {
3323 final Expression key;
3324 final FunctionNode functionNode;
3325 final boolean computed;
3326
3327 PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) {
3328 this.key = key;
3329 this.functionNode = function;
3330 this.computed = computed;
3331 }
3332 }
3333
3334 /**
3335 * LeftHandSideExpression :
3336 * NewExpression
3337 * CallExpression
3338 *
3339 * CallExpression :
3340 * MemberExpression Arguments
3341 * SuperCall
3342 * CallExpression Arguments
3343 * CallExpression [ Expression ]
3344 * CallExpression . IdentifierName
3345 *
3346 * SuperCall :
3347 * super Arguments
3348 *
3349 * See 11.2
3350 *
3351 * Parse left hand side expression.
3352 * @return Expression node.
3353 */
3354 private Expression leftHandSideExpression() {
3355 int callLine = line;
3356 long callToken = token;
3357
3358 Expression lhs = memberExpression();
3359
3360 if (type == LPAREN) {
3361 final List<Expression> arguments = optimizeList(argumentList());
3362
3363 // Catch special functions.
3364 if (lhs instanceof IdentNode) {
3365 detectSpecialFunction((IdentNode)lhs);
3366 }
3367
3368 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3369 }
3370
3371 loop:
3372 while (true) {
3373 // Capture token.
3374 callLine = line;
3375 callToken = token;
3376
3377 switch (type) {
3378 case LPAREN: {
3379 // Get NEW or FUNCTION arguments.
3380 final List<Expression> arguments = optimizeList(argumentList());
3381
3382 // Create call node.
3383 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3384
3385 break;
3386 }
3387 case LBRACKET: {
3388 next();
3389
3390 // Get array index.
3391 final Expression rhs = expression();
3392
3393 expect(RBRACKET);
3394
3395 // Create indexing node.
3396 lhs = new IndexNode(callToken, finish, lhs, rhs);
3397
3398 break;
3399 }
3400 case PERIOD: {
3401 next();
3402
3403 final IdentNode property = getIdentifierName();
3404
3405 // Create property access node.
3406 lhs = new AccessNode(callToken, finish, lhs, property.getName());
3407
3408 break;
3409 }
3410 case TEMPLATE:
3411 case TEMPLATE_HEAD: {
3412 // tagged template literal
3413 final List<Expression> arguments = templateLiteralArgumentList();
3414
3415 // Create call node.
3416 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3417
3418 break;
3419 }
3420 default:
3421 break loop;
3422 }
3423 }
3424
3425 return lhs;
3426 }
3427
3428 /**
3429 * NewExpression :
3430 * MemberExpression
3431 * new NewExpression
3432 *
3433 * See 11.2
3434 *
3435 * Parse new expression.
3436 * @return Expression node.
3437 */
3438 private Expression newExpression() {
3439 final long newToken = token;
3440 // NEW is tested in caller.
3441 next();
3442
3443 if (type == PERIOD && isES6()) {
3444 next();
3445 if (type == IDENT && "target".equals(getValue())) {
3446 if (lc.getCurrentFunction().isProgram()) {
3447 throw error(AbstractParser.message("new.target.in.function"), token);
3448 }
3449 next();
3450 markNewTarget(lc);
3451 return new IdentNode(newToken, finish, "new.target");
3452 } else {
3453 throw error(AbstractParser.message("expected.target"), token);
3454 }
3455 }
3456
3457 // Get function base.
3458 final int callLine = line;
3459 final Expression constructor = memberExpression();
3460 if (constructor == null) {
3461 return null;
3462 }
3463 // Get arguments.
3464 ArrayList<Expression> arguments;
3465
3466 // Allow for missing arguments.
3467 if (type == LPAREN) {
3468 arguments = argumentList();
3469 } else {
3470 arguments = new ArrayList<>();
3471 }
3472
3473 // Nashorn extension: This is to support the following interface implementation
3474 // syntax:
3475 //
3476 // var r = new java.lang.Runnable() {
3477 // run: function() { println("run"); }
3478 // };
3479 //
3480 // The object literal following the "new Constructor()" expression
3481 // is passed as an additional (last) argument to the constructor.
3482 if (!env._no_syntax_extensions && type == LBRACE) {
3483 arguments.add(objectLiteral());
3484 }
3485
3486 final CallNode callNode = new CallNode(callLine, constructor.getToken(), finish, constructor, optimizeList(arguments), true);
3487
3488 return new UnaryNode(newToken, callNode);
3489 }
3490
3491 /**
3492 * MemberExpression :
3493 * PrimaryExpression
3494 * FunctionExpression
3495 * ClassExpression
3496 * GeneratorExpression
3497 * MemberExpression [ Expression ]
3498 * MemberExpression . IdentifierName
3499 * MemberExpression TemplateLiteral
3500 * SuperProperty
3501 * MetaProperty
3502 * new MemberExpression Arguments
3503 *
3504 * SuperProperty :
3505 * super [ Expression ]
3506 * super . IdentifierName
3507 *
3508 * MetaProperty :
3509 * NewTarget
3510 *
3511 * Parse member expression.
3512 * @return Expression node.
3513 */
3514 @SuppressWarnings("fallthrough")
3515 private Expression memberExpression() {
3516 // Prepare to build operation.
3517 Expression lhs;
3518 boolean isSuper = false;
3519
3520 switch (type) {
3521 case NEW:
3522 // Get new expression.
3523 lhs = newExpression();
3524 break;
3525
3526 case FUNCTION:
3527 // Get function expression.
3528 lhs = functionExpression(false, false);
3529 break;
3530
3531 case CLASS:
3532 if (isES6()) {
3533 lhs = classExpression(false);
3534 break;
3535 } else {
3536 // fall through
3537 }
3538
3539 case SUPER:
3540 if (isES6()) {
3541 final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction();
3542 if (currentFunction.isMethod()) {
3543 long identToken = Token.recast(token, IDENT);
3544 next();
3545 lhs = createIdentNode(identToken, finish, SUPER.getName());
3546
3547 switch (type) {
3548 case LBRACKET:
3549 case PERIOD:
3550 getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER);
3551 isSuper = true;
3552 break;
3553 case LPAREN:
3554 if (currentFunction.isSubclassConstructor()) {
3555 lhs = ((IdentNode)lhs).setIsDirectSuper();
3556 break;
3557 } else {
3558 // fall through to throw error
3559 }
3560 default:
3561 throw error(AbstractParser.message("invalid.super"), identToken);
3562 }
3563 break;
3564 } else {
3565 // fall through
3566 }
3567 } else {
3568 // fall through
3569 }
3570
3571 default:
3572 // Get primary expression.
3573 lhs = primaryExpression();
3574 break;
3575 }
3576
3577 loop:
3578 while (true) {
3579 // Capture token.
3580 final long callToken = token;
3581
3582 switch (type) {
3583 case LBRACKET: {
3584 next();
3585
3586 // Get array index.
3587 final Expression index = expression();
3588
3589 expect(RBRACKET);
3590
3591 // Create indexing node.
3592 lhs = new IndexNode(callToken, finish, lhs, index);
3593
3594 if (isSuper) {
3595 isSuper = false;
3596 lhs = ((BaseNode) lhs).setIsSuper();
3597 }
3598
3599 break;
3600 }
3601 case PERIOD: {
3602 if (lhs == null) {
3603 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
3604 }
3605
3606 next();
3607
3608 final IdentNode property = getIdentifierName();
3609
3610 // Create property access node.
3611 lhs = new AccessNode(callToken, finish, lhs, property.getName());
3612
3613 if (isSuper) {
3614 isSuper = false;
3615 lhs = ((BaseNode) lhs).setIsSuper();
3616 }
3617
3618 break;
3619 }
3620 case TEMPLATE:
3621 case TEMPLATE_HEAD: {
3622 // tagged template literal
3623 final int callLine = line;
3624 final List<Expression> arguments = templateLiteralArgumentList();
3625
3626 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
3627
3628 break;
3629 }
3630 default:
3631 break loop;
3632 }
3633 }
3634
3635 return lhs;
3636 }
3637
3638 /**
3639 * Arguments :
3640 * ( )
3641 * ( ArgumentList )
3642 *
3643 * ArgumentList :
3644 * AssignmentExpression
3645 * ... AssignmentExpression
3646 * ArgumentList , AssignmentExpression
3647 * ArgumentList , ... AssignmentExpression
3648 *
3649 * See 11.2
3650 *
3651 * Parse function call arguments.
3652 * @return Argument list.
3653 */
3654 private ArrayList<Expression> argumentList() {
3655 // Prepare to accumulate list of arguments.
3656 final ArrayList<Expression> nodeList = new ArrayList<>();
3657 // LPAREN tested in caller.
3658 next();
3659
3660 // Track commas.
3661 boolean first = true;
3662
3663 while (type != RPAREN) {
3664 // Comma prior to every argument except the first.
3665 if (!first) {
3666 expect(COMMARIGHT);
3667 } else {
3668 first = false;
3669 }
3670
3671 long spreadToken = 0;
3672 if (type == ELLIPSIS && isES6()) {
3673 spreadToken = token;
3674 next();
3675 }
3676
3677 // Get argument expression.
3678 Expression expression = assignmentExpression(false);
3679 if (spreadToken != 0) {
3680 expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression);
3681 }
3682 nodeList.add(expression);
3683 }
3684
3685 expect(RPAREN);
3686 return nodeList;
3687 }
3688
3689 private static <T> List<T> optimizeList(final ArrayList<T> list) {
3690 switch(list.size()) {
3691 case 0: {
3692 return Collections.emptyList();
3693 }
3694 case 1: {
3695 return Collections.singletonList(list.get(0));
3696 }
3697 default: {
3698 list.trimToSize();
3699 return list;
3700 }
3701 }
3702 }
3703
3704 /**
3705 * FunctionDeclaration :
3706 * function Identifier ( FormalParameterList? ) { FunctionBody }
3707 *
3708 * FunctionExpression :
3709 * function Identifier? ( FormalParameterList? ) { FunctionBody }
3710 *
3711 * See 13
3712 *
3713 * Parse function declaration.
3714 * @param isStatement True if for is a statement.
3715 *
3716 * @return Expression node.
3717 */
3718 private Expression functionExpression(final boolean isStatement, final boolean topLevel) {
3719 final long functionToken = token;
3720 final int functionLine = line;
3721 // FUNCTION is tested in caller.
3722 assert type == FUNCTION;
3723 next();
3724
3725 boolean generator = false;
3726 if (type == MUL && isES6()) {
3727 generator = true;
3728 next();
3729 }
3730
3731 IdentNode name = null;
3732
3733 if (isBindingIdentifier()) {
3734 if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) {
3735 // 12.1.1 Early SyntaxError if:
3736 // GeneratorExpression with BindingIdentifier yield
3737 // HoistableDeclaration with BindingIdentifier yield in generator function body
3738 expect(IDENT);
3739 }
3740 name = getIdent();
3741 verifyStrictIdent(name, "function name");
3742 } else if (isStatement) {
3743 // Nashorn extension: anonymous function statements.
3744 // Do not allow anonymous function statement if extensions
3745 // are now allowed. But if we are reparsing then anon function
3746 // statement is possible - because it was used as function
3747 // expression in surrounding code.
3748 if (env._no_syntax_extensions && reparsedFunction == null) {
3749 expect(IDENT);
3750 }
3751 }
3752
3753 // name is null, generate anonymous name
3754 boolean isAnonymous = false;
3755 if (name == null) {
3756 final String tmpName = getDefaultValidFunctionName(functionLine, isStatement);
3757 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName);
3758 isAnonymous = true;
3759 }
3760
3761 FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
3762 List<IdentNode> parameters = Collections.emptyList();
3763 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters);
3764 lc.push(functionNode);
3765
3766 Block functionBody = null;
3767 // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}"
3768 // If we didn't hide the current default name, then the innermost anonymous function would receive "x3".
3769 hideDefaultName();
3770 try {
3771 final ParserContextBlockNode parameterBlock = newBlock();
3772 try {
3773 expect(LPAREN);
3774 parameters = formalParameterList(generator);
3775 functionNode.setParameters(parameters);
3776 expect(RPAREN);
3777 } finally {
3778 restoreBlock(parameterBlock);
3779 }
3780
3781 functionBody = functionBody(functionNode);
3782
3783 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
3784 } finally {
3785 defaultNames.pop();
3786 lc.pop(functionNode);
3787 }
3788
3789 if (isStatement) {
3790 if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) {
3791 functionNode.setFlag(FunctionNode.IS_DECLARED);
3792 } else if (isStrictMode) {
3793 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
3794 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ERROR) {
3795 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here"), functionToken);
3796 } else if (env._function_statement == ScriptEnvironment.FunctionStatementBehavior.WARNING) {
3797 warning(JSErrorType.SYNTAX_ERROR, AbstractParser.message("no.func.decl.here.warn"), functionToken);
3798 }
3799 if (isArguments(name)) {
3800 lc.getCurrentFunction().setFlag(FunctionNode.DEFINES_ARGUMENTS);
3801 }
3802 }
3803
3804 if (isAnonymous) {
3805 functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
3806 }
3807
3808 verifyParameterList(parameters, functionNode);
3809
3810 final FunctionNode function = createFunctionNode(
3811 functionNode,
3812 functionToken,
3813 name,
3814 parameters,
3815 functionKind,
3816 functionLine,
3817 functionBody);
3818
3819 if (isStatement) {
3820 if (isAnonymous) {
3821 appendStatement(new ExpressionStatement(functionLine, functionToken, finish, function));
3822 return function;
3823 }
3824
3825 // mark ES6 block functions as lexically scoped
3826 final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
3827 final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, function, varFlags);
3828 if (topLevel) {
3829 functionDeclarations.add(varNode);
3830 } else if (useBlockScope()) {
3831 prependStatement(varNode); // Hoist to beginning of current block
3832 } else {
3833 appendStatement(varNode);
3834 }
3835 }
3836
3837 return function;
3838 }
3839
3840 private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) {
3841 final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding();
3842 if (duplicateParameter != null) {
3843 if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) {
3844 throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken());
3845 }
3846
3847 final int arity = parameters.size();
3848 final HashSet<String> parametersSet = new HashSet<>(arity);
3849
3850 for (int i = arity - 1; i >= 0; i--) {
3851 final IdentNode parameter = parameters.get(i);
3852 String parameterName = parameter.getName();
3853
3854 if (parametersSet.contains(parameterName)) {
3855 // redefinition of parameter name, rename in non-strict mode
3856 parameterName = functionNode.uniqueName(parameterName);
3857 final long parameterToken = parameter.getToken();
3858 parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
3859 }
3860 parametersSet.add(parameterName);
3861 }
3862 }
3863 }
3864
3865 private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) {
3866 assert functionBody.isFunctionBody();
3867 if (!parameterBlock.getStatements().isEmpty()) {
3868 parameterBlock.appendStatement(new BlockStatement(functionBody));
3869 return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements());
3870 }
3871 return functionBody;
3872 }
3873
3874 private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) {
3875 final String defaultFunctionName = getDefaultFunctionName();
3876 if (isValidIdentifier(defaultFunctionName)) {
3877 if (isStatement) {
3878 // The name will be used as the LHS of a symbol assignment. We add the anonymous function
3879 // prefix to ensure that it can't clash with another variable.
3880 return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName;
3881 }
3882 return defaultFunctionName;
3883 }
3884 return ANON_FUNCTION_PREFIX.symbolName() + functionLine;
3885 }
3886
3887 private static boolean isValidIdentifier(final String name) {
3888 if (name == null || name.isEmpty()) {
3889 return false;
3890 }
3891 if (!Character.isJavaIdentifierStart(name.charAt(0))) {
3892 return false;
3893 }
3894 for (int i = 1; i < name.length(); ++i) {
3895 if (!Character.isJavaIdentifierPart(name.charAt(i))) {
3896 return false;
3897 }
3898 }
3899 return true;
3900 }
3901
3902 private String getDefaultFunctionName() {
3903 if (!defaultNames.isEmpty()) {
3904 final Object nameExpr = defaultNames.peek();
3905 if (nameExpr instanceof PropertyKey) {
3906 markDefaultNameUsed();
3907 return ((PropertyKey)nameExpr).getPropertyName();
3908 } else if (nameExpr instanceof AccessNode) {
3909 markDefaultNameUsed();
3910 return ((AccessNode)nameExpr).getProperty();
3911 }
3912 }
3913 return null;
3914 }
3915
3916 private void markDefaultNameUsed() {
3917 defaultNames.pop();
3918 hideDefaultName();
3919 }
3920
3921 private void hideDefaultName() {
3922 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value
3923 // from. Can't be null
3924 defaultNames.push("");
3925 }
3926
3927 /**
3928 * FormalParameterList :
3929 * Identifier
3930 * FormalParameterList , Identifier
3931 *
3932 * See 13
3933 *
3934 * Parse function parameter list.
3935 * @return List of parameter nodes.
3936 */
3937 private List<IdentNode> formalParameterList(final boolean yield) {
3938 return formalParameterList(RPAREN, yield);
3939 }
3940
3941 /**
3942 * Same as the other method of the same name - except that the end
3943 * token type expected is passed as argument to this method.
3944 *
3945 * FormalParameterList :
3946 * Identifier
3947 * FormalParameterList , Identifier
3948 *
3949 * See 13
3950 *
3951 * Parse function parameter list.
3952 * @return List of parameter nodes.
3953 */
3954 private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) {
3955 // Prepare to gather parameters.
3956 final ArrayList<IdentNode> parameters = new ArrayList<>();
3957 // Track commas.
3958 boolean first = true;
3959
3960 while (type != endType) {
3961 // Comma prior to every argument except the first.
3962 if (!first) {
3963 expect(COMMARIGHT);
3964 } else {
3965 first = false;
3966 }
3967
3968 boolean restParameter = false;
3969 if (type == ELLIPSIS && isES6()) {
3970 next();
3971 restParameter = true;
3972 }
3973
3974 if (type == YIELD && yield) {
3975 expect(IDENT);
3976 }
3977
3978 final long paramToken = token;
3979 final int paramLine = line;
3980 final String contextString = "function parameter";
3981 IdentNode ident;
3982 if (isBindingIdentifier() || restParameter || !isES6()) {
3983 ident = bindingIdentifier(contextString);
3984
3985 if (restParameter) {
3986 ident = ident.setIsRestParameter();
3987 // rest parameter must be last
3988 expectDontAdvance(endType);
3989 parameters.add(ident);
3990 break;
3991 } else if (type == ASSIGN && isES6()) {
3992 next();
3993 ident = ident.setIsDefaultParameter();
3994
3995 if (type == YIELD && yield) {
3996 // error: yield in default expression
3997 expect(IDENT);
3998 }
3999
4000 // default parameter
4001 Expression initializer = assignmentExpression(false);
4002
4003 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4004 if (currentFunction != null) {
4005 // desugar to: param = (param === undefined) ? initializer : param;
4006 // possible alternative: if (param === undefined) param = initializer;
4007 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4008 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4009 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
4010 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4011 }
4012 }
4013
4014 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4015 if (currentFunction != null) {
4016 currentFunction.addParameterBinding(ident);
4017 if (ident.isRestParameter() || ident.isDefaultParameter()) {
4018 currentFunction.setSimpleParameterList(false);
4019 }
4020 }
4021 } else {
4022 final Expression pattern = bindingPattern();
4023 // Introduce synthetic temporary parameter to capture the object to be destructured.
4024 ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter();
4025 verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString);
4026
4027 Expression value = ident;
4028 if (type == ASSIGN) {
4029 next();
4030 ident = ident.setIsDefaultParameter();
4031
4032 // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param
4033 Expression initializer = assignmentExpression(false);
4034 // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list)
4035 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4036 value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4037 }
4038
4039 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4040 if (currentFunction != null) {
4041 // destructuring assignment
4042 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value);
4043 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4044 }
4045 }
4046 parameters.add(ident);
4047 }
4048
4049 parameters.trimToSize();
4050 return parameters;
4051 }
4052
4053 private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) {
4054 verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() {
4055 public void accept(IdentNode identNode) {
4056 verifyIdent(identNode, contextString);
4057
4058 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4059 if (currentFunction != null) {
4060 // declare function-scope variables for destructuring bindings
4061 lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null));
4062 // detect duplicate bounds names in parameter list
4063 currentFunction.addParameterBinding(identNode);
4064 currentFunction.setSimpleParameterList(false);
4065 }
4066 }
4067 });
4068 }
4069
4070 /**
4071 * FunctionBody :
4072 * SourceElements?
4073 *
4074 * See 13
4075 *
4076 * Parse function body.
4077 * @return function node (body.)
4078 */
4079 private Block functionBody(final ParserContextFunctionNode functionNode) {
4080 long lastToken = 0L;
4081 ParserContextBlockNode body = null;
4082 final long bodyToken = token;
4083 Block functionBody;
4084 int bodyFinish = 0;
4085
4086 final boolean parseBody;
4087 Object endParserState = null;
4088 try {
4089 // Create a new function block.
4090 body = newBlock();
4091 if (env._debug_scopes) {
4092 // debug scope options forces everything to be in scope
4093 markEval(lc);
4094 }
4095 assert functionNode != null;
4096 final int functionId = functionNode.getId();
4097 parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
4098 // Nashorn extension: expression closures
4099 if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) {
4100 /*
4101 * Example:
4102 *
4103 * function square(x) x * x;
4104 * print(square(3));
4105 */
4106
4107 // just expression as function body
4108 final Expression expr = assignmentExpression(false);
4109 lastToken = previousToken;
4110 functionNode.setLastToken(previousToken);
4111 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
4112 // EOL uses length field to store the line number
4113 final int lastFinish = Token.descPosition(lastToken) + (Token.descType(lastToken) == EOL ? 0 : Token.descLength(lastToken));
4114 // Only create the return node if we aren't skipping nested functions. Note that we aren't
4115 // skipping parsing of these extended functions; they're considered to be small anyway. Also,
4116 // they don't end with a single well known token, so it'd be very hard to get correctly (see
4117 // the note below for reasoning on skipping happening before instead of after RBRACE for
4118 // details).
4119 if (parseBody) {
4120 final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
4121 appendStatement(returnNode);
4122 }
4123 // bodyFinish = finish;
4124 } else {
4125 expectDontAdvance(LBRACE);
4126 if (parseBody || !skipFunctionBody(functionNode)) {
4127 next();
4128 // Gather the function elements.
4129 final List<Statement> prevFunctionDecls = functionDeclarations;
4130 functionDeclarations = new ArrayList<>();
4131 try {
4132 sourceElements(false);
4133 addFunctionDeclarations(functionNode);
4134 } finally {
4135 functionDeclarations = prevFunctionDecls;
4136 }
4137
4138 lastToken = token;
4139 if (parseBody) {
4140 // Since the lexer can read ahead and lexify some number of tokens in advance and have
4141 // them buffered in the TokenStream, we need to produce a lexer state as it was just
4142 // before it lexified RBRACE, and not whatever is its current (quite possibly well read
4143 // ahead) state.
4144 endParserState = new ParserState(Token.descPosition(token), line, linePosition);
4145
4146 // NOTE: you might wonder why do we capture/restore parser state before RBRACE instead of
4147 // after RBRACE; after all, we could skip the below "expect(RBRACE);" if we captured the
4148 // state after it. The reason is that RBRACE is a well-known token that we can expect and
4149 // will never involve us getting into a weird lexer state, and as such is a great reparse
4150 // point. Typical example of a weird lexer state after RBRACE would be:
4151 // function this_is_skipped() { ... } "use strict";
4152 // because lexer is doing weird off-by-one maneuvers around string literal quotes. Instead
4153 // of compensating for the possibility of a string literal (or similar) after RBRACE,
4154 // we'll rather just restart parsing from this well-known, friendly token instead.
4155 }
4156 }
4157 bodyFinish = finish;
4158 functionNode.setLastToken(token);
4159 expect(RBRACE);
4160 }
4161 } finally {
4162 restoreBlock(body);
4163 }
4164
4165 // NOTE: we can only do alterations to the function node after restoreFunctionNode.
4166
4167 if (parseBody) {
4168 functionNode.setEndParserState(endParserState);
4169 } else if (!body.getStatements().isEmpty()){
4170 // This is to ensure the body is empty when !parseBody but we couldn't skip parsing it (see
4171 // skipFunctionBody() for possible reasons). While it is not strictly necessary for correctness to
4172 // enforce empty bodies in nested functions that were supposed to be skipped, we do assert it as
4173 // an invariant in few places in the compiler pipeline, so for consistency's sake we'll throw away
4174 // nested bodies early if we were supposed to skip 'em.
4175 body.setStatements(Collections.<Statement>emptyList());
4176 }
4177
4178 if (reparsedFunction != null) {
4179 // We restore the flags stored in the function's ScriptFunctionData that we got when we first
4180 // eagerly parsed the code. We're doing it because some flags would be set based on the
4181 // content of the function, or even content of its nested functions, most of which are normally
4182 // skipped during an on-demand compilation.
4183 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
4184 if (data != null) {
4185 // Data can be null if when we originally parsed the file, we removed the function declaration
4186 // as it was dead code.
4187 functionNode.setFlag(data.getFunctionFlags());
4188 // This compensates for missing markEval() in case the function contains an inner function
4189 // that contains eval(), that now we didn't discover since we skipped the inner function.
4190 if (functionNode.hasNestedEval()) {
4191 assert functionNode.hasScopeBlock();
4192 body.setFlag(Block.NEEDS_SCOPE);
4193 }
4194 }
4195 }
4196 functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements());
4197 return functionBody;
4198 }
4199
4200 private boolean skipFunctionBody(final ParserContextFunctionNode functionNode) {
4201 if (reparsedFunction == null) {
4202 // Not reparsing, so don't skip any function body.
4203 return false;
4204 }
4205 // Skip to the RBRACE of this function, and continue parsing from there.
4206 final RecompilableScriptFunctionData data = reparsedFunction.getScriptFunctionData(functionNode.getId());
4207 if (data == null) {
4208 // Nested function is not known to the reparsed function. This can happen if the FunctionNode was
4209 // in dead code that was removed. Both FoldConstants and Lower prune dead code. In that case, the
4210 // FunctionNode was dropped before a RecompilableScriptFunctionData could've been created for it.
4211 return false;
4212 }
4213 final ParserState parserState = (ParserState)data.getEndParserState();
4214 assert parserState != null;
4215
4216 if (k < stream.last() && start < parserState.position && parserState.position <= Token.descPosition(stream.get(stream.last()))) {
4217 // RBRACE is already in the token stream, so fast forward to it
4218 for (; k < stream.last(); k++) {
4219 final long nextToken = stream.get(k + 1);
4220 if (Token.descPosition(nextToken) == parserState.position && Token.descType(nextToken) == RBRACE) {
4221 token = stream.get(k);
4222 type = Token.descType(token);
4223 next();
4224 assert type == RBRACE && start == parserState.position;
4225 return true;
4226 }
4227 }
4228 }
4229
4230 stream.reset();
4231 lexer = parserState.createLexer(source, lexer, stream, scripting && !env._no_syntax_extensions, env._es6);
4232 line = parserState.line;
4233 linePosition = parserState.linePosition;
4234 // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
4235 // the RBRACE.
4236 type = SEMICOLON;
4237 scanFirstToken();
4238
4239 return true;
4240 }
4241
4242 /**
4243 * Encapsulates part of the state of the parser, enough to reconstruct the state of both parser and lexer
4244 * for resuming parsing after skipping a function body.
4245 */
4246 private static class ParserState implements Serializable {
4247 private final int position;
4248 private final int line;
4249 private final int linePosition;
4250
4251 private static final long serialVersionUID = -2382565130754093694L;
4252
4253 ParserState(final int position, final int line, final int linePosition) {
4254 this.position = position;
4255 this.line = line;
4256 this.linePosition = linePosition;
4257 }
4258
4259 Lexer createLexer(final Source source, final Lexer lexer, final TokenStream stream, final boolean scripting, final boolean es6) {
4260 final Lexer newLexer = new Lexer(source, position, lexer.limit - position, stream, scripting, es6, true);
4261 newLexer.restoreState(new Lexer.State(position, Integer.MAX_VALUE, line, -1, linePosition, SEMICOLON));
4262 return newLexer;
4263 }
4264 }
4265
4266 private void printAST(final FunctionNode functionNode) {
4267 if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
4268 env.getErr().println(new ASTWriter(functionNode));
4269 }
4270
4271 if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
4272 env.getErr().println(new PrintVisitor(functionNode, true, false));
4273 }
4274 }
4275
4276 private void addFunctionDeclarations(final ParserContextFunctionNode functionNode) {
4277 VarNode lastDecl = null;
4278 for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
4279 Statement decl = functionDeclarations.get(i);
4280 if (lastDecl == null && decl instanceof VarNode) {
4281 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
4282 functionNode.setFlag(FunctionNode.HAS_FUNCTION_DECLARATIONS);
4283 }
4284 prependStatement(decl);
4285 }
4286 }
4287
4288 private RuntimeNode referenceError(final Expression lhs, final Expression rhs, final boolean earlyError) {
4289 if (earlyError) {
4290 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
4291 }
4292 final ArrayList<Expression> args = new ArrayList<>();
4293 args.add(lhs);
4294 if (rhs == null) {
4295 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish()));
4296 } else {
4297 args.add(rhs);
4298 }
4299 args.add(LiteralNode.newInstance(lhs.getToken(), lhs.getFinish(), lhs.toString()));
4300 return new RuntimeNode(lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
4301 }
4302
4303 /**
4304 * PostfixExpression :
4305 * LeftHandSideExpression
4306 * LeftHandSideExpression ++ // [no LineTerminator here]
4307 * LeftHandSideExpression -- // [no LineTerminator here]
4308 *
4309 * See 11.3
4310 *
4311 * UnaryExpression :
4312 * PostfixExpression
4313 * delete UnaryExpression
4314 * void UnaryExpression
4315 * typeof UnaryExpression
4316 * ++ UnaryExpression
4317 * -- UnaryExpression
4318 * + UnaryExpression
4319 * - UnaryExpression
4320 * ~ UnaryExpression
4321 * ! UnaryExpression
4322 *
4323 * See 11.4
4324 *
4325 * Parse unary expression.
4326 * @return Expression node.
4327 */
4328 private Expression unaryExpression() {
4329 final int unaryLine = line;
4330 final long unaryToken = token;
4331
4332 switch (type) {
4333 case DELETE: {
4334 next();
4335 final Expression expr = unaryExpression();
4336 if (expr instanceof BaseNode || expr instanceof IdentNode) {
4337 return new UnaryNode(unaryToken, expr);
4338 }
4339 appendStatement(new ExpressionStatement(unaryLine, unaryToken, finish, expr));
4340 return LiteralNode.newInstance(unaryToken, finish, true);
4341 }
4342 case VOID:
4343 case TYPEOF:
4344 case ADD:
4345 case SUB:
4346 case BIT_NOT:
4347 case NOT:
4348 next();
4349 final Expression expr = unaryExpression();
4350 return new UnaryNode(unaryToken, expr);
4351
4352 case INCPREFIX:
4353 case DECPREFIX:
4354 final TokenType opType = type;
4355 next();
4356
4357 final Expression lhs = leftHandSideExpression();
4358 // ++, -- without operand..
4359 if (lhs == null) {
4360 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
4361 }
4362
4363 return verifyIncDecExpression(unaryToken, opType, lhs, false);
4364
4365 default:
4366 break;
4367 }
4368
4369 Expression expression = leftHandSideExpression();
4370
4371 if (last != EOL) {
4372 switch (type) {
4373 case INCPREFIX:
4374 case DECPREFIX:
4375 final long opToken = token;
4376 final TokenType opType = type;
4377 final Expression lhs = expression;
4378 // ++, -- without operand..
4379 if (lhs == null) {
4380 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
4381 }
4382 next();
4383
4384 return verifyIncDecExpression(opToken, opType, lhs, true);
4385 default:
4386 break;
4387 }
4388 }
4389
4390 if (expression == null) {
4391 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
4392 }
4393
4394 return expression;
4395 }
4396
4397 private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) {
4398 assert lhs != null;
4399
4400 if (!(lhs instanceof AccessNode ||
4401 lhs instanceof IndexNode ||
4402 lhs instanceof IdentNode)) {
4403 return referenceError(lhs, null, env._early_lvalue_error);
4404 }
4405
4406 if (lhs instanceof IdentNode) {
4407 if (!checkIdentLValue((IdentNode)lhs)) {
4408 return referenceError(lhs, null, false);
4409 }
4410 verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
4411 }
4412
4413 return incDecExpression(unaryToken, opType, lhs, isPostfix);
4414 }
4415
4416 /**
4417 * {@code
4418 * MultiplicativeExpression :
4419 * UnaryExpression
4420 * MultiplicativeExpression * UnaryExpression
4421 * MultiplicativeExpression / UnaryExpression
4422 * MultiplicativeExpression % UnaryExpression
4423 *
4424 * See 11.5
4425 *
4426 * AdditiveExpression :
4427 * MultiplicativeExpression
4428 * AdditiveExpression + MultiplicativeExpression
4429 * AdditiveExpression - MultiplicativeExpression
4430 *
4431 * See 11.6
4432 *
4433 * ShiftExpression :
4434 * AdditiveExpression
4435 * ShiftExpression << AdditiveExpression
4436 * ShiftExpression >> AdditiveExpression
4437 * ShiftExpression >>> AdditiveExpression
4438 *
4439 * See 11.7
4440 *
4441 * RelationalExpression :
4442 * ShiftExpression
4443 * RelationalExpression < ShiftExpression
4444 * RelationalExpression > ShiftExpression
4445 * RelationalExpression <= ShiftExpression
4446 * RelationalExpression >= ShiftExpression
4447 * RelationalExpression instanceof ShiftExpression
4448 * RelationalExpression in ShiftExpression // if !noIf
4449 *
4450 * See 11.8
4451 *
4452 * RelationalExpression
4453 * EqualityExpression == RelationalExpression
4454 * EqualityExpression != RelationalExpression
4455 * EqualityExpression === RelationalExpression
4456 * EqualityExpression !== RelationalExpression
4457 *
4458 * See 11.9
4459 *
4460 * BitwiseANDExpression :
4461 * EqualityExpression
4462 * BitwiseANDExpression & EqualityExpression
4463 *
4464 * BitwiseXORExpression :
4465 * BitwiseANDExpression
4466 * BitwiseXORExpression ^ BitwiseANDExpression
4467 *
4468 * BitwiseORExpression :
4469 * BitwiseXORExpression
4470 * BitwiseORExpression | BitwiseXORExpression
4471 *
4472 * See 11.10
4473 *
4474 * LogicalANDExpression :
4475 * BitwiseORExpression
4476 * LogicalANDExpression && BitwiseORExpression
4477 *
4478 * LogicalORExpression :
4479 * LogicalANDExpression
4480 * LogicalORExpression || LogicalANDExpression
4481 *
4482 * See 11.11
4483 *
4484 * ConditionalExpression :
4485 * LogicalORExpression
4486 * LogicalORExpression ? AssignmentExpression : AssignmentExpression
4487 *
4488 * See 11.12
4489 *
4490 * AssignmentExpression :
4491 * ConditionalExpression
4492 * LeftHandSideExpression AssignmentOperator AssignmentExpression
4493 *
4494 * AssignmentOperator :
4495 * = *= /= %= += -= <<= >>= >>>= &= ^= |=
4496 *
4497 * See 11.13
4498 *
4499 * Expression :
4500 * AssignmentExpression
4501 * Expression , AssignmentExpression
4502 *
4503 * See 11.14
4504 * }
4505 *
4506 * Parse expression.
4507 * @return Expression node.
4508 */
4509 protected Expression expression() {
4510 // This method is protected so that subclass can get details
4511 // at expression start point!
4512
4513 // Include commas in expression parsing.
4514 return expression(false);
4515 }
4516
4517 private Expression expression(final boolean noIn) {
4518 Expression assignmentExpression = assignmentExpression(noIn);
4519 while (type == COMMARIGHT) {
4520 long commaToken = token;
4521 next();
4522
4523 boolean rhsRestParameter = false;
4524 if (type == ELLIPSIS && isES6()) {
4525 // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error).
4526 // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead.
4527 if (isRestParameterEndOfArrowFunctionParameterList()) {
4528 next();
4529 rhsRestParameter = true;
4530 }
4531 }
4532
4533 Expression rhs = assignmentExpression(noIn);
4534
4535 if (rhsRestParameter) {
4536 rhs = ((IdentNode)rhs).setIsRestParameter();
4537 // Our only valid move is to end Expression here and continue with ArrowFunction.
4538 // We've already checked that this is the parameter list of an arrow function (see above).
4539 // RPAREN is next, so we'll finish the binary expression and drop out of the loop.
4540 assert type == RPAREN;
4541 }
4542
4543 assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs);
4544 }
4545 return assignmentExpression;
4546 }
4547
4548 private Expression expression(final int minPrecedence, final boolean noIn) {
4549 return expression(unaryExpression(), minPrecedence, noIn);
4550 }
4551
4552 private JoinPredecessorExpression joinPredecessorExpression() {
4553 return new JoinPredecessorExpression(expression());
4554 }
4555
4556 private Expression expression(final Expression exprLhs, final int minPrecedence, final boolean noIn) {
4557 // Get the precedence of the next operator.
4558 int precedence = type.getPrecedence();
4559 Expression lhs = exprLhs;
4560
4561 // While greater precedence.
4562 while (type.isOperator(noIn) && precedence >= minPrecedence) {
4563 // Capture the operator token.
4564 final long op = token;
4565
4566 if (type == TERNARY) {
4567 // Skip operator.
4568 next();
4569
4570 // Pass expression. Middle expression of a conditional expression can be a "in"
4571 // expression - even in the contexts where "in" is not permitted.
4572 final Expression trueExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), false);
4573
4574 expect(COLON);
4575
4576 // Fail expression.
4577 final Expression falseExpr = expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
4578
4579 // Build up node.
4580 lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
4581 } else {
4582 // Skip operator.
4583 next();
4584
4585 // Get the next primary expression.
4586 Expression rhs;
4587 final boolean isAssign = Token.descType(op) == ASSIGN;
4588 if(isAssign) {
4589 defaultNames.push(lhs);
4590 }
4591 try {
4592 rhs = unaryExpression();
4593 // Get precedence of next operator.
4594 int nextPrecedence = type.getPrecedence();
4595
4596 // Subtask greater precedence.
4597 while (type.isOperator(noIn) &&
4598 (nextPrecedence > precedence ||
4599 nextPrecedence == precedence && !type.isLeftAssociative())) {
4600 rhs = expression(rhs, nextPrecedence, noIn);
4601 nextPrecedence = type.getPrecedence();
4602 }
4603 } finally {
4604 if(isAssign) {
4605 defaultNames.pop();
4606 }
4607 }
4608 lhs = verifyAssignment(op, lhs, rhs);
4609 }
4610
4611 precedence = type.getPrecedence();
4612 }
4613
4614 return lhs;
4615 }
4616
4617 /**
4618 * AssignmentExpression.
4619 *
4620 * AssignmentExpression[In, Yield] :
4621 * ConditionalExpression[?In, ?Yield]
4622 * [+Yield] YieldExpression[?In]
4623 * ArrowFunction[?In, ?Yield]
4624 * LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield]
4625 * LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield]
4626 */
4627 protected Expression assignmentExpression(final boolean noIn) {
4628 // This method is protected so that subclass can get details
4629 // at assignment expression start point!
4630
4631 if (type == YIELD && inGeneratorFunction() && isES6()) {
4632 return yieldExpression(noIn);
4633 }
4634
4635 final long startToken = token;
4636 final int startLine = line;
4637 final Expression exprLhs = conditionalExpression(noIn);
4638
4639 if (type == ARROW && isES6()) {
4640 if (checkNoLineTerminator()) {
4641 final Expression paramListExpr;
4642 if (exprLhs instanceof ExpressionList) {
4643 paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0));
4644 } else {
4645 paramListExpr = exprLhs;
4646 }
4647 return arrowFunction(startToken, startLine, paramListExpr);
4648 }
4649 }
4650 assert !(exprLhs instanceof ExpressionList);
4651
4652 if (isAssignmentOperator(type)) {
4653 final boolean isAssign = type == ASSIGN;
4654 if (isAssign) {
4655 defaultNames.push(exprLhs);
4656 }
4657 try {
4658 final long assignToken = token;
4659 next();
4660 final Expression exprRhs = assignmentExpression(noIn);
4661 return verifyAssignment(assignToken, exprLhs, exprRhs);
4662 } finally {
4663 if (isAssign) {
4664 defaultNames.pop();
4665 }
4666 }
4667 } else {
4668 return exprLhs;
4669 }
4670 }
4671
4672 /**
4673 * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}?
4674 */
4675 private static boolean isAssignmentOperator(TokenType type) {
4676 switch (type) {
4677 case ASSIGN:
4678 case ASSIGN_ADD:
4679 case ASSIGN_BIT_AND:
4680 case ASSIGN_BIT_OR:
4681 case ASSIGN_BIT_XOR:
4682 case ASSIGN_DIV:
4683 case ASSIGN_MOD:
4684 case ASSIGN_MUL:
4685 case ASSIGN_SAR:
4686 case ASSIGN_SHL:
4687 case ASSIGN_SHR:
4688 case ASSIGN_SUB:
4689 return true;
4690 }
4691 return false;
4692 }
4693
4694 /**
4695 * ConditionalExpression.
4696 */
4697 private Expression conditionalExpression(boolean noIn) {
4698 return expression(TERNARY.getPrecedence(), noIn);
4699 }
4700
4701 /**
4702 * ArrowFunction.
4703 *
4704 * @param startToken start token of the ArrowParameters expression
4705 * @param functionLine start line of the arrow function
4706 * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list)
4707 */
4708 private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) {
4709 // caller needs to check that there's no LineTerminator between parameter list and arrow
4710 assert type != ARROW || checkNoLineTerminator();
4711 expect(ARROW);
4712
4713 final long functionToken = Token.recast(startToken, ARROW);
4714 final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), NameCodec.encode("=>:") + functionLine);
4715 final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null);
4716 functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
4717
4718 lc.push(functionNode);
4719 try {
4720 ParserContextBlockNode parameterBlock = newBlock();
4721 final List<IdentNode> parameters;
4722 try {
4723 parameters = convertArrowFunctionParameterList(paramListExpr, functionLine);
4724 functionNode.setParameters(parameters);
4725
4726 if (!functionNode.isSimpleParameterList()) {
4727 markEvalInArrowParameterList(parameterBlock);
4728 }
4729 } finally {
4730 restoreBlock(parameterBlock);
4731 }
4732 Block functionBody = functionBody(functionNode);
4733
4734 functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
4735
4736 verifyParameterList(parameters, functionNode);
4737
4738 final FunctionNode function = createFunctionNode(
4739 functionNode,
4740 functionToken,
4741 name,
4742 parameters,
4743 FunctionNode.Kind.ARROW,
4744 functionLine,
4745 functionBody);
4746 return function;
4747 } finally {
4748 lc.pop(functionNode);
4749 }
4750 }
4751
4752 private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) {
4753 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
4754 final ParserContextFunctionNode current = iter.next();
4755 final ParserContextFunctionNode parent = iter.next();
4756
4757 if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) {
4758 // we might have flagged has-eval in the parent function during parsing the parameter list,
4759 // if the parameter list contains eval; must tag arrow function as has-eval.
4760 for (final Statement st : parameterBlock.getStatements()) {
4761 st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
4762 @Override
4763 public boolean enterCallNode(final CallNode callNode) {
4764 if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) {
4765 current.setFlag(FunctionNode.HAS_EVAL);
4766 }
4767 return true;
4768 }
4769 });
4770 }
4771 // TODO: function containing the arrow function should not be flagged has-eval
4772 }
4773 }
4774
4775 private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) {
4776 final List<IdentNode> parameters;
4777 if (paramListExpr == null) {
4778 // empty parameter list, i.e. () =>
4779 parameters = Collections.emptyList();
4780 } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) {
4781 parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine));
4782 } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) {
4783 parameters = new ArrayList<>();
4784 Expression car = paramListExpr;
4785 do {
4786 final Expression cdr = ((BinaryNode) car).rhs();
4787 parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine));
4788 car = ((BinaryNode) car).lhs();
4789 } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT);
4790 parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine));
4791 } else {
4792 throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken());
4793 }
4794 return parameters;
4795 }
4796
4797 private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) {
4798 final String contextString = "function parameter";
4799 if (param instanceof IdentNode) {
4800 IdentNode ident = (IdentNode)param;
4801 verifyStrictIdent(ident, contextString);
4802 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4803 if (currentFunction != null) {
4804 currentFunction.addParameterBinding(ident);
4805 }
4806 return ident;
4807 }
4808
4809 if (param.isTokenType(ASSIGN)) {
4810 Expression lhs = ((BinaryNode) param).lhs();
4811 long paramToken = lhs.getToken();
4812 Expression initializer = ((BinaryNode) param).rhs();
4813 if (lhs instanceof IdentNode) {
4814 // default parameter
4815 IdentNode ident = (IdentNode) lhs;
4816
4817 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4818 if (currentFunction != null) {
4819 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4820 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4821 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
4822 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4823
4824 currentFunction.addParameterBinding(ident);
4825 currentFunction.setSimpleParameterList(false);
4826 }
4827 return ident;
4828 } else if (isDestructuringLhs(lhs)) {
4829 // binding pattern with initializer
4830 // Introduce synthetic temporary parameter to capture the object to be destructured.
4831 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter();
4832 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
4833
4834 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4835 if (currentFunction != null) {
4836 BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
4837 TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
4838 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value);
4839 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4840 }
4841 return ident;
4842 }
4843 } else if (isDestructuringLhs(param)) {
4844 // binding pattern
4845 long paramToken = param.getToken();
4846
4847 // Introduce synthetic temporary parameter to capture the object to be destructured.
4848 IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter();
4849 verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
4850
4851 ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
4852 if (currentFunction != null) {
4853 BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident);
4854 lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
4855 }
4856 return ident;
4857 }
4858 throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken());
4859 }
4860
4861 private boolean checkNoLineTerminator() {
4862 assert type == ARROW;
4863 if (last == RPAREN) {
4864 return true;
4865 } else if (last == IDENT) {
4866 return true;
4867 }
4868 for (int i = k - 1; i >= 0; i--) {
4869 TokenType t = T(i);
4870 switch (t) {
4871 case RPAREN:
4872 case IDENT:
4873 return true;
4874 case EOL:
4875 return false;
4876 case COMMENT:
4877 continue;
4878 default:
4879 if (t.getKind() == TokenKind.FUTURESTRICT) {
4880 return true;
4881 }
4882 return false;
4883 }
4884 }
4885 return false;
4886 }
4887
4888 /**
4889 * Peek ahead to see if what follows after the ellipsis is a rest parameter
4890 * at the end of an arrow function parameter list.
4891 */
4892 private boolean isRestParameterEndOfArrowFunctionParameterList() {
4893 assert type == ELLIPSIS;
4894 // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT
4895 int i = 1;
4896 for (;;) {
4897 TokenType t = T(k + i++);
4898 if (t == IDENT) {
4899 break;
4900 } else if (t == EOL || t == COMMENT) {
4901 continue;
4902 } else {
4903 return false;
4904 }
4905 }
4906 for (;;) {
4907 TokenType t = T(k + i++);
4908 if (t == RPAREN) {
4909 break;
4910 } else if (t == EOL || t == COMMENT) {
4911 continue;
4912 } else {
4913 return false;
4914 }
4915 }
4916 for (;;) {
4917 TokenType t = T(k + i++);
4918 if (t == ARROW) {
4919 break;
4920 } else if (t == COMMENT) {
4921 continue;
4922 } else {
4923 return false;
4924 }
4925 }
4926 return true;
4927 }
4928
4929 /**
4930 * Parse an end of line.
4931 */
4932 private void endOfLine() {
4933 switch (type) {
4934 case SEMICOLON:
4935 case EOL:
4936 next();
4937 break;
4938 case RPAREN:
4939 case RBRACKET:
4940 case RBRACE:
4941 case EOF:
4942 break;
4943 default:
4944 if (last != EOL) {
4945 expect(SEMICOLON);
4946 }
4947 break;
4948 }
4949 }
4950
4951 /**
4952 * Parse untagged template literal as string concatenation.
4953 */
4954 private Expression templateLiteral() {
4955 assert type == TEMPLATE || type == TEMPLATE_HEAD;
4956 final boolean noSubstitutionTemplate = type == TEMPLATE;
4957 long lastLiteralToken = token;
4958 LiteralNode<?> literal = getLiteral();
4959 if (noSubstitutionTemplate) {
4960 return literal;
4961 }
4962
4963 Expression concat = literal;
4964 TokenType lastLiteralType;
4965 do {
4966 final Expression expression = expression();
4967 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) {
4968 throw error(AbstractParser.message("unterminated.template.expression"), token);
4969 }
4970 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, expression);
4971 lastLiteralType = type;
4972 lastLiteralToken = token;
4973 literal = getLiteral();
4974 concat = new BinaryNode(Token.recast(lastLiteralToken, TokenType.ADD), concat, literal);
4975 } while (lastLiteralType == TEMPLATE_MIDDLE);
4976 return concat;
4977 }
4978
4979 /**
4980 * Parse tagged template literal as argument list.
4981 * @return argument list for a tag function call (template object, ...substitutions)
4982 */
4983 private List<Expression> templateLiteralArgumentList() {
4984 assert type == TEMPLATE || type == TEMPLATE_HEAD;
4985 final ArrayList<Expression> argumentList = new ArrayList<>();
4986 final ArrayList<Expression> rawStrings = new ArrayList<>();
4987 final ArrayList<Expression> cookedStrings = new ArrayList<>();
4988 argumentList.add(null); // filled at the end
4989
4990 final long templateToken = token;
4991 final boolean hasSubstitutions = type == TEMPLATE_HEAD;
4992 addTemplateLiteralString(rawStrings, cookedStrings);
4993
4994 if (hasSubstitutions) {
4995 TokenType lastLiteralType;
4996 do {
4997 final Expression expression = expression();
4998 if (type != TEMPLATE_MIDDLE && type != TEMPLATE_TAIL) {
4999 throw error(AbstractParser.message("unterminated.template.expression"), token);
5000 }
5001 argumentList.add(expression);
5002
5003 lastLiteralType = type;
5004 addTemplateLiteralString(rawStrings, cookedStrings);
5005 } while (lastLiteralType == TEMPLATE_MIDDLE);
5006 }
5007
5008 final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings);
5009 final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings);
5010 final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
5011 argumentList.set(0, templateObject);
5012 return optimizeList(argumentList);
5013 }
5014
5015 private void addTemplateLiteralString(final ArrayList<Expression> rawStrings, final ArrayList<Expression> cookedStrings) {
5016 final long stringToken = token;
5017 final String rawString = lexer.valueOfRawString(stringToken);
5018 final String cookedString = (String) getValue();
5019 next();
5020 rawStrings.add(LiteralNode.newInstance(stringToken, finish, rawString));
5021 cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString));
5022 }
5023
5024
5025 /**
5026 * Parse a module.
5027 *
5028 * Module :
5029 * ModuleBody?
5030 *
5031 * ModuleBody :
5032 * ModuleItemList
5033 */
5034 private FunctionNode module(final String moduleName) {
5035 boolean oldStrictMode = isStrictMode;
5036 try {
5037 isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1)
5038
5039 // Make a pseudo-token for the script holding its start and length.
5040 int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish);
5041 final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart);
5042 final int functionLine = line;
5043
5044 final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName);
5045 final ParserContextFunctionNode script = createParserContextFunctionNode(
5046 ident,
5047 functionToken,
5048 FunctionNode.Kind.MODULE,
5049 functionLine,
5050 Collections.<IdentNode>emptyList());
5051 lc.push(script);
5052
5053 final ParserContextModuleNode module = new ParserContextModuleNode(moduleName);
5054 lc.push(module);
5055
5056 final ParserContextBlockNode body = newBlock();
5057
5058 functionDeclarations = new ArrayList<>();
5059 moduleBody();
5060 addFunctionDeclarations(script);
5061 functionDeclarations = null;
5062
5063 restoreBlock(body);
5064 body.setFlag(Block.NEEDS_SCOPE);
5065 final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
5066 lc.pop(module);
5067 lc.pop(script);
5068 script.setLastToken(token);
5069
5070 expect(EOF);
5071
5072 script.setModule(module.createModule());
5073 return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody);
5074 } finally {
5075 isStrictMode = oldStrictMode;
5076 }
5077 }
5078
5079 /**
5080 * Parse module body.
5081 *
5082 * ModuleBody :
5083 * ModuleItemList
5084 *
5085 * ModuleItemList :
5086 * ModuleItem
5087 * ModuleItemList ModuleItem
5088 *
5089 * ModuleItem :
5090 * ImportDeclaration
5091 * ExportDeclaration
5092 * StatementListItem
5093 */
5094 private void moduleBody() {
5095 loop:
5096 while (type != EOF) {
5097 switch (type) {
5098 case EOF:
5099 break loop;
5100 case IMPORT:
5101 importDeclaration();
5102 break;
5103 case EXPORT:
5104 exportDeclaration();
5105 break;
5106 default:
5107 // StatementListItem
5108 statement(true, false, false, false);
5109 break;
5110 }
5111 }
5112 }
5113
5114
5115 /**
5116 * Parse import declaration.
5117 *
5118 * ImportDeclaration :
5119 * import ImportClause FromClause ;
5120 * import ModuleSpecifier ;
5121 * ImportClause :
5122 * ImportedDefaultBinding
5123 * NameSpaceImport
5124 * NamedImports
5125 * ImportedDefaultBinding , NameSpaceImport
5126 * ImportedDefaultBinding , NamedImports
5127 * ImportedDefaultBinding :
5128 * ImportedBinding
5129 * ModuleSpecifier :
5130 * StringLiteral
5131 * ImportedBinding :
5132 * BindingIdentifier
5133 */
5134 private void importDeclaration() {
5135 expect(IMPORT);
5136 final ParserContextModuleNode module = lc.getCurrentModule();
5137 if (type == STRING || type == ESCSTRING) {
5138 // import ModuleSpecifier ;
5139 final String moduleSpecifier = (String) getValue();
5140 next();
5141 module.addModuleRequest(moduleSpecifier);
5142 } else {
5143 // import ImportClause FromClause ;
5144 List<Module.ImportEntry> importEntries;
5145 if (type == MUL) {
5146 importEntries = Collections.singletonList(nameSpaceImport());
5147 } else if (type == LBRACE) {
5148 importEntries = namedImports();
5149 } else if (isBindingIdentifier()) {
5150 // ImportedDefaultBinding
5151 final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding");
5152 Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName());
5153
5154 if (type == COMMARIGHT) {
5155 next();
5156 importEntries = new ArrayList<>();
5157 if (type == MUL) {
5158 importEntries.add(nameSpaceImport());
5159 } else if (type == LBRACE) {
5160 importEntries.addAll(namedImports());
5161 } else {
5162 throw error(AbstractParser.message("expected.named.import"));
5163 }
5164 } else {
5165 importEntries = Collections.singletonList(defaultImport);
5166 }
5167 } else {
5168 throw error(AbstractParser.message("expected.import"));
5169 }
5170
5171 final String moduleSpecifier = fromClause();
5172 module.addModuleRequest(moduleSpecifier);
5173 for (int i = 0; i < importEntries.size(); i++) {
5174 module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier));
5175 }
5176 }
5177 expect(SEMICOLON);
5178 }
5179
5180 /**
5181 * NameSpaceImport :
5182 * * as ImportedBinding
5183 *
5184 * @return imported binding identifier
5185 */
5186 private Module.ImportEntry nameSpaceImport() {
5187 assert type == MUL;
5188 next();
5189 final long asToken = token;
5190 final String as = (String) expectValue(IDENT);
5191 if (!"as".equals(as)) {
5192 throw error(AbstractParser.message("expected.as"), asToken);
5193 }
5194 final IdentNode localNameSpace = bindingIdentifier("ImportedBinding");
5195 return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName());
5196 }
5197
5198 /**
5199 * NamedImports :
5200 * { }
5201 * { ImportsList }
5202 * { ImportsList , }
5203 * ImportsList :
5204 * ImportSpecifier
5205 * ImportsList , ImportSpecifier
5206 * ImportSpecifier :
5207 * ImportedBinding
5208 * IdentifierName as ImportedBinding
5209 * ImportedBinding :
5210 * BindingIdentifier
5211 */
5212 private List<Module.ImportEntry> namedImports() {
5213 assert type == LBRACE;
5214 next();
5215 List<Module.ImportEntry> importEntries = new ArrayList<>();
5216 while (type != RBRACE) {
5217 final boolean bindingIdentifier = isBindingIdentifier();
5218 final long nameToken = token;
5219 final IdentNode importName = getIdentifierName();
5220 if (type == IDENT && "as".equals(getValue())) {
5221 next();
5222 final IdentNode localName = bindingIdentifier("ImportedBinding");
5223 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName()));
5224 } else if (!bindingIdentifier) {
5225 throw error(AbstractParser.message("expected.binding.identifier"), nameToken);
5226 } else {
5227 importEntries.add(Module.ImportEntry.importSpecifier(importName.getName()));
5228 }
5229 if (type == COMMARIGHT) {
5230 next();
5231 } else {
5232 break;
5233 }
5234 }
5235 expect(RBRACE);
5236 return importEntries;
5237 }
5238
5239 /**
5240 * FromClause :
5241 * from ModuleSpecifier
5242 */
5243 private String fromClause() {
5244 final long fromToken = token;
5245 final String name = (String) expectValue(IDENT);
5246 if (!"from".equals(name)) {
5247 throw error(AbstractParser.message("expected.from"), fromToken);
5248 }
5249 if (type == STRING || type == ESCSTRING) {
5250 final String moduleSpecifier = (String) getValue();
5251 next();
5252 return moduleSpecifier;
5253 } else {
5254 throw error(expectMessage(STRING));
5255 }
5256 }
5257
5258 /**
5259 * Parse export declaration.
5260 *
5261 * ExportDeclaration :
5262 * export * FromClause ;
5263 * export ExportClause FromClause ;
5264 * export ExportClause ;
5265 * export VariableStatement
5266 * export Declaration
5267 * export default HoistableDeclaration[Default]
5268 * export default ClassDeclaration[Default]
5269 * export default [lookahead !in {function, class}] AssignmentExpression[In] ;
5270 */
5271 private void exportDeclaration() {
5272 expect(EXPORT);
5273 final ParserContextModuleNode module = lc.getCurrentModule();
5274 switch (type) {
5275 case MUL: {
5276 next();
5277 final String moduleRequest = fromClause();
5278 expect(SEMICOLON);
5279 module.addModuleRequest(moduleRequest);
5280 module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest));
5281 break;
5282 }
5283 case LBRACE: {
5284 final List<Module.ExportEntry> exportEntries = exportClause();
5285 if (type == IDENT && "from".equals(getValue())) {
5286 final String moduleRequest = fromClause();
5287 module.addModuleRequest(moduleRequest);
5288 for (Module.ExportEntry exportEntry : exportEntries) {
5289 module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest));
5290 }
5291 } else {
5292 for (Module.ExportEntry exportEntry : exportEntries) {
5293 module.addLocalExportEntry(exportEntry);
5294 }
5295 }
5296 expect(SEMICOLON);
5297 break;
5298 }
5299 case DEFAULT:
5300 next();
5301 final Expression assignmentExpression;
5302 IdentNode ident;
5303 final int lineNumber = line;
5304 final long rhsToken = token;
5305 final boolean declaration;
5306 switch (type) {
5307 case FUNCTION:
5308 assignmentExpression = functionExpression(false, true);
5309 ident = ((FunctionNode) assignmentExpression).getIdent();
5310 declaration = true;
5311 break;
5312 case CLASS:
5313 assignmentExpression = classDeclaration(true);
5314 ident = ((ClassNode) assignmentExpression).getIdent();
5315 declaration = true;
5316 break;
5317 default:
5318 assignmentExpression = assignmentExpression(false);
5319 ident = null;
5320 declaration = false;
5321 break;
5322 }
5323 if (ident != null) {
5324 module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName()));
5325 } else {
5326 ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME);
5327 lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression));
5328 if (!declaration) {
5329 expect(SEMICOLON);
5330 }
5331 module.addLocalExportEntry(Module.ExportEntry.exportDefault());
5332 }
5333 break;
5334 case VAR:
5335 case LET:
5336 case CONST:
5337 final List<Statement> statements = lc.getCurrentBlock().getStatements();
5338 final int previousEnd = statements.size();
5339 variableStatement(type);
5340 for (final Statement statement : statements.subList(previousEnd, statements.size())) {
5341 if (statement instanceof VarNode) {
5342 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName()));
5343 }
5344 }
5345 break;
5346 case CLASS: {
5347 final ClassNode classDeclaration = classDeclaration(false);
5348 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName()));
5349 break;
5350 }
5351 case FUNCTION: {
5352 final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true);
5353 module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName()));
5354 break;
5355 }
5356 default:
5357 throw error(AbstractParser.message("invalid.export"), token);
5358 }
5359 }
5360
5361 /**
5362 * ExportClause :
5363 * { }
5364 * { ExportsList }
5365 * { ExportsList , }
5366 * ExportsList :
5367 * ExportSpecifier
5368 * ExportsList , ExportSpecifier
5369 * ExportSpecifier :
5370 * IdentifierName
5371 * IdentifierName as IdentifierName
5372 *
5373 * @return a list of ExportSpecifiers
5374 */
5375 private List<Module.ExportEntry> exportClause() {
5376 assert type == LBRACE;
5377 next();
5378 List<Module.ExportEntry> exports = new ArrayList<>();
5379 while (type != RBRACE) {
5380 final IdentNode localName = getIdentifierName();
5381 if (type == IDENT && "as".equals(getValue())) {
5382 next();
5383 final IdentNode exportName = getIdentifierName();
5384 exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName()));
5385 } else {
5386 exports.add(Module.ExportEntry.exportSpecifier(localName.getName()));
5387 }
5388 if (type == COMMARIGHT) {
5389 next();
5390 } else {
5391 break;
5392 }
5393 }
5394 expect(RBRACE);
5395 return exports;
5396 }
5397
5398 @Override
5399 public String toString() {
5400 return "'JavaScript Parsing'";
5401 }
5402
5403 private static void markEval(final ParserContext lc) {
5404 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5405 boolean flaggedCurrentFn = false;
5406 while (iter.hasNext()) {
5407 final ParserContextFunctionNode fn = iter.next();
5408 if (!flaggedCurrentFn) {
5409 fn.setFlag(FunctionNode.HAS_EVAL);
5410 flaggedCurrentFn = true;
5411 if (fn.getKind() == FunctionNode.Kind.ARROW) {
5412 // possible use of this in an eval that's nested in an arrow function, e.g.:
5413 // function fun(){ return (() => eval("this"))(); };
5414 markThis(lc);
5415 markNewTarget(lc);
5416 }
5417 } else {
5418 fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
5419 }
5420 final ParserContextBlockNode body = lc.getFunctionBody(fn);
5421 // NOTE: it is crucial to mark the body of the outer function as needing scope even when we skip
5422 // parsing a nested function. functionBody() contains code to compensate for the lack of invoking
5423 // this method when the parser skips a nested function.
5424 body.setFlag(Block.NEEDS_SCOPE);
5425 fn.setFlag(FunctionNode.HAS_SCOPE_BLOCK);
5426 }
5427 }
5428
5429 private void prependStatement(final Statement statement) {
5430 lc.prependStatementToCurrentNode(statement);
5431 }
5432
5433 private void appendStatement(final Statement statement) {
5434 lc.appendStatementToCurrentNode(statement);
5435 }
5436
5437 private static void markSuperCall(final ParserContext lc) {
5438 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5439 while (iter.hasNext()) {
5440 final ParserContextFunctionNode fn = iter.next();
5441 if (fn.getKind() != FunctionNode.Kind.ARROW) {
5442 assert fn.isSubclassConstructor();
5443 fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
5444 break;
5445 }
5446 }
5447 }
5448
5449 private ParserContextFunctionNode getCurrentNonArrowFunction() {
5450 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5451 while (iter.hasNext()) {
5452 final ParserContextFunctionNode fn = iter.next();
5453 if (fn.getKind() != FunctionNode.Kind.ARROW) {
5454 return fn;
5455 }
5456 }
5457 return null;
5458 }
5459
5460 private static void markThis(final ParserContext lc) {
5461 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5462 while (iter.hasNext()) {
5463 final ParserContextFunctionNode fn = iter.next();
5464 fn.setFlag(FunctionNode.USES_THIS);
5465 if (fn.getKind() != FunctionNode.Kind.ARROW) {
5466 break;
5467 }
5468 }
5469 }
5470
5471 private static void markNewTarget(final ParserContext lc) {
5472 final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
5473 while (iter.hasNext()) {
5474 final ParserContextFunctionNode fn = iter.next();
5475 if (fn.getKind() != FunctionNode.Kind.ARROW) {
5476 if (!fn.isProgram()) {
5477 fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET);
5478 }
5479 break;
5480 }
5481 }
5482 }
5483
5484 private boolean inGeneratorFunction() {
5485 return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR;
5486 }
5487 }
--- EOF ---