src/jdk/nashorn/internal/parser/Parser.java

changeset 211
3a209cbd1d8f
parent 144
4be452026847
child 227
7917ef020898
equal deleted inserted replaced
210:c8460f668d0c 211:3a209cbd1d8f
52 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON; 52 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
53 import static jdk.nashorn.internal.parser.TokenType.TERNARY; 53 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
54 import static jdk.nashorn.internal.parser.TokenType.WHILE; 54 import static jdk.nashorn.internal.parser.TokenType.WHILE;
55 55
56 import java.util.ArrayList; 56 import java.util.ArrayList;
57 import java.util.HashMap;
58 import java.util.HashSet; 57 import java.util.HashSet;
59 import java.util.Iterator; 58 import java.util.Iterator;
59 import java.util.LinkedHashMap;
60 import java.util.List; 60 import java.util.List;
61 import java.util.Map; 61 import java.util.Map;
62 import java.util.Stack;
63 import jdk.nashorn.internal.codegen.CompilerConstants; 62 import jdk.nashorn.internal.codegen.CompilerConstants;
64 import jdk.nashorn.internal.codegen.Namespace; 63 import jdk.nashorn.internal.codegen.Namespace;
65 import jdk.nashorn.internal.ir.AccessNode; 64 import jdk.nashorn.internal.ir.AccessNode;
66 import jdk.nashorn.internal.ir.BinaryNode; 65 import jdk.nashorn.internal.ir.BinaryNode;
67 import jdk.nashorn.internal.ir.Block; 66 import jdk.nashorn.internal.ir.Block;
67 import jdk.nashorn.internal.ir.BlockLexicalContext;
68 import jdk.nashorn.internal.ir.BreakNode; 68 import jdk.nashorn.internal.ir.BreakNode;
69 import jdk.nashorn.internal.ir.BreakableNode; 69 import jdk.nashorn.internal.ir.BreakableNode;
70 import jdk.nashorn.internal.ir.CallNode; 70 import jdk.nashorn.internal.ir.CallNode;
71 import jdk.nashorn.internal.ir.CaseNode; 71 import jdk.nashorn.internal.ir.CaseNode;
72 import jdk.nashorn.internal.ir.CatchNode; 72 import jdk.nashorn.internal.ir.CatchNode;
73 import jdk.nashorn.internal.ir.ContinueNode; 73 import jdk.nashorn.internal.ir.ContinueNode;
74 import jdk.nashorn.internal.ir.DoWhileNode;
75 import jdk.nashorn.internal.ir.EmptyNode; 74 import jdk.nashorn.internal.ir.EmptyNode;
76 import jdk.nashorn.internal.ir.ExecuteNode; 75 import jdk.nashorn.internal.ir.ExecuteNode;
77 import jdk.nashorn.internal.ir.ForNode; 76 import jdk.nashorn.internal.ir.ForNode;
78 import jdk.nashorn.internal.ir.FunctionNode; 77 import jdk.nashorn.internal.ir.FunctionNode;
79 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 78 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
82 import jdk.nashorn.internal.ir.IndexNode; 81 import jdk.nashorn.internal.ir.IndexNode;
83 import jdk.nashorn.internal.ir.LabelNode; 82 import jdk.nashorn.internal.ir.LabelNode;
84 import jdk.nashorn.internal.ir.LexicalContext; 83 import jdk.nashorn.internal.ir.LexicalContext;
85 import jdk.nashorn.internal.ir.LineNumberNode; 84 import jdk.nashorn.internal.ir.LineNumberNode;
86 import jdk.nashorn.internal.ir.LiteralNode; 85 import jdk.nashorn.internal.ir.LiteralNode;
86 import jdk.nashorn.internal.ir.LoopNode;
87 import jdk.nashorn.internal.ir.Node; 87 import jdk.nashorn.internal.ir.Node;
88 import jdk.nashorn.internal.ir.ObjectNode; 88 import jdk.nashorn.internal.ir.ObjectNode;
89 import jdk.nashorn.internal.ir.PropertyKey; 89 import jdk.nashorn.internal.ir.PropertyKey;
90 import jdk.nashorn.internal.ir.PropertyNode; 90 import jdk.nashorn.internal.ir.PropertyNode;
91 import jdk.nashorn.internal.ir.ReturnNode; 91 import jdk.nashorn.internal.ir.ReturnNode;
115 private final ScriptEnvironment env; 115 private final ScriptEnvironment env;
116 116
117 /** Is scripting mode. */ 117 /** Is scripting mode. */
118 private final boolean scripting; 118 private final boolean scripting;
119 119
120 private final LexicalContext lexicalContext = new LexicalContext();
121 private List<Node> functionDeclarations; 120 private List<Node> functionDeclarations;
121
122 private final BlockLexicalContext lc = new BlockLexicalContext();
122 123
123 /** Namespace for function names where not explicitly given */ 124 /** Namespace for function names where not explicitly given */
124 private final Namespace namespace; 125 private final Namespace namespace;
125 126
126 private static final DebugLogger LOG = new DebugLogger("parser"); 127 private static final DebugLogger LOG = new DebugLogger("parser");
144 * @param errors error manager 145 * @param errors error manager
145 * @param strict parser created with strict mode enabled. 146 * @param strict parser created with strict mode enabled.
146 */ 147 */
147 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) { 148 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) {
148 super(source, errors, strict); 149 super(source, errors, strict);
149 this.env = env; 150 this.env = env;
150 this.namespace = new Namespace(env.getNamespace()); 151 this.namespace = new Namespace(env.getNamespace());
151 this.scripting = env._scripting; 152 this.scripting = env._scripting;
152 } 153 }
153 154
154 /** 155 /**
160 * "runScript" {@link CompilerConstants#RUN_SCRIPT} 161 * "runScript" {@link CompilerConstants#RUN_SCRIPT}
161 * 162 *
162 * @return function node resulting from successful parse 163 * @return function node resulting from successful parse
163 */ 164 */
164 public FunctionNode parse() { 165 public FunctionNode parse() {
165 return parse(RUN_SCRIPT.tag()); 166 return parse(RUN_SCRIPT.symbolName());
166 } 167 }
167 168
168 /** 169 /**
169 * Execute parse and return the resulting function node. 170 * Execute parse and return the resulting function node.
170 * Errors will be thrown and the error manager will contain information 171 * Errors will be thrown and the error manager will contain information
174 * 175 *
175 * @return function node resulting from successful parse 176 * @return function node resulting from successful parse
176 */ 177 */
177 public FunctionNode parse(final String scriptName) { 178 public FunctionNode parse(final String scriptName) {
178 final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L; 179 final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L;
179 LOG.info(this + " begin for '" + scriptName + "'"); 180 LOG.info(this, " begin for '", scriptName, "'");
180 181
181 try { 182 try {
182 stream = new TokenStream(); 183 stream = new TokenStream();
183 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions); 184 lexer = new Lexer(source, stream, scripting && !env._no_syntax_extensions);
184 185
212 return null; 213 return null;
213 } finally { 214 } finally {
214 final String end = this + " end '" + scriptName + "'"; 215 final String end = this + " end '" + scriptName + "'";
215 if (Timing.isEnabled()) { 216 if (Timing.isEnabled()) {
216 Timing.accumulateTime(toString(), System.currentTimeMillis() - t0); 217 Timing.accumulateTime(toString(), System.currentTimeMillis() - t0);
217 LOG.info(end + "' in " + (System.currentTimeMillis() - t0) + " ms"); 218 LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms");
218 } else { 219 } else {
219 LOG.info(end); 220 LOG.info(end);
220 } 221 }
221 } 222 }
222 } 223 }
273 * 274 *
274 * @return New block. 275 * @return New block.
275 */ 276 */
276 private Block newBlock() { 277 private Block newBlock() {
277 final Block block = new Block(source, token, Token.descPosition(token)); 278 final Block block = new Block(source, token, Token.descPosition(token));
278 lexicalContext.push(block); 279 return lc.push(block);
279 return block;
280 } 280 }
281 281
282 /** 282 /**
283 * Set up a new function block. 283 * Set up a new function block.
284 * 284 *
285 * @param ident Name of function. 285 * @param ident Name of function.
286 * @return New block. 286 * @return New block.
287 */ 287 */
288 private FunctionNode newFunctionBlock(final IdentNode ident) { 288 private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
289 // Build function name. 289 // Build function name.
290 final StringBuilder sb = new StringBuilder(); 290 final StringBuilder sb = new StringBuilder();
291 291
292 final FunctionNode parentFunction = getFunction(); 292 final FunctionNode parentFunction = lc.getCurrentFunction();
293 if(parentFunction != null && !parentFunction.isProgram()) { 293 if (parentFunction != null && !parentFunction.isProgram()) {
294 sb.append(parentFunction.getName()).append('$'); 294 sb.append(parentFunction.getName()).append('$');
295 } 295 }
296 296
297 sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag()); 297 sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName());
298 final String name = namespace.uniqueName(sb.toString()); 298 final String name = namespace.uniqueName(sb.toString());
299 assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). 299 assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName()) : "name = " + name;// must not rename runScript().
300
301 int flags = 0;
302 if (parentFunction == null) {
303 flags |= FunctionNode.IS_PROGRAM;
304 }
305 if (isStrictMode) {
306 flags |= FunctionNode.IS_STRICT;
307 }
300 308
301 // Start new block. 309 // Start new block.
302 final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name); 310 FunctionNode functionNode =
303 if(parentFunction == null) { 311 new FunctionNode(
304 functionBlock.setProgram(); 312 source,
305 } 313 token,
306 functionBlock.setStrictMode(isStrictMode); 314 Token.descPosition(token),
307 functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 315 startToken,
308 lexicalContext.push(functionBlock); 316 namespace,
309 317 ident,
310 return functionBlock; 318 name,
319 parameters,
320 kind,
321 flags);
322
323 functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
324 lc.push(functionNode);
325 // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
326 // FunctionNode.
327 newBlock();
328 return functionNode;
311 } 329 }
312 330
313 /** 331 /**
314 * Restore the current block. 332 * Restore the current block.
315 */ 333 */
316 private void restoreBlock(Block block) { 334 private Block restoreBlock(final Block block) {
317 lexicalContext.pop(block); 335 return lc.pop(block);//.setFlag(lc, flags);
336 }
337
338 private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) {
339 final Block newBody = restoreBlock(lc.getFunctionBody(functionNode));
340
341 return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken);
318 } 342 }
319 343
320 /** 344 /**
321 * Get the statements in a block. 345 * Get the statements in a block.
322 * @return Block statements. 346 * @return Block statements.
323 */ 347 */
324 private Block getBlock(final boolean needsBraces) { 348 private Block getBlock(final boolean needsBraces) {
325 // Set up new block. Captures LBRACE. 349 // Set up new block. Captures LBRACE.
326 final Block newBlock = newBlock(); 350 Block newBlock = newBlock();
327 try { 351 try {
328 pushControlNode(newBlock);
329
330 // Block opening brace. 352 // Block opening brace.
331 if (needsBraces) { 353 if (needsBraces) {
332 expect(LBRACE); 354 expect(LBRACE);
333 } 355 }
334 356 // Accumulate block statements.
335 try { 357 statementList();
336 // Accumulate block statements. 358
337 statementList();
338 } finally {
339 popControlNode();
340 }
341 } finally { 359 } finally {
342 restoreBlock(newBlock); 360 newBlock = restoreBlock(newBlock);
343 } 361 }
344 362
345 final int possibleEnd = Token.descPosition(token) + Token.descLength(token); 363 final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
346 364
347 // Block closing brace. 365 // Block closing brace.
361 private Block getStatement() { 379 private Block getStatement() {
362 if (type == LBRACE) { 380 if (type == LBRACE) {
363 return getBlock(true); 381 return getBlock(true);
364 } 382 }
365 // Set up new block. Captures first token. 383 // Set up new block. Captures first token.
366 final Block newBlock = newBlock(); 384 Block newBlock = newBlock();
367
368 try { 385 try {
369 // Accumulate statements.
370 statement(); 386 statement();
371 } finally { 387 } finally {
372 restoreBlock(newBlock); 388 newBlock = restoreBlock(newBlock);
373 } 389 }
374
375 return newBlock; 390 return newBlock;
376 } 391 }
377 392
378 /** 393 /**
379 * Detect calls to special functions. 394 * Detect calls to special functions.
380 * @param ident Called function. 395 * @param ident Called function.
381 */ 396 */
382 private void detectSpecialFunction(final IdentNode ident) { 397 private void detectSpecialFunction(final IdentNode ident) {
383 final String name = ident.getName(); 398 final String name = ident.getName();
384 399
385 if (EVAL.tag().equals(name)) { 400 if (EVAL.symbolName().equals(name)) {
386 final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 401 markWithOrEval(lc, FunctionNode.HAS_EVAL);
387 if(it.hasNext()) {
388 it.next().setHasEval(it);
389 }
390 } 402 }
391 } 403 }
392 404
393 /** 405 /**
394 * Detect use of special properties. 406 * Detect use of special properties.
395 * @param ident Referenced property. 407 * @param ident Referenced property.
396 */ 408 */
397 private void detectSpecialProperty(final IdentNode ident) { 409 private void detectSpecialProperty(final IdentNode ident) {
398 final String name = ident.getName(); 410 final String name = ident.getName();
399 411
400 if (ARGUMENTS.tag().equals(name)) { 412 if (ARGUMENTS.symbolName().equals(name)) {
401 getFunction().setUsesArguments(); 413 lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS);
402 } 414 }
403 } 415 }
404 416
405 /** 417 /**
406 * Tells whether a IdentNode can be used as L-value of an assignment 418 * Tells whether a IdentNode can be used as L-value of an assignment
437 case ASSIGN_SUB: 449 case ASSIGN_SUB:
438 if (!(lhs instanceof AccessNode || 450 if (!(lhs instanceof AccessNode ||
439 lhs instanceof IndexNode || 451 lhs instanceof IndexNode ||
440 lhs instanceof IdentNode)) { 452 lhs instanceof IdentNode)) {
441 if (env._early_lvalue_error) { 453 if (env._early_lvalue_error) {
442 error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 454 throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken());
443 } 455 }
444 return referenceError(lhs, rhs); 456 return referenceError(lhs, rhs);
445 } 457 }
446 458
447 if (lhs instanceof IdentNode) { 459 if (lhs instanceof IdentNode) {
467 * @param expression Left hand side expression. 479 * @param expression Left hand side expression.
468 * @param isPostfix Prefix or postfix. 480 * @param isPostfix Prefix or postfix.
469 * @return Reduced expression. 481 * @return Reduced expression.
470 */ 482 */
471 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { 483 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) {
472 long incDecToken = firstToken;
473 if (isPostfix) { 484 if (isPostfix) {
474 incDecToken = Token.recast(incDecToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX); 485 return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression);
475 } 486 }
476 487
477 final UnaryNode node = new UnaryNode(source, incDecToken, expression); 488 return new UnaryNode(source, firstToken, expression);
478 if (isPostfix) { 489 }
479 node.setStart(expression.getStart());
480 node.setFinish(Token.descPosition(incDecToken) + Token.descLength(incDecToken));
481 }
482
483 return node;
484 }
485
486 /**
487 * Find a label node in the label stack.
488 * @param ident Ident to find.
489 * @return null or the found label node.
490 */
491 private LabelNode findLabel(final IdentNode ident) {
492 for (final LabelNode labelNode : getFunction().getLabelStack()) {
493 if (labelNode.getLabel().equals(ident)) {
494 return labelNode;
495 }
496 }
497
498 return null;
499 }
500
501 /**
502 * Add a label to the label stack.
503 * @param labelNode Label to add.
504 */
505 private void pushLabel(final LabelNode labelNode) {
506 getFunction().getLabelStack().push(labelNode);
507 }
508
509 /**
510 * Remove a label from the label stack.
511 */
512 private void popLabel() {
513 getFunction().getLabelStack().pop();
514 }
515
516 /**
517 * Track the current nesting of controls for break and continue.
518 * @param node For, while, do or switch node.
519 */
520 private void pushControlNode(final Node node) {
521 final boolean isLoop = node instanceof WhileNode;
522 final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
523 final FunctionNode function = getFunction();
524 function.getControlStack().push(node);
525
526 for (final LabelNode labelNode : function.getLabelStack()) {
527 if (isBreakable && labelNode.getBreakNode() == null) {
528 labelNode.setBreakNode(node);
529 }
530
531 if (isLoop && labelNode.getContinueNode() == null) {
532 labelNode.setContinueNode(node);
533 }
534 }
535 }
536
537 /**
538 * Finish with control.
539 */
540 private void popControlNode() {
541 // Get control stack.
542 final Stack<Node> controlStack = getFunction().getControlStack();
543
544 // Can be empty if missing brace.
545 if (!controlStack.isEmpty()) {
546 controlStack.pop();
547 }
548 }
549
550 private void popControlNode(final Node node) {
551 // Get control stack.
552 final Stack<Node> controlStack = getFunction().getControlStack();
553
554 // Can be empty if missing brace.
555 if (!controlStack.isEmpty() && controlStack.peek() == node) {
556 controlStack.pop();
557 }
558 }
559
560 private boolean isInWithBlock() {
561 final Stack<Node> controlStack = getFunction().getControlStack();
562 for (int i = controlStack.size() - 1; i >= 0; i--) {
563 final Node node = controlStack.get(i);
564
565 if (node instanceof WithNode) {
566 return true;
567 }
568 }
569
570 return false;
571 }
572
573 private <T extends Node> T findControl(final Class<T> ctype) {
574 final Stack<Node> controlStack = getFunction().getControlStack();
575 for (int i = controlStack.size() - 1; i >= 0; i--) {
576 final Node node = controlStack.get(i);
577
578 if (ctype.isAssignableFrom(node.getClass())) {
579 return ctype.cast(node);
580 }
581 }
582
583 return null;
584 }
585
586 private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
587 final List<T> nodes = new ArrayList<>();
588 final Stack<Node> controlStack = getFunction().getControlStack();
589 for (int i = controlStack.size() - 1; i >= 0; i--) {
590 final Node node = controlStack.get(i);
591
592 if (to == node) {
593 break; //stop looking
594 }
595
596 if (ctype.isAssignableFrom(node.getClass())) {
597 nodes.add(ctype.cast(node));
598 }
599 }
600
601 return nodes;
602 }
603
604 private <T extends Node> int countControls(final Class<T> ctype, final Node to) {
605 return findControls(ctype, to).size();
606 }
607
608 490
609 /** 491 /**
610 * ----------------------------------------------------------------------- 492 * -----------------------------------------------------------------------
611 * 493 *
612 * Grammar based on 494 * Grammar based on
628 private FunctionNode program(final String scriptName) { 510 private FunctionNode program(final String scriptName) {
629 // Make a fake token for the script. 511 // Make a fake token for the script.
630 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 512 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
631 // Set up the script to append elements. 513 // Set up the script to append elements.
632 514
633 final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName)); 515 FunctionNode script = newFunctionNode(
634 516 functionToken,
635 script.setKind(FunctionNode.Kind.SCRIPT); 517 new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName),
636 script.setFirstToken(functionToken); 518 new ArrayList<IdentNode>(),
519 FunctionNode.Kind.SCRIPT);
520
637 functionDeclarations = new ArrayList<>(); 521 functionDeclarations = new ArrayList<>();
638 sourceElements(); 522 sourceElements();
639 script.prependStatements(functionDeclarations); 523 addFunctionDeclarations(script);
640 functionDeclarations = null; 524 functionDeclarations = null;
525
641 expect(EOF); 526 expect(EOF);
642 script.setLastToken(token); 527
643 script.setFinish(source.getLength() - 1); 528 script.setFinish(source.getLength() - 1);
644 529
530 script = restoreFunctionNode(script, token); //commit code
531 script = script.setBody(lc, script.getBody().setNeedsScope(lc));
645 return script; 532 return script;
646 } 533 }
647 534
648 /** 535 /**
649 * Directive value or null if statement is not a directive. 536 * Directive value or null if statement is not a directive.
668 555
669 return null; 556 return null;
670 } 557 }
671 558
672 /** 559 /**
673 * Return last node in a statement list.
674 *
675 * @param statements Statement list.
676 *
677 * @return Last (non-debug) statement or null if empty block.
678 */
679 private static Node lastStatement(final List<Node> statements) {
680 for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) {
681 final Node node = statements.get(lastIndex);
682 if (!node.isDebug()) {
683 return node;
684 }
685 }
686
687 return null;
688 }
689
690 /**
691 * SourceElements : 560 * SourceElements :
692 * SourceElement 561 * SourceElement
693 * SourceElements SourceElement 562 * SourceElements SourceElement
694 * 563 *
695 * See 14 564 * See 14
714 statement(true); 583 statement(true);
715 584
716 // check for directive prologues 585 // check for directive prologues
717 if (checkDirective) { 586 if (checkDirective) {
718 // skip any debug statement like line number to get actual first line 587 // skip any debug statement like line number to get actual first line
719 final Node lastStatement = lastStatement(getBlock().getStatements()); 588 final Node lastStatement = lc.getLastStatement();
720 589
721 // get directive prologue, if any 590 // get directive prologue, if any
722 final String directive = getDirective(lastStatement); 591 final String directive = getDirective(lastStatement);
723 592
724 // If we have seen first non-directive statement, 593 // If we have seen first non-directive statement,
734 } 603 }
735 604
736 // handle use strict directive 605 // handle use strict directive
737 if ("use strict".equals(directive)) { 606 if ("use strict".equals(directive)) {
738 isStrictMode = true; 607 isStrictMode = true;
739 final FunctionNode function = getFunction(); 608 final FunctionNode function = lc.getCurrentFunction();
740 function.setStrictMode(true); 609 lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT);
741 610
742 // We don't need to check these, if lexical environment is already strict 611 // We don't need to check these, if lexical environment is already strict
743 if (!oldStrictMode && directiveStmts != null) { 612 if (!oldStrictMode && directiveStmts != null) {
744 // check that directives preceding this one do not violate strictness 613 // check that directives preceding this one do not violate strictness
745 for (final Node statement : directiveStmts) { 614 for (final Node statement : directiveStmts) {
757 } 626 }
758 } 627 }
759 } 628 }
760 } 629 }
761 } catch (final Exception e) { 630 } catch (final Exception e) {
762 // Recover parsing. 631 //recover parsing
763 recover(e); 632 recover(e);
764 } 633 }
765 634
766 // No backtracking from here on. 635 // No backtracking from here on.
767 stream.commit(k); 636 stream.commit(k);
805 674
806 if (type == FUNCTION) { 675 if (type == FUNCTION) {
807 // As per spec (ECMA section 12), function declarations as arbitrary statement 676 // As per spec (ECMA section 12), function declarations as arbitrary statement
808 // is not "portable". Implementation can issue a warning or disallow the same. 677 // is not "portable". Implementation can issue a warning or disallow the same.
809 if (isStrictMode && !topLevel) { 678 if (isStrictMode && !topLevel) {
810 error(AbstractParser.message("strict.no.func.here"), token); 679 throw error(AbstractParser.message("strict.no.func.here"), token);
811 } 680 }
812 functionExpression(true, topLevel); 681 functionExpression(true, topLevel);
813 return; 682 return;
814 } 683 }
815 684
816 getBlock().addStatement(lineNumberNode); 685 if (lineNumberNode != null) {
686 appendStatement(lineNumberNode);
687 }
817 688
818 switch (type) { 689 switch (type) {
819 case LBRACE: 690 case LBRACE:
820 block(); 691 block();
821 break; 692 break;
891 * see 12.1 762 * see 12.1
892 * 763 *
893 * Parse a statement block. 764 * Parse a statement block.
894 */ 765 */
895 private void block() { 766 private void block() {
896 // Get statements in block.
897 final Block newBlock = getBlock(true); 767 final Block newBlock = getBlock(true);
898
899 // Force block execution. 768 // Force block execution.
900 final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock); 769 appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock));
901
902 getBlock().addStatement(executeNode);
903 } 770 }
904 771
905 /** 772 /**
906 * StatementList : 773 * StatementList :
907 * Statement 774 * Statement
940 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 807 private void verifyStrictIdent(final IdentNode ident, final String contextString) {
941 if (isStrictMode) { 808 if (isStrictMode) {
942 switch (ident.getName()) { 809 switch (ident.getName()) {
943 case "eval": 810 case "eval":
944 case "arguments": 811 case "arguments":
945 error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 812 throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken());
946 default: 813 default:
947 break; 814 break;
948 } 815 }
949 } 816 }
950 } 817 }
993 } 860 }
994 861
995 // Allocate var node. 862 // Allocate var node.
996 final VarNode var = new VarNode(source, varToken, finish, name, init); 863 final VarNode var = new VarNode(source, varToken, finish, name, init);
997 vars.add(var); 864 vars.add(var);
998 // Add to current block. 865 appendStatement(var);
999 getBlock().addStatement(var);
1000 866
1001 if (type != COMMARIGHT) { 867 if (type != COMMARIGHT) {
1002 break; 868 break;
1003 } 869 }
1004 next(); 870 next();
1007 // If is a statement then handle end of line. 873 // If is a statement then handle end of line.
1008 if (isStatement) { 874 if (isStatement) {
1009 boolean semicolon = type == SEMICOLON; 875 boolean semicolon = type == SEMICOLON;
1010 endOfLine(); 876 endOfLine();
1011 if (semicolon) { 877 if (semicolon) {
1012 getBlock().setFinish(finish); 878 lc.getCurrentBlock().setFinish(finish);
1013 } 879 }
1014 } 880 }
1015 881
1016 return vars; 882 return vars;
1017 } 883 }
1024 * 890 *
1025 * Parse an empty statement. 891 * Parse an empty statement.
1026 */ 892 */
1027 private void emptyStatement() { 893 private void emptyStatement() {
1028 if (env._empty_statements) { 894 if (env._empty_statements) {
1029 getBlock().addStatement(new EmptyNode(source, token, 895 appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token)));
1030 Token.descPosition(token) + Token.descLength(token)));
1031 } 896 }
1032 897
1033 // SEMICOLON checked in caller. 898 // SEMICOLON checked in caller.
1034 next(); 899 next();
1035 } 900 }
1050 final Node expression = expression(); 915 final Node expression = expression();
1051 916
1052 ExecuteNode executeNode = null; 917 ExecuteNode executeNode = null;
1053 if (expression != null) { 918 if (expression != null) {
1054 executeNode = new ExecuteNode(source, expressionToken, finish, expression); 919 executeNode = new ExecuteNode(source, expressionToken, finish, expression);
1055 getBlock().addStatement(executeNode); 920 appendStatement(executeNode);
1056 } else { 921 } else {
1057 expect(null); 922 expect(null);
1058 } 923 }
1059 924
1060 endOfLine(); 925 endOfLine();
1061 926
1062 if (executeNode != null) { 927 if (executeNode != null) {
1063 executeNode.setFinish(finish); 928 executeNode.setFinish(finish);
1064 getBlock().setFinish(finish); 929 lc.getCurrentBlock().setFinish(finish);
1065 } 930 }
1066 } 931 }
1067 932
1068 /** 933 /**
1069 * IfStatement : 934 * IfStatement :
1079 final long ifToken = token; 944 final long ifToken = token;
1080 // IF tested in caller. 945 // IF tested in caller.
1081 next(); 946 next();
1082 947
1083 expect(LPAREN); 948 expect(LPAREN);
1084
1085 // Get the test expression.
1086 final Node test = expression(); 949 final Node test = expression();
1087
1088 expect(RPAREN); 950 expect(RPAREN);
1089
1090 // Get the pass statement.
1091 final Block pass = getStatement(); 951 final Block pass = getStatement();
1092 952
1093 // Assume no else.
1094 Block fail = null; 953 Block fail = null;
1095
1096 if (type == ELSE) { 954 if (type == ELSE) {
1097 next(); 955 next();
1098
1099 // Get the else block.
1100 fail = getStatement(); 956 fail = getStatement();
1101 } 957 }
1102 958
1103 // Construct and add new if node. 959 appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail));
1104 final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
1105
1106 getBlock().addStatement(ifNode);
1107 } 960 }
1108 961
1109 /** 962 /**
1110 * ... IterationStatement: 963 * ... IterationStatement:
1111 * ... 964 * ...
1118 * 971 *
1119 * Parse a FOR statement. 972 * Parse a FOR statement.
1120 */ 973 */
1121 private void forStatement() { 974 private void forStatement() {
1122 // Create FOR node, capturing FOR token. 975 // Create FOR node, capturing FOR token.
1123 final ForNode forNode = new ForNode(source, token, Token.descPosition(token)); 976 ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR);
1124 977
1125 pushControlNode(forNode);
1126 978
1127 // Set up new block for scope of vars. Captures first token. 979 // Set up new block for scope of vars. Captures first token.
1128 final Block outer = newBlock(); 980 Block outer = newBlock();
981 lc.push(forNode);
1129 982
1130 try { 983 try {
1131 // FOR tested in caller. 984 // FOR tested in caller.
1132 next(); 985 next();
1133 986
1134 // Nashorn extension: for each expression. 987 // Nashorn extension: for each expression.
1135 // iterate property values rather than property names. 988 // iterate property values rather than property names.
1136 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 989 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) {
1137 forNode.setIsForEach(); 990 forNode = forNode.setIsForEach(lc);
1138 next(); 991 next();
1139 } 992 }
1140 993
1141 expect(LPAREN); 994 expect(LPAREN);
1142 995
1143 /// Capture control information. 996 List<VarNode> vars = null;
1144 forControl(forNode); 997
998 switch (type) {
999 case VAR:
1000 // Var statements captured in for outer block.
1001 vars = variableStatement(false);
1002 break;
1003 case SEMICOLON:
1004 break;
1005 default:
1006 final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
1007 forNode = forNode.setInit(lc, expression);
1008 break;
1009 }
1010
1011 switch (type) {
1012 case SEMICOLON:
1013 // for (init; test; modify)
1014 expect(SEMICOLON);
1015 if (type != SEMICOLON) {
1016 forNode = forNode.setTest(lc, expression());
1017 }
1018 expect(SEMICOLON);
1019 if (type != RPAREN) {
1020 forNode = forNode.setModify(lc, expression());
1021 }
1022 break;
1023
1024 case IN:
1025 forNode = forNode.setIsForIn(lc);
1026 if (vars != null) {
1027 // for (var i in obj)
1028 if (vars.size() == 1) {
1029 forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName()));
1030 } else {
1031 // for (var i, j in obj) is invalid
1032 throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
1033 }
1034
1035 } else {
1036 // for (expr in obj)
1037 final Node init = forNode.getInit();
1038 assert init != null : "for..in init expression can not be null here";
1039
1040 // check if initial expression is a valid L-value
1041 if (!(init instanceof AccessNode ||
1042 init instanceof IndexNode ||
1043 init instanceof IdentNode)) {
1044 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1045 }
1046
1047 if (init instanceof IdentNode) {
1048 if (!checkIdentLValue((IdentNode)init)) {
1049 throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1050 }
1051 verifyStrictIdent((IdentNode)init, "for-in iterator");
1052 }
1053 }
1054
1055 next();
1056
1057 // Get the collection expression.
1058 forNode = forNode.setModify(lc, expression());
1059 break;
1060
1061 default:
1062 expect(SEMICOLON);
1063 break;
1064 }
1145 1065
1146 expect(RPAREN); 1066 expect(RPAREN);
1147 1067
1148 // Set the for body. 1068 // Set the for body.
1149 final Block body = getStatement(); 1069 final Block body = getStatement();
1150 forNode.setBody(body); 1070 forNode = forNode.setBody(lc, body);
1151 forNode.setFinish(body.getFinish()); 1071 forNode.setFinish(body.getFinish());
1152 outer.setFinish(body.getFinish()); 1072 outer.setFinish(body.getFinish());
1153 1073
1154 // Add for to current block. 1074 appendStatement(forNode);
1155 getBlock().addStatement(forNode);
1156 } finally { 1075 } finally {
1157 restoreBlock(outer); 1076 lc.pop(forNode);
1158 popControlNode(); 1077 outer = restoreBlock(outer);
1159 } 1078 }
1160 1079
1161 getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 1080 appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
1162 } 1081 }
1163 1082
1164 /** 1083 /**
1165 * ... IterationStatement : 1084 * ... IterationStatement :
1166 * ... 1085 * ...
1173 * 1092 *
1174 * Parse the control section of a FOR statement. Also used for 1093 * Parse the control section of a FOR statement. Also used for
1175 * comprehensions. 1094 * comprehensions.
1176 * @param forNode Owning FOR. 1095 * @param forNode Owning FOR.
1177 */ 1096 */
1178 private void forControl(final ForNode forNode) { 1097
1179 List<VarNode> vars = null;
1180
1181 switch (type) {
1182 case VAR:
1183 // Var statements captured in for outer block.
1184 vars = variableStatement(false);
1185 break;
1186
1187 case SEMICOLON:
1188 break;
1189
1190 default:
1191 final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true);
1192 forNode.setInit(expression);
1193 }
1194
1195 switch (type) {
1196 case SEMICOLON:
1197 // for (init; test; modify)
1198 expect(SEMICOLON);
1199
1200 // Get the test expression.
1201 if (type != SEMICOLON) {
1202 forNode.setTest(expression());
1203 }
1204
1205 expect(SEMICOLON);
1206
1207 // Get the modify expression.
1208 if (type != RPAREN) {
1209 final Node expression = expression();
1210 forNode.setModify(expression);
1211 }
1212
1213 break;
1214
1215 case IN:
1216 forNode.setIsForIn();
1217
1218 if (vars != null) {
1219 // for (var i in obj)
1220 if (vars.size() == 1) {
1221 forNode.setInit(new IdentNode(vars.get(0).getName()));
1222 } else {
1223 // for (var i, j in obj) is invalid
1224 error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken());
1225 }
1226
1227 } else {
1228 // for (expr in obj)
1229 final Node init = forNode.getInit();
1230 assert init != null : "for..in init expression can not be null here";
1231
1232 // check if initial expression is a valid L-value
1233 if (!(init instanceof AccessNode ||
1234 init instanceof IndexNode ||
1235 init instanceof IdentNode)) {
1236 error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1237 }
1238
1239 if (init instanceof IdentNode) {
1240 if (!checkIdentLValue((IdentNode)init)) {
1241 error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken());
1242 }
1243 verifyStrictIdent((IdentNode)init, "for-in iterator");
1244 }
1245 }
1246
1247 next();
1248
1249 // Get the collection expression.
1250 forNode.setModify(expression());
1251 break;
1252
1253 default:
1254 expect(SEMICOLON);
1255 break;
1256 }
1257
1258 }
1259 1098
1260 /** 1099 /**
1261 * ...IterationStatement : 1100 * ...IterationStatement :
1262 * ... 1101 * ...
1263 * while ( Expression ) Statement 1102 * while ( Expression ) Statement
1272 final long whileToken = token; 1111 final long whileToken = token;
1273 // WHILE tested in caller. 1112 // WHILE tested in caller.
1274 next(); 1113 next();
1275 1114
1276 // Construct WHILE node. 1115 // Construct WHILE node.
1277 final WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken)); 1116 WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false);
1278 pushControlNode(whileNode); 1117 lc.push(whileNode);
1279 1118
1280 try { 1119 try {
1281 expect(LPAREN); 1120 expect(LPAREN);
1282 1121 whileNode = whileNode.setTest(lc, expression());
1283 // Get the test expression.
1284 final Node test = expression();
1285 whileNode.setTest(test);
1286
1287 expect(RPAREN); 1122 expect(RPAREN);
1288 1123 whileNode = whileNode.setBody(lc, getStatement());
1289 // Get WHILE body. 1124 appendStatement(whileNode);
1290 final Block statements = getStatement();
1291 whileNode.setBody(statements);
1292 whileNode.setFinish(statements.getFinish());
1293
1294 // Add WHILE node.
1295 getBlock().addStatement(whileNode);
1296 } finally { 1125 } finally {
1297 popControlNode(); 1126 lc.pop(whileNode);
1298 } 1127 }
1299 } 1128 }
1300 1129
1301 /** 1130 /**
1302 * ...IterationStatement : 1131 * ...IterationStatement :
1312 // Capture DO token. 1141 // Capture DO token.
1313 final long doToken = token; 1142 final long doToken = token;
1314 // DO tested in the caller. 1143 // DO tested in the caller.
1315 next(); 1144 next();
1316 1145
1317 final WhileNode doWhileNode = new DoWhileNode(source, doToken, Token.descPosition(doToken)); 1146 WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true);
1318 pushControlNode(doWhileNode); 1147 lc.push(doWhileNode);
1319 1148
1320 try { 1149 try {
1321 // Get DO body. 1150 // Get DO body.
1322 final Block statements = getStatement(); 1151 doWhileNode = doWhileNode.setBody(lc, getStatement());
1323 doWhileNode.setBody(statements);
1324 1152
1325 expect(WHILE); 1153 expect(WHILE);
1326
1327 expect(LPAREN); 1154 expect(LPAREN);
1328 1155 doWhileNode = doWhileNode.setTest(lc, expression());
1329 // Get the test expression.
1330 final Node test = expression();
1331 doWhileNode.setTest(test);
1332
1333 expect(RPAREN); 1156 expect(RPAREN);
1334 1157
1335 if (type == SEMICOLON) { 1158 if (type == SEMICOLON) {
1336 endOfLine(); 1159 endOfLine();
1337 } 1160 }
1338
1339 doWhileNode.setFinish(finish); 1161 doWhileNode.setFinish(finish);
1340 1162 appendStatement(doWhileNode);
1341 // Add DO node.
1342 getBlock().addStatement(doWhileNode);
1343 } finally { 1163 } finally {
1344 popControlNode(); 1164 lc.pop(doWhileNode);
1345 } 1165 }
1346 } 1166 }
1347 1167
1348 /** 1168 /**
1349 * ContinueStatement : 1169 * ContinueStatement :
1368 case EOL: 1188 case EOL:
1369 break; 1189 break;
1370 1190
1371 default: 1191 default:
1372 final IdentNode ident = getIdent(); 1192 final IdentNode ident = getIdent();
1373 labelNode = findLabel(ident); 1193 labelNode = lc.findLabel(ident.getName());
1374 1194
1375 if (labelNode == null) { 1195 if (labelNode == null) {
1376 error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1196 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
1377 } 1197 }
1378 1198
1379 break; 1199 break;
1380 } 1200 }
1381 1201
1382 final Node targetNode = labelNode != null ? labelNode.getContinueNode() : findControl(WhileNode.class); 1202 final IdentNode label = labelNode == null ? null : labelNode.getLabel();
1203 final LoopNode targetNode = lc.getContinueTo(label);
1383 1204
1384 if (targetNode == null) { 1205 if (targetNode == null) {
1385 error(AbstractParser.message("illegal.continue.stmt"), continueToken); 1206 throw error(AbstractParser.message("illegal.continue.stmt"), continueToken);
1386 } 1207 }
1387 1208
1388 endOfLine(); 1209 endOfLine();
1389 1210
1390 // Construct and add CONTINUE node. 1211 // Construct and add CONTINUE node.
1391 final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class)); 1212 appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label)));
1392 continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
1393
1394 getBlock().addStatement(continueNode);
1395 } 1213 }
1396 1214
1397 /** 1215 /**
1398 * BreakStatement : 1216 * BreakStatement :
1399 * break Identifier? ; // [no LineTerminator here] 1217 * break Identifier? ; // [no LineTerminator here]
1416 case EOL: 1234 case EOL:
1417 break; 1235 break;
1418 1236
1419 default: 1237 default:
1420 final IdentNode ident = getIdent(); 1238 final IdentNode ident = getIdent();
1421 labelNode = findLabel(ident); 1239 labelNode = lc.findLabel(ident.getName());
1422 1240
1423 if (labelNode == null) { 1241 if (labelNode == null) {
1424 error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 1242 throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken());
1425 } 1243 }
1426 1244
1427 break; 1245 break;
1428 } 1246 }
1429 1247
1430 final Node targetNode = labelNode != null ? labelNode.getBreakNode() : findControl(BreakableNode.class); 1248 //either an explicit label - then get its node or just a "break" - get first breakable
1431 1249 //targetNode is what we are breaking out from.
1250 final IdentNode label = labelNode == null ? null : labelNode.getLabel();
1251 final BreakableNode targetNode = lc.getBreakable(label);
1432 if (targetNode == null) { 1252 if (targetNode == null) {
1433 error(AbstractParser.message("illegal.break.stmt"), breakToken); 1253 throw error(AbstractParser.message("illegal.break.stmt"), breakToken);
1434 } 1254 }
1435 1255
1436 endOfLine(); 1256 endOfLine();
1437 1257
1438 // Construct and add BREAK node. 1258 // Construct and add BREAK node.
1439 final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class)); 1259 appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label)));
1440 breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
1441
1442 getBlock().addStatement(breakNode);
1443 } 1260 }
1444 1261
1445 /** 1262 /**
1446 * ReturnStatement : 1263 * ReturnStatement :
1447 * return Expression? ; // [no LineTerminator here] 1264 * return Expression? ; // [no LineTerminator here]
1450 * 1267 *
1451 * Parse RETURN statement. 1268 * Parse RETURN statement.
1452 */ 1269 */
1453 private void returnStatement() { 1270 private void returnStatement() {
1454 // check for return outside function 1271 // check for return outside function
1455 if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) { 1272 if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
1456 error(AbstractParser.message("invalid.return")); 1273 throw error(AbstractParser.message("invalid.return"));
1457 } 1274 }
1458 1275
1459 // Capture RETURN token. 1276 // Capture RETURN token.
1460 final long returnToken = token; 1277 final long returnToken = token;
1461 // RETURN tested in caller. 1278 // RETURN tested in caller.
1476 } 1293 }
1477 1294
1478 endOfLine(); 1295 endOfLine();
1479 1296
1480 // Construct and add RETURN node. 1297 // Construct and add RETURN node.
1481 final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class)); 1298 appendStatement(new ReturnNode(source, returnToken, finish, expression));
1482 getBlock().addStatement(returnNode);
1483 } 1299 }
1484 1300
1485 /** 1301 /**
1486 * YieldStatement : 1302 * YieldStatement :
1487 * yield Expression? ; // [no LineTerminator here] 1303 * yield Expression? ; // [no LineTerminator here]
1511 } 1327 }
1512 1328
1513 endOfLine(); 1329 endOfLine();
1514 1330
1515 // Construct and add YIELD node. 1331 // Construct and add YIELD node.
1516 final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class)); 1332 appendStatement(new ReturnNode(source, yieldToken, finish, expression));
1517 getBlock().addStatement(yieldNode);
1518 } 1333 }
1519 1334
1520 /** 1335 /**
1521 * WithStatement : 1336 * WithStatement :
1522 * with ( Expression ) Statement 1337 * with ( Expression ) Statement
1531 // WITH tested in caller. 1346 // WITH tested in caller.
1532 next(); 1347 next();
1533 1348
1534 // ECMA 12.10.1 strict mode restrictions 1349 // ECMA 12.10.1 strict mode restrictions
1535 if (isStrictMode) { 1350 if (isStrictMode) {
1536 error(AbstractParser.message("strict.no.with"), withToken); 1351 throw error(AbstractParser.message("strict.no.with"), withToken);
1537 } 1352 }
1538 1353
1539 // Get WITH expression. 1354 // Get WITH expression.
1540 final WithNode withNode = new WithNode(source, withToken, finish, null, null); 1355 WithNode withNode = new WithNode(source, withToken, finish);
1541 final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 1356 markWithOrEval(lc, FunctionNode.HAS_WITH);
1542 if(it.hasNext()) {
1543 it.next().setHasWith(it);
1544 }
1545 1357
1546 try { 1358 try {
1547 pushControlNode(withNode); 1359 lc.push(withNode);
1548
1549 expect(LPAREN); 1360 expect(LPAREN);
1550 1361 withNode = withNode.setExpression(lc, expression());
1551 final Node expression = expression();
1552 withNode.setExpression(expression);
1553
1554 expect(RPAREN); 1362 expect(RPAREN);
1555 1363 withNode = withNode.setBody(lc, getStatement());
1556 // Get WITH body.
1557 final Block statements = getStatement();
1558 withNode.setBody(statements);
1559 withNode.setFinish(finish);
1560 } finally { 1364 } finally {
1561 popControlNode(withNode); 1365 lc.pop(withNode);
1562 } 1366 }
1563 1367
1564 getBlock().addStatement(withNode); 1368 appendStatement(withNode);
1565 } 1369 }
1566 1370
1567 /** 1371 /**
1568 * SwitchStatement : 1372 * SwitchStatement :
1569 * switch ( Expression ) CaseBlock 1373 * switch ( Expression ) CaseBlock
1585 * See 12.11 1389 * See 12.11
1586 * 1390 *
1587 * Parse SWITCH statement. 1391 * Parse SWITCH statement.
1588 */ 1392 */
1589 private void switchStatement() { 1393 private void switchStatement() {
1590 // Capture SWITCH token.
1591 final long switchToken = token; 1394 final long switchToken = token;
1592 // SWITCH tested in caller. 1395 // SWITCH tested in caller.
1593 next(); 1396 next();
1594 1397
1595 // Create and add switch statement. 1398 // Create and add switch statement.
1596 final SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken)); 1399 SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null);
1597 pushControlNode(switchNode); 1400 lc.push(switchNode);
1598 1401
1599 try { 1402 try {
1600 expect(LPAREN); 1403 expect(LPAREN);
1601 1404 switchNode = switchNode.setExpression(lc, expression());
1602 // Get switch expression.
1603 final Node switchExpression = expression();
1604 switchNode.setExpression(switchExpression);
1605
1606 expect(RPAREN); 1405 expect(RPAREN);
1607 1406
1608 expect(LBRACE); 1407 expect(LBRACE);
1609 1408
1610 // Prepare to accumulate cases. 1409 // Prepare to accumulate cases.
1617 final long caseToken = token; 1416 final long caseToken = token;
1618 1417
1619 switch (type) { 1418 switch (type) {
1620 case CASE: 1419 case CASE:
1621 next(); 1420 next();
1622
1623 // Get case expression.
1624 caseExpression = expression(); 1421 caseExpression = expression();
1625
1626 break; 1422 break;
1627 1423
1628 case DEFAULT: 1424 case DEFAULT:
1629 if (defaultCase != null) { 1425 if (defaultCase != null) {
1630 error(AbstractParser.message("duplicate.default.in.switch")); 1426 throw error(AbstractParser.message("duplicate.default.in.switch"));
1631 } 1427 }
1632
1633 next(); 1428 next();
1634
1635 break; 1429 break;
1636 1430
1637 default: 1431 default:
1638 // Force an error. 1432 // Force an error.
1639 expect(CASE); 1433 expect(CASE);
1652 } 1446 }
1653 1447
1654 cases.add(caseNode); 1448 cases.add(caseNode);
1655 } 1449 }
1656 1450
1657 switchNode.setCases(cases); 1451 switchNode = switchNode.setCases(lc, cases, defaultCase);
1658 switchNode.setDefaultCase(defaultCase);
1659
1660 next(); 1452 next();
1661
1662 switchNode.setFinish(finish); 1453 switchNode.setFinish(finish);
1663 1454
1664 getBlock().addStatement(switchNode); 1455 appendStatement(switchNode);
1665 } finally { 1456 } finally {
1666 popControlNode(); 1457 lc.pop(switchNode);
1667 } 1458 }
1668 } 1459 }
1669 1460
1670 /** 1461 /**
1671 * LabelledStatement : 1462 * LabelledStatement :
1681 // Get label ident. 1472 // Get label ident.
1682 final IdentNode ident = getIdent(); 1473 final IdentNode ident = getIdent();
1683 1474
1684 expect(COLON); 1475 expect(COLON);
1685 1476
1686 if (findLabel(ident) != null) { 1477 if (lc.findLabel(ident.getName()) != null) {
1687 error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 1478 throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken);
1688 } 1479 }
1689 1480
1481 LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null);
1690 try { 1482 try {
1691 // Create and add label. 1483 lc.push(labelNode);
1692 final LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); 1484 labelNode = labelNode.setBody(lc, getStatement());
1693 pushLabel(labelNode);
1694 // Get and save body.
1695 final Block statements = getStatement();
1696 labelNode.setBody(statements);
1697 labelNode.setFinish(finish); 1485 labelNode.setFinish(finish);
1698 1486 appendStatement(labelNode);
1699 getBlock().addStatement(labelNode);
1700 } finally { 1487 } finally {
1701 // Remove label. 1488 assert lc.peek() instanceof LabelNode;
1702 popLabel(); 1489 lc.pop(labelNode);
1703 } 1490 }
1704 } 1491 }
1705 1492
1706 /** 1493 /**
1707 * ThrowStatement : 1494 * ThrowStatement :
1730 expression = expression(); 1517 expression = expression();
1731 break; 1518 break;
1732 } 1519 }
1733 1520
1734 if (expression == null) { 1521 if (expression == null) {
1735 error(AbstractParser.message("expected.operand", type.getNameOrType())); 1522 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
1736 } 1523 }
1737 1524
1738 endOfLine(); 1525 endOfLine();
1739 1526
1740 // Construct and add THROW node. 1527 appendStatement(new ThrowNode(source, throwToken, finish, expression));
1741 final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
1742 getBlock().addStatement(throwNode);
1743 } 1528 }
1744 1529
1745 /** 1530 /**
1746 * TryStatement : 1531 * TryStatement :
1747 * try Block Catch 1532 * try Block Catch
1764 final long tryToken = token; 1549 final long tryToken = token;
1765 // TRY tested in caller. 1550 // TRY tested in caller.
1766 next(); 1551 next();
1767 1552
1768 // Container block needed to act as target for labeled break statements 1553 // Container block needed to act as target for labeled break statements
1769 final Block outer = newBlock(); 1554 Block outer = newBlock();
1770 pushControlNode(outer);
1771 1555
1772 // Create try. 1556 // Create try.
1773 final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class));
1774 pushControlNode(tryNode);
1775 1557
1776 try { 1558 try {
1777 // Get TRY body. 1559 final Block tryBody = getBlock(true);
1778 final Block tryBody = getBlock(true);
1779
1780 // Prepare to accumulate catches.
1781 final List<Block> catchBlocks = new ArrayList<>(); 1560 final List<Block> catchBlocks = new ArrayList<>();
1782 1561
1783 while (type == CATCH) { 1562 while (type == CATCH) {
1784 // Capture CATCH token.
1785 final long catchToken = token; 1563 final long catchToken = token;
1786 next(); 1564 next();
1787
1788 expect(LPAREN); 1565 expect(LPAREN);
1789
1790 // Get exception ident.
1791 final IdentNode exception = getIdent(); 1566 final IdentNode exception = getIdent();
1792 1567
1793 // ECMA 12.4.1 strict mode restrictions 1568 // ECMA 12.4.1 strict mode restrictions
1794 verifyStrictIdent(exception, "catch argument"); 1569 verifyStrictIdent(exception, "catch argument");
1795 1570
1796 // Check for conditional catch. 1571 // Check for conditional catch.
1797 Node ifExpression = null; 1572 Node ifExpression = null;
1798
1799 if (type == IF) { 1573 if (type == IF) {
1800 next(); 1574 next();
1801
1802 // Get the exception condition. 1575 // Get the exception condition.
1803 ifExpression = expression(); 1576 ifExpression = expression();
1804 } 1577 }
1805 1578
1806 expect(RPAREN); 1579 expect(RPAREN);
1807 1580
1808 final Block catchBlock = newBlock(); 1581 Block catchBlock = newBlock();
1809 try { 1582 try {
1810
1811 // Get CATCH body. 1583 // Get CATCH body.
1812 final Block catchBody = getBlock(true); 1584 final Block catchBody = getBlock(true);
1813
1814 // Create and add catch.
1815 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); 1585 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
1816 getBlock().addStatement(catchNode); 1586 appendStatement(catchNode);
1587 } finally {
1588 catchBlock = restoreBlock(catchBlock);
1817 catchBlocks.add(catchBlock); 1589 catchBlocks.add(catchBlock);
1818 } finally {
1819 restoreBlock(catchBlock);
1820 } 1590 }
1821 1591
1822 // If unconditional catch then should to be the end. 1592 // If unconditional catch then should to be the end.
1823 if (ifExpression == null) { 1593 if (ifExpression == null) {
1824 break; 1594 break;
1825 } 1595 }
1826 } 1596 }
1827 1597
1828 popControlNode();
1829
1830 // Prepare to capture finally statement. 1598 // Prepare to capture finally statement.
1831 Block finallyStatements = null; 1599 Block finallyStatements = null;
1832 1600
1833 if (type == FINALLY) { 1601 if (type == FINALLY) {
1834 next(); 1602 next();
1835
1836 // Get FINALLY body.
1837 finallyStatements = getBlock(true); 1603 finallyStatements = getBlock(true);
1838 } 1604 }
1839 1605
1840 // Need at least one catch or a finally. 1606 // Need at least one catch or a finally.
1841 if (catchBlocks.isEmpty() && finallyStatements == null) { 1607 if (catchBlocks.isEmpty() && finallyStatements == null) {
1842 error(AbstractParser.message("missing.catch.or.finally"), tryToken); 1608 throw error(AbstractParser.message("missing.catch.or.finally"), tryToken);
1843 } 1609 }
1844 1610
1845 tryNode.setBody(tryBody); 1611 final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements);
1846 tryNode.setCatchBlocks(catchBlocks); 1612 // Add try.
1847 tryNode.setFinallyBody(finallyStatements); 1613 assert lc.peek() == outer;
1614 appendStatement(tryNode);
1615
1848 tryNode.setFinish(finish); 1616 tryNode.setFinish(finish);
1849 outer.setFinish(finish); 1617 outer.setFinish(finish);
1850 1618
1851 // Add try.
1852 outer.addStatement(tryNode);
1853 } finally { 1619 } finally {
1854 popControlNode(tryNode); 1620 outer = restoreBlock(outer);
1855 restoreBlock(outer); 1621 }
1856 popControlNode(outer); 1622
1857 } 1623 appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
1858
1859 getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
1860 } 1624 }
1861 1625
1862 /** 1626 /**
1863 * DebuggerStatement : 1627 * DebuggerStatement :
1864 * debugger ; 1628 * debugger ;
1870 private void debuggerStatement() { 1634 private void debuggerStatement() {
1871 // Capture DEBUGGER token. 1635 // Capture DEBUGGER token.
1872 final long debuggerToken = token; 1636 final long debuggerToken = token;
1873 // DEBUGGER tested in caller. 1637 // DEBUGGER tested in caller.
1874 next(); 1638 next();
1875
1876 endOfLine(); 1639 endOfLine();
1877 1640 appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()));
1878 final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
1879 getBlock().addStatement(runtimeNode);
1880 } 1641 }
1881 1642
1882 /** 1643 /**
1883 * PrimaryExpression : 1644 * PrimaryExpression :
1884 * this 1645 * this
1910 } 1671 }
1911 detectSpecialProperty(ident); 1672 detectSpecialProperty(ident);
1912 return ident; 1673 return ident;
1913 case OCTAL: 1674 case OCTAL:
1914 if (isStrictMode) { 1675 if (isStrictMode) {
1915 error(AbstractParser.message("strict.no.octal"), token); 1676 throw error(AbstractParser.message("strict.no.octal"), token);
1916 } 1677 }
1917 case STRING: 1678 case STRING:
1918 case ESCSTRING: 1679 case ESCSTRING:
1919 case DECIMAL: 1680 case DECIMAL:
1920 case HEXADECIMAL: 1681 case HEXADECIMAL:
1979 // Add the following expression to arguments. 1740 // Add the following expression to arguments.
1980 arguments.add(expression()); 1741 arguments.add(expression());
1981 // Skip ending of edit string expression. 1742 // Skip ending of edit string expression.
1982 expect(RBRACE); 1743 expect(RBRACE);
1983 1744
1984 return new CallNode(source, primaryToken, finish, execIdent, arguments); 1745 return new CallNode(source, primaryToken, finish, execIdent, arguments, 0);
1985 } 1746 }
1986 1747
1987 /** 1748 /**
1988 * ArrayLiteral : 1749 * ArrayLiteral :
1989 * [ Elision? ] 1750 * [ Elision? ]
2034 1795
2035 break; 1796 break;
2036 1797
2037 default: 1798 default:
2038 if (!elision) { 1799 if (!elision) {
2039 error(AbstractParser.message("expected.comma", type.getNameOrType())); 1800 throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2040 } 1801 }
2041 // Add expression element. 1802 // Add expression element.
2042 final Node expression = assignmentExpression(false); 1803 final Node expression = assignmentExpression(false);
2043 1804
2044 if (expression != null) { 1805 if (expression != null) {
2075 // LBRACE tested in caller. 1836 // LBRACE tested in caller.
2076 next(); 1837 next();
2077 1838
2078 // Object context. 1839 // Object context.
2079 // Prepare to accumulate elements. 1840 // Prepare to accumulate elements.
2080 final List<Node> elements = new ArrayList<>(); 1841 // final List<Node> elements = new ArrayList<>();
2081 final Map<Object, PropertyNode> map = new HashMap<>(); 1842 final Map<String, PropertyNode> map = new LinkedHashMap<>();
2082 1843
2083 // Create a block for the object literal. 1844 // Create a block for the object literal.
2084 boolean commaSeen = true; 1845 boolean commaSeen = true;
2085 loop: 1846 loop:
2086 while (true) { 1847 while (true) {
2094 commaSeen = true; 1855 commaSeen = true;
2095 break; 1856 break;
2096 1857
2097 default: 1858 default:
2098 if (!commaSeen) { 1859 if (!commaSeen) {
2099 error(AbstractParser.message("expected.comma", type.getNameOrType())); 1860 throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
2100 } 1861 }
2101 1862
2102 commaSeen = false; 1863 commaSeen = false;
2103 // Get and add the next property. 1864 // Get and add the next property.
2104 final PropertyNode property = propertyAssignment(); 1865 final PropertyNode property = propertyAssignment();
2105 final Object key = property.getKeyName(); 1866 final String key = property.getKeyName();
2106 final PropertyNode existingProperty = map.get(key); 1867 final PropertyNode existingProperty = map.get(key);
2107 1868
2108 if (existingProperty != null) { 1869 if (existingProperty == null) {
1870 map.put(key, property);
1871 // elements.add(property);
1872 break;
1873 }
1874
2109 // ECMA section 11.1.5 Object Initialiser 1875 // ECMA section 11.1.5 Object Initialiser
2110 // point # 4 on property assignment production 1876 // point # 4 on property assignment production
2111 final Node value = property.getValue(); 1877 final Node value = property.getValue();
2112 final Node getter = property.getGetter(); 1878 final FunctionNode getter = property.getGetter();
2113 final Node setter = property.getSetter(); 1879 final FunctionNode setter = property.getSetter();
2114 1880
2115 final Node prevValue = existingProperty.getValue(); 1881 final Node prevValue = existingProperty.getValue();
2116 final Node prevGetter = existingProperty.getGetter(); 1882 final FunctionNode prevGetter = existingProperty.getGetter();
2117 final Node prevSetter = existingProperty.getSetter(); 1883 final FunctionNode prevSetter = existingProperty.getSetter();
2118 1884
2119 boolean redefinitionOk = true; 1885 boolean redefinitionOk = true;
2120 // ECMA 11.1.5 strict mode restrictions 1886 // ECMA 11.1.5 strict mode restrictions
2121 if (isStrictMode) { 1887 if (isStrictMode) {
2122 if (value != null && prevValue != null) { 1888 if (value != null && prevValue != null) {
2123 redefinitionOk = false; 1889 redefinitionOk = false;
2124 } 1890 }
2125 } 1891 }
2126 1892
2127 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 1893 final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
2128 final boolean isAccessor = getter != null || setter != null; 1894 final boolean isAccessor = getter != null || setter != null;
2129 1895
2130 // data property redefined as accessor property 1896 // data property redefined as accessor property
2131 if (prevValue != null && isAccessor) { 1897 if (prevValue != null && isAccessor) {
2132 redefinitionOk = false; 1898 redefinitionOk = false;
2133 } 1899 }
2143 redefinitionOk = false; 1909 redefinitionOk = false;
2144 } 1910 }
2145 } 1911 }
2146 1912
2147 if (!redefinitionOk) { 1913 if (!redefinitionOk) {
2148 error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); 1914 throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken());
2149 } 1915 }
2150 1916
1917 PropertyNode newProperty = existingProperty;
2151 if (value != null) { 1918 if (value != null) {
2152 final Node existingValue = existingProperty.getValue(); 1919 if (prevValue == null) {
2153 1920 map.put(key, newProperty = newProperty.setValue(value));
2154 if (existingValue == null) {
2155 existingProperty.setValue(value);
2156 } else { 1921 } else {
2157 final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT); 1922 final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT);
2158 existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value)); 1923 map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value)));
2159 } 1924 }
2160 1925
2161 existingProperty.setGetter(null); 1926 map.put(key, newProperty = newProperty.setGetter(null).setSetter(null));
2162 existingProperty.setSetter(null);
2163 } 1927 }
2164 1928
2165 if (getter != null) { 1929 if (getter != null) {
2166 existingProperty.setGetter(getter); 1930 map.put(key, newProperty = newProperty.setGetter(getter));
2167 } 1931 }
2168 1932
2169 if (setter != null) { 1933 if (setter != null) {
2170 existingProperty.setSetter(setter); 1934 map.put(key, newProperty = newProperty.setSetter(setter));
2171 } 1935 }
2172 } else { 1936 break;
2173 map.put(key, property); 1937 }
2174 elements.add(property); 1938 }
2175 } 1939
2176 1940 return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values()));
2177 break;
2178 }
2179 }
2180
2181 return new ObjectNode(source, objectToken, finish, elements);
2182 } 1941 }
2183 1942
2184 /** 1943 /**
2185 * PropertyName : 1944 * PropertyName :
2186 * IdentifierName 1945 * IdentifierName
2196 switch (type) { 1955 switch (type) {
2197 case IDENT: 1956 case IDENT:
2198 return getIdent(); 1957 return getIdent();
2199 case OCTAL: 1958 case OCTAL:
2200 if (isStrictMode) { 1959 if (isStrictMode) {
2201 error(AbstractParser.message("strict.no.octal"), token); 1960 throw error(AbstractParser.message("strict.no.octal"), token);
2202 } 1961 }
2203 case STRING: 1962 case STRING:
2204 case ESCSTRING: 1963 case ESCSTRING:
2205 case DECIMAL: 1964 case DECIMAL:
2206 case HEXADECIMAL: 1965 case HEXADECIMAL:
2233 private PropertyNode propertyAssignment() { 1992 private PropertyNode propertyAssignment() {
2234 // Capture firstToken. 1993 // Capture firstToken.
2235 final long propertyToken = token; 1994 final long propertyToken = token;
2236 1995
2237 FunctionNode functionNode; 1996 FunctionNode functionNode;
2238 List<IdentNode> parameters;
2239 PropertyNode propertyNode;
2240 PropertyKey propertyName; 1997 PropertyKey propertyName;
2241 1998
2242 if (type == IDENT) { 1999 if (type == IDENT) {
2243 // Get IDENT. 2000 // Get IDENT.
2244 final String ident = (String)expectValue(IDENT); 2001 final String ident = (String)expectValue(IDENT);
2251 final PropertyKey getIdent = propertyName(); 2008 final PropertyKey getIdent = propertyName();
2252 final String getterName = getIdent.getPropertyName(); 2009 final String getterName = getIdent.getPropertyName();
2253 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName); 2010 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName);
2254 expect(LPAREN); 2011 expect(LPAREN);
2255 expect(RPAREN); 2012 expect(RPAREN);
2256 parameters = new ArrayList<>(); 2013 functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER);
2257 functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER); 2014 return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null);
2258 propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
2259 propertyNode.setGetter(functionNode);
2260 return propertyNode;
2261 2015
2262 case "set": 2016 case "set":
2263 final PropertyKey setIdent = propertyName(); 2017 final PropertyKey setIdent = propertyName();
2264 final String setterName = setIdent.getPropertyName(); 2018 final String setterName = setIdent.getPropertyName();
2265 final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName); 2019 final IdentNode setNameNode = new IdentNode(source, ((Node)setIdent).getToken(), finish, "set " + setterName);
2266 expect(LPAREN); 2020 expect(LPAREN);
2267 final IdentNode argIdent = getIdent(); 2021 final IdentNode argIdent = getIdent();
2268 verifyStrictIdent(argIdent, "setter argument"); 2022 verifyStrictIdent(argIdent, "setter argument");
2269 expect(RPAREN); 2023 expect(RPAREN);
2270 parameters = new ArrayList<>(); 2024 List<IdentNode> parameters = new ArrayList<>();
2271 parameters.add(argIdent); 2025 parameters.add(argIdent);
2272 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); 2026 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
2273 propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null); 2027 return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode);
2274 propertyNode.setSetter(functionNode);
2275 return propertyNode;
2276 2028
2277 default: 2029 default:
2278 break; 2030 break;
2279 } 2031 }
2280 } 2032 }
2284 propertyName = propertyName(); 2036 propertyName = propertyName();
2285 } 2037 }
2286 2038
2287 expect(COLON); 2039 expect(COLON);
2288 2040
2289 final Node value = assignmentExpression(false); 2041 return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null);
2290 propertyNode = new PropertyNode(source, propertyToken, finish, propertyName, value); 2042 }
2291 return propertyNode; 2043
2044 private int callNodeFlags() {
2045 return lc.inWith() ? CallNode.IN_WITH_BLOCK : 0;
2292 } 2046 }
2293 2047
2294 /** 2048 /**
2295 * LeftHandSideExpression : 2049 * LeftHandSideExpression :
2296 * NewExpression 2050 * NewExpression
2318 // Catch special functions. 2072 // Catch special functions.
2319 if (lhs instanceof IdentNode) { 2073 if (lhs instanceof IdentNode) {
2320 detectSpecialFunction((IdentNode)lhs); 2074 detectSpecialFunction((IdentNode)lhs);
2321 } 2075 }
2322 2076
2323 lhs = new CallNode(source, callToken, finish, lhs, arguments); 2077 lhs = new CallNode(source, callToken, finish, lhs, arguments, callNodeFlags());
2324 if (isInWithBlock()) {
2325 ((CallNode)lhs).setInWithBlock();
2326 }
2327 } 2078 }
2328 2079
2329 loop: 2080 loop:
2330 while (true) { 2081 while (true) {
2331 // Capture token. 2082 // Capture token.
2335 case LPAREN: 2086 case LPAREN:
2336 // Get NEW or FUNCTION arguments. 2087 // Get NEW or FUNCTION arguments.
2337 final List<Node> arguments = argumentList(); 2088 final List<Node> arguments = argumentList();
2338 2089
2339 // Create call node. 2090 // Create call node.
2340 lhs = new CallNode(source, callToken, finish, lhs, arguments); 2091 lhs = new CallNode(source, callToken, finish, lhs, arguments, callNodeFlags());
2341 if (isInWithBlock()) {
2342 ((CallNode)lhs).setInWithBlock();
2343 }
2344 2092
2345 break; 2093 break;
2346 2094
2347 case LBRACKET: 2095 case LBRACKET:
2348 next(); 2096 next();
2417 2165
2418 if (!env._no_syntax_extensions && type == LBRACE) { 2166 if (!env._no_syntax_extensions && type == LBRACE) {
2419 arguments.add(objectLiteral()); 2167 arguments.add(objectLiteral());
2420 } 2168 }
2421 2169
2422 final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments); 2170 final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments, callNodeFlags());
2423 if (isInWithBlock()) {
2424 callNode.setInWithBlock();
2425 }
2426 2171
2427 return new UnaryNode(source, newToken, callNode); 2172 return new UnaryNode(source, newToken, callNode);
2428 } 2173 }
2429 2174
2430 /** 2175 /**
2480 2225
2481 break; 2226 break;
2482 2227
2483 case PERIOD: 2228 case PERIOD:
2484 if (lhs == null) { 2229 if (lhs == null) {
2485 error(AbstractParser.message("expected.operand", type.getNameOrType())); 2230 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2486 return null;
2487 } 2231 }
2488 2232
2489 next(); 2233 next();
2490 2234
2491 final IdentNode property = getIdentifierName(); 2235 final IdentNode property = getIdentifierName();
2583 name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName); 2327 name = new IdentNode(source, functionToken, Token.descPosition(functionToken), tmpName);
2584 isAnonymous = true; 2328 isAnonymous = true;
2585 } 2329 }
2586 2330
2587 expect(LPAREN); 2331 expect(LPAREN);
2588
2589 final List<IdentNode> parameters = formalParameterList(); 2332 final List<IdentNode> parameters = formalParameterList();
2590
2591 expect(RPAREN); 2333 expect(RPAREN);
2592 2334
2593 final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); 2335 FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
2594 2336
2595 if (isStatement) { 2337 if (isStatement) {
2596 if(topLevel) { 2338 if (topLevel) {
2597 functionNode.setIsDeclared(); 2339 functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED);
2598 } 2340 }
2599 if(ARGUMENTS.tag().equals(name.getName())) { 2341 if (ARGUMENTS.symbolName().equals(name.getName())) {
2600 getFunction().setDefinesArguments(); 2342 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
2601 } 2343 }
2602 } 2344 }
2603 2345
2604 if (isAnonymous) { 2346 if (isAnonymous) {
2605 functionNode.setIsAnonymous(); 2347 functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS);
2606 } 2348 }
2607 2349
2608 final int arity = parameters.size(); 2350 final int arity = parameters.size();
2609 2351
2610 final boolean strict = functionNode.isStrictMode(); 2352 final boolean strict = functionNode.isStrict();
2611 if (arity > 1) { 2353 if (arity > 1) {
2612 final HashSet<String> parametersSet = new HashSet<>(arity); 2354 final HashSet<String> parametersSet = new HashSet<>(arity);
2613 2355
2614 for (int i = arity - 1; i >= 0; i--) { 2356 for (int i = arity - 1; i >= 0; i--) {
2615 final IdentNode parameter = parameters.get(i); 2357 final IdentNode parameter = parameters.get(i);
2616 String parameterName = parameter.getName(); 2358 String parameterName = parameter.getName();
2617 2359
2618 if (ARGUMENTS.tag().equals(parameterName)) { 2360 if (ARGUMENTS.symbolName().equals(parameterName)) {
2619 functionNode.setDefinesArguments(); 2361 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
2620 } 2362 }
2621 2363
2622 if (parametersSet.contains(parameterName)) { 2364 if (parametersSet.contains(parameterName)) {
2623 // redefinition of parameter name 2365 // redefinition of parameter name
2624 if (strict) { 2366 if (strict) {
2625 error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 2367 throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
2626 } else {
2627 // rename in non-strict mode
2628 parameterName = functionNode.uniqueName(parameterName);
2629 final long parameterToken = parameter.getToken();
2630 parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
2631 } 2368 }
2369 // rename in non-strict mode
2370 parameterName = functionNode.uniqueName(parameterName);
2371 final long parameterToken = parameter.getToken();
2372 parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
2632 } 2373 }
2633 2374
2634 parametersSet.add(parameterName); 2375 parametersSet.add(parameterName);
2635 } 2376 }
2636 } else if (arity == 1) { 2377 } else if (arity == 1) {
2637 if (ARGUMENTS.tag().equals(parameters.get(0).getName())) { 2378 if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) {
2638 functionNode.setDefinesArguments(); 2379 functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS);
2639 } 2380 }
2640 } 2381 }
2641 2382
2642 if (isStatement) { 2383 if (isStatement) {
2643 final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true); 2384 final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT);
2644 if(topLevel) { 2385 if (topLevel) {
2645 functionDeclarations.add(lineNumber); 2386 functionDeclarations.add(lineNumber);
2646 functionDeclarations.add(varNode); 2387 functionDeclarations.add(varNode);
2647 } else { 2388 } else {
2648 final Block block = getBlock(); 2389 appendStatement(lineNumber);
2649 block.addStatement(lineNumber); 2390 appendStatement(varNode);
2650 block.addStatement(varNode);
2651 } 2391 }
2652 } 2392 }
2653 2393
2654 return functionNode; 2394 return functionNode;
2655 } 2395 }
2699 * Parse function body. 2439 * Parse function body.
2700 * @return function node (body.) 2440 * @return function node (body.)
2701 */ 2441 */
2702 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { 2442 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) {
2703 FunctionNode functionNode = null; 2443 FunctionNode functionNode = null;
2444 long lastToken = 0L;
2704 2445
2705 try { 2446 try {
2706 // Create a new function block. 2447 // Create a new function block.
2707 functionNode = newFunctionBlock(ident); 2448 functionNode = newFunctionNode(firstToken, ident, parameters, kind);
2708 functionNode.setParameters(parameters);
2709 functionNode.setKind(kind);
2710 functionNode.setFirstToken(firstToken);
2711 2449
2712 // Nashorn extension: expression closures 2450 // Nashorn extension: expression closures
2713 if (!env._no_syntax_extensions && type != LBRACE) { 2451 if (!env._no_syntax_extensions && type != LBRACE) {
2714 /* 2452 /*
2715 * Example: 2453 * Example:
2718 * print(square(3)); 2456 * print(square(3));
2719 */ 2457 */
2720 2458
2721 // just expression as function body 2459 // just expression as function body
2722 final Node expr = expression(); 2460 final Node expr = expression();
2723 2461 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
2724 // create a return statement - this creates code in itself and does not need to be 2462 // create a return statement - this creates code in itself and does not need to be
2725 // wrapped into an ExecuteNode 2463 // wrapped into an ExecuteNode
2726 final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null); 2464 final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr);
2727 2465 appendStatement(returnNode);
2728 // add the return statement 2466 lastToken = token;
2729 functionNode.addStatement(returnNode);
2730 functionNode.setLastToken(token);
2731 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); 2467 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token));
2732 2468
2733 } else { 2469 } else {
2734 expect(LBRACE); 2470 expect(LBRACE);
2735 2471
2736 // Gather the function elements. 2472 // Gather the function elements.
2737 final List<Node> prevFunctionDecls = functionDeclarations; 2473 final List<Node> prevFunctionDecls = functionDeclarations;
2738 functionDeclarations = new ArrayList<>(); 2474 functionDeclarations = new ArrayList<>();
2739 try { 2475 try {
2740 sourceElements(); 2476 sourceElements();
2741 functionNode.prependStatements(functionDeclarations); 2477 addFunctionDeclarations(functionNode);
2742 } finally { 2478 } finally {
2743 functionDeclarations = prevFunctionDecls; 2479 functionDeclarations = prevFunctionDecls;
2744 } 2480 }
2745 2481
2746 functionNode.setLastToken(token); 2482 lastToken = token;
2747 expect(RBRACE); 2483 expect(RBRACE);
2748 functionNode.setFinish(finish); 2484 functionNode.setFinish(finish);
2749 2485
2750 } 2486 }
2751 } finally { 2487 } finally {
2752 restoreBlock(functionNode); 2488 functionNode = restoreFunctionNode(functionNode, lastToken);
2753 } 2489 }
2754
2755 return functionNode; 2490 return functionNode;
2491 }
2492
2493 private void addFunctionDeclarations(final FunctionNode functionNode) {
2494 assert lc.peek() == lc.getFunctionBody(functionNode);
2495 VarNode lastDecl = null;
2496 for (int i = functionDeclarations.size() - 1; i >= 0; i--) {
2497 Node decl = functionDeclarations.get(i);
2498 if (lastDecl == null && decl instanceof VarNode) {
2499 decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION);
2500 lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS);
2501 }
2502 prependStatement(decl);
2503 }
2756 } 2504 }
2757 2505
2758 private RuntimeNode referenceError(final Node lhs, final Node rhs) { 2506 private RuntimeNode referenceError(final Node lhs, final Node rhs) {
2759 final ArrayList<Node> args = new ArrayList<>(); 2507 final ArrayList<Node> args = new ArrayList<>();
2760 args.add(lhs); 2508 args.add(lhs);
2762 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish())); 2510 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish()));
2763 } else { 2511 } else {
2764 args.add(rhs); 2512 args.add(rhs);
2765 } 2513 }
2766 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); 2514 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString()));
2767 final RuntimeNode runtimeNode = new RuntimeNode(source, lhs.getToken(), 2515 return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
2768 lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args);
2769 return runtimeNode;
2770 } 2516 }
2771 2517
2772 /* 2518 /*
2773 * parse LHS [a, b, ..., c]. 2519 * parse LHS [a, b, ..., c].
2774 * 2520 *
2813 case ADD: 2559 case ADD:
2814 case SUB: 2560 case SUB:
2815 case BIT_NOT: 2561 case BIT_NOT:
2816 case NOT: 2562 case NOT:
2817 next(); 2563 next();
2818
2819 final Node expr = unaryExpression(); 2564 final Node expr = unaryExpression();
2820
2821 /*
2822 // Not sure if "delete <ident>" is a compile-time error or a
2823 // runtime error in strict mode.
2824
2825 if (isStrictMode) {
2826 if (unaryTokenType == DELETE && expr instanceof IdentNode) {
2827 error(message("strict.cant.delete.ident", ((IdentNode)expr).getName()), expr.getToken());
2828 }
2829 }
2830 */
2831 return new UnaryNode(source, unaryToken, expr); 2565 return new UnaryNode(source, unaryToken, expr);
2832 2566
2833 case INCPREFIX: 2567 case INCPREFIX:
2834 case DECPREFIX: 2568 case DECPREFIX:
2835 final TokenType opType = type; 2569 final TokenType opType = type;
2888 break; 2622 break;
2889 } 2623 }
2890 } 2624 }
2891 2625
2892 if (expression == null) { 2626 if (expression == null) {
2893 error(AbstractParser.message("expected.operand", type.getNameOrType())); 2627 throw error(AbstractParser.message("expected.operand", type.getNameOrType()));
2894 } 2628 }
2895 2629
2896 return expression; 2630 return expression;
2897 } 2631 }
2898 2632
2990 private Node expression() { 2724 private Node expression() {
2991 // TODO - Destructuring array. 2725 // TODO - Destructuring array.
2992 // Include commas in expression parsing. 2726 // Include commas in expression parsing.
2993 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 2727 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
2994 } 2728 }
2729
2995 private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) { 2730 private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) {
2996 // Get the precedence of the next operator. 2731 // Get the precedence of the next operator.
2997 int precedence = type.getPrecedence(); 2732 int precedence = type.getPrecedence();
2998 Node lhs = exprLhs; 2733 Node lhs = exprLhs;
2999 2734
3085 @Override 2820 @Override
3086 public String toString() { 2821 public String toString() {
3087 return "[JavaScript Parsing]"; 2822 return "[JavaScript Parsing]";
3088 } 2823 }
3089 2824
3090 private Block getBlock() { 2825 private static void markWithOrEval(final LexicalContext lc, int flag) {
3091 return lexicalContext.getCurrentBlock(); 2826 final Iterator<FunctionNode> iter = lc.getFunctions();
3092 } 2827 boolean flaggedCurrentFn = false;
3093 2828 while (iter.hasNext()) {
3094 private FunctionNode getFunction() { 2829 final FunctionNode fn = iter.next();
3095 return lexicalContext.getCurrentFunction(); 2830 if (!flaggedCurrentFn) {
2831 lc.setFlag(fn, flag);
2832 flaggedCurrentFn = true;
2833 } else {
2834 lc.setFlag(fn, FunctionNode.HAS_DESCENDANT_WITH_OR_EVAL);
2835 }
2836 lc.setFlag(lc.getFunctionBody(fn), Block.NEEDS_SCOPE);
2837 }
2838 }
2839
2840 private void prependStatement(final Node statement) {
2841 lc.prependStatement(statement);
2842 }
2843
2844 private void appendStatement(final Node statement) {
2845 lc.appendStatement(statement);
3096 } 2846 }
3097 } 2847 }

mercurial