< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java

Print this page




  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
  30 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
  31 
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.List;
  36 import java.util.ListIterator;
  37 import java.util.regex.Pattern;
  38 import jdk.nashorn.internal.ir.AccessNode;
  39 import jdk.nashorn.internal.ir.BaseNode;
  40 import jdk.nashorn.internal.ir.BinaryNode;
  41 import jdk.nashorn.internal.ir.Block;
  42 import jdk.nashorn.internal.ir.BlockLexicalContext;
  43 import jdk.nashorn.internal.ir.BlockStatement;
  44 import jdk.nashorn.internal.ir.BreakNode;
  45 import jdk.nashorn.internal.ir.CallNode;
  46 import jdk.nashorn.internal.ir.CaseNode;
  47 import jdk.nashorn.internal.ir.CatchNode;

  48 import jdk.nashorn.internal.ir.ContinueNode;
  49 import jdk.nashorn.internal.ir.DebuggerNode;
  50 import jdk.nashorn.internal.ir.EmptyNode;
  51 import jdk.nashorn.internal.ir.Expression;
  52 import jdk.nashorn.internal.ir.ExpressionStatement;
  53 import jdk.nashorn.internal.ir.ForNode;
  54 import jdk.nashorn.internal.ir.FunctionNode;
  55 import jdk.nashorn.internal.ir.IdentNode;
  56 import jdk.nashorn.internal.ir.IfNode;
  57 import jdk.nashorn.internal.ir.IndexNode;
  58 import jdk.nashorn.internal.ir.JumpStatement;
  59 import jdk.nashorn.internal.ir.JumpToInlinedFinally;
  60 import jdk.nashorn.internal.ir.LabelNode;
  61 import jdk.nashorn.internal.ir.LexicalContext;
  62 import jdk.nashorn.internal.ir.LiteralNode;
  63 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
  64 import jdk.nashorn.internal.ir.LoopNode;
  65 import jdk.nashorn.internal.ir.Node;
  66 import jdk.nashorn.internal.ir.ReturnNode;
  67 import jdk.nashorn.internal.ir.RuntimeNode;
  68 import jdk.nashorn.internal.ir.Statement;
  69 import jdk.nashorn.internal.ir.SwitchNode;
  70 import jdk.nashorn.internal.ir.Symbol;
  71 import jdk.nashorn.internal.ir.ThrowNode;
  72 import jdk.nashorn.internal.ir.TryNode;

  73 import jdk.nashorn.internal.ir.VarNode;
  74 import jdk.nashorn.internal.ir.WhileNode;
  75 import jdk.nashorn.internal.ir.WithNode;
  76 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
  77 import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
  78 import jdk.nashorn.internal.parser.Token;
  79 import jdk.nashorn.internal.parser.TokenType;
  80 import jdk.nashorn.internal.runtime.Context;


  81 import jdk.nashorn.internal.runtime.JSType;
  82 import jdk.nashorn.internal.runtime.Source;
  83 import jdk.nashorn.internal.runtime.logging.DebugLogger;
  84 import jdk.nashorn.internal.runtime.logging.Loggable;
  85 import jdk.nashorn.internal.runtime.logging.Logger;
  86 
  87 /**
  88  * Lower to more primitive operations. After lowering, an AST still has no symbols
  89  * and types, but several nodes have been turned into more low level constructs
  90  * and control flow termination criteria have been computed.
  91  *
  92  * We do things like code copying/inlining of finallies here, as it is much
  93  * harder and context dependent to do any code copying after symbols have been
  94  * finalized.
  95  */
  96 @Logger(name="lower")
  97 final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Loggable {
  98 
  99     private final DebugLogger log;
 100     private final boolean es6;

 101 
 102     // Conservative pattern to test if element names consist of characters valid for identifiers.
 103     // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
 104     private static final Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*");
 105 
 106     /**
 107      * Constructor.
 108      */
 109     Lower(final Compiler compiler) {
 110         super(new BlockLexicalContext() {
 111 
 112             @Override
 113             public List<Statement> popStatements() {
 114                 final List<Statement> newStatements = new ArrayList<>();
 115                 boolean terminated = false;
 116 
 117                 final List<Statement> statements = super.popStatements();
 118                 for (final Statement statement : statements) {
 119                     if (!terminated) {
 120                         newStatements.add(statement);


 129             }
 130 
 131             @Override
 132             protected Block afterSetStatements(final Block block) {
 133                 final List<Statement> stmts = block.getStatements();
 134                 for(final ListIterator<Statement> li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
 135                     final Statement stmt = li.previous();
 136                     // popStatements() guarantees that the only thing after a terminal statement are uninitialized
 137                     // VarNodes. We skip past those, and set the terminal state of the block to the value of the
 138                     // terminal state of the first statement that is not an uninitialized VarNode.
 139                     if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
 140                         return block.setIsTerminal(this, stmt.isTerminal());
 141                     }
 142                 }
 143                 return block.setIsTerminal(this, false);
 144             }
 145         });
 146 
 147         this.log = initLogger(compiler.getContext());
 148         this.es6 = compiler.getScriptEnvironment()._es6;

 149     }
 150 
 151     @Override
 152     public DebugLogger getLogger() {
 153         return log;
 154     }
 155 
 156     @Override
 157     public DebugLogger initLogger(final Context context) {
 158         return context.getLogger(this.getClass());
 159     }
 160 
 161     @Override
 162     public boolean enterBreakNode(final BreakNode breakNode) {
 163         addStatement(breakNode);
 164         return false;
 165     }
 166 
 167     @Override
 168     public Node leaveCallNode(final CallNode callNode) {


 224 
 225     @Override
 226     public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
 227         final Expression expr = expressionStatement.getExpression();
 228         ExpressionStatement node = expressionStatement;
 229 
 230         final FunctionNode currentFunction = lc.getCurrentFunction();
 231 
 232         if (currentFunction.isProgram()) {
 233             if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
 234                 node = expressionStatement.setExpression(
 235                     new BinaryNode(
 236                         Token.recast(
 237                             expressionStatement.getToken(),
 238                             TokenType.ASSIGN),
 239                         compilerConstant(RETURN),
 240                     expr));
 241             }
 242         }
 243 




 244         return addStatement(node);
 245     }
 246 
 247     @Override
 248     public Node leaveBlockStatement(final BlockStatement blockStatement) {
 249         return addStatement(blockStatement);
 250     }
 251 
 252     @Override
 253     public Node leaveForNode(final ForNode forNode) {
 254         ForNode newForNode = forNode;
 255 
 256         final Expression test = forNode.getTest();
 257         if (!forNode.isForInOrOf() && isAlwaysTrue(test)) {
 258             newForNode = forNode.setTest(lc, null);
 259         }
 260 
 261         newForNode = checkEscape(newForNode);
 262         if(!es6 && newForNode.isForInOrOf()) {
 263             // Wrap it in a block so its internally created iterator is restricted in scope, unless we are running
 264             // in ES6 mode, in which case the parser already created a block to capture let/const declarations.
 265             addStatementEnclosedInBlock(newForNode);
 266         } else {
 267             addStatement(newForNode);
 268         }
 269         return newForNode;
 270     }
 271 
 272     @Override























 273     public Node leaveFunctionNode(final FunctionNode functionNode) {
 274         log.info("END FunctionNode: ", functionNode.getName());
 275         return functionNode;
 276     }
 277 
 278     @Override
 279     public Node leaveIfNode(final IfNode ifNode) {
 280         return addStatement(ifNode);
 281     }
 282 
 283     @Override
 284     public Node leaveIN(final BinaryNode binaryNode) {
 285         return new RuntimeNode(binaryNode);
 286     }
 287 
 288     @Override
 289     public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
 290         return new RuntimeNode(binaryNode);
 291     }
 292 


 561         /*
 562          * Now that the transform is done, we have to go into the try and splice
 563          * the finally block in front of any statement that is outside the try
 564          */
 565         return (TryNode)lc.replace(tryNode, spliceFinally(newTryNode, rethrows.get(0), finallyBody));
 566     }
 567 
 568     private TryNode ensureUnconditionalCatch(final TryNode tryNode) {
 569         final List<CatchNode> catches = tryNode.getCatches();
 570         if(catches == null || catches.isEmpty() || catches.get(catches.size() - 1).getExceptionCondition() == null) {
 571             return tryNode;
 572         }
 573         // If the last catch block is conditional, add an unconditional rethrow block
 574         final List<Block> newCatchBlocks = new ArrayList<>(tryNode.getCatchBlocks());
 575 
 576         newCatchBlocks.add(catchAllBlock(tryNode));
 577         return tryNode.setCatchBlocks(lc, newCatchBlocks);
 578     }
 579 
 580     @Override















 581     public Node leaveVarNode(final VarNode varNode) {
 582         addStatement(varNode);
 583         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION)
 584                 && lc.getCurrentFunction().isProgram()
 585                 && ((FunctionNode) varNode.getInit()).isAnonymous()) {
 586             new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
 587         }
 588         return varNode;
 589     }
 590 
 591     @Override
 592     public Node leaveWhileNode(final WhileNode whileNode) {
 593         final Expression test = whileNode.getTest();
 594         final Block body = whileNode.getBody();
 595 
 596         if (isAlwaysTrue(test)) {
 597             //turn it into a for node without a test.
 598             final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this);
 599             lc.replace(whileNode, forNode);
 600             return forNode;
 601         }
 602 
 603          return addStatement(checkEscape(whileNode));
 604     }
 605 
 606     @Override
 607     public Node leaveWithNode(final WithNode withNode) {
 608         return addStatement(withNode);
 609     }
 610 






 611     /**
 612      * Given a function node that is a callee in a CallNode, replace it with
 613      * the appropriate marker function. This is used by {@link CodeGenerator}
 614      * for fast scope calls
 615      *
 616      * @param function function called by a CallNode
 617      * @return transformed node to marker function or identity if not ident/access/indexnode
 618      */
 619     private static Expression markerFunction(final Expression function) {
 620         if (function instanceof IdentNode) {
 621             return ((IdentNode)function).setIsFunction();
 622         } else if (function instanceof BaseNode) {
 623             return ((BaseNode)function).setIsFunction();
 624         }
 625         return function;
 626     }
 627 
 628     /**
 629      * Calculate a synthetic eval location for a node for the stacktrace, for example src#17<eval>
 630      * @param node a node


 748         final Symbol symbol = ((IdentNode)expression).getSymbol();
 749         return symbol != null && symbol.isInternal();
 750     }
 751 
 752     /**
 753      * Is this an assignment to the special variable that hosts scripting eval
 754      * results, i.e. __return__?
 755      *
 756      * @param expression expression to check whether it is $evalresult = X
 757      * @return true if an assignment to eval result, false otherwise
 758      */
 759     private static boolean isEvalResultAssignment(final Node expression) {
 760         final Node e = expression;
 761         if (e instanceof BinaryNode) {
 762             final Node lhs = ((BinaryNode)e).lhs();
 763             if (lhs instanceof IdentNode) {
 764                 return ((IdentNode)lhs).getName().equals(RETURN.symbolName());
 765             }
 766         }
 767         return false;









 768     }
 769 }


  28 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
  29 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN;
  30 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue;
  31 
  32 import java.util.ArrayList;
  33 import java.util.Arrays;
  34 import java.util.Collections;
  35 import java.util.List;
  36 import java.util.ListIterator;
  37 import java.util.regex.Pattern;
  38 import jdk.nashorn.internal.ir.AccessNode;
  39 import jdk.nashorn.internal.ir.BaseNode;
  40 import jdk.nashorn.internal.ir.BinaryNode;
  41 import jdk.nashorn.internal.ir.Block;
  42 import jdk.nashorn.internal.ir.BlockLexicalContext;
  43 import jdk.nashorn.internal.ir.BlockStatement;
  44 import jdk.nashorn.internal.ir.BreakNode;
  45 import jdk.nashorn.internal.ir.CallNode;
  46 import jdk.nashorn.internal.ir.CaseNode;
  47 import jdk.nashorn.internal.ir.CatchNode;
  48 import jdk.nashorn.internal.ir.ClassNode;
  49 import jdk.nashorn.internal.ir.ContinueNode;
  50 import jdk.nashorn.internal.ir.DebuggerNode;
  51 import jdk.nashorn.internal.ir.EmptyNode;
  52 import jdk.nashorn.internal.ir.Expression;
  53 import jdk.nashorn.internal.ir.ExpressionStatement;
  54 import jdk.nashorn.internal.ir.ForNode;
  55 import jdk.nashorn.internal.ir.FunctionNode;
  56 import jdk.nashorn.internal.ir.IdentNode;
  57 import jdk.nashorn.internal.ir.IfNode;
  58 import jdk.nashorn.internal.ir.IndexNode;
  59 import jdk.nashorn.internal.ir.JumpStatement;
  60 import jdk.nashorn.internal.ir.JumpToInlinedFinally;
  61 import jdk.nashorn.internal.ir.LabelNode;
  62 import jdk.nashorn.internal.ir.LexicalContext;
  63 import jdk.nashorn.internal.ir.LiteralNode;
  64 import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
  65 import jdk.nashorn.internal.ir.LoopNode;
  66 import jdk.nashorn.internal.ir.Node;
  67 import jdk.nashorn.internal.ir.ReturnNode;
  68 import jdk.nashorn.internal.ir.RuntimeNode;
  69 import jdk.nashorn.internal.ir.Statement;
  70 import jdk.nashorn.internal.ir.SwitchNode;
  71 import jdk.nashorn.internal.ir.Symbol;
  72 import jdk.nashorn.internal.ir.ThrowNode;
  73 import jdk.nashorn.internal.ir.TryNode;
  74 import jdk.nashorn.internal.ir.UnaryNode;
  75 import jdk.nashorn.internal.ir.VarNode;
  76 import jdk.nashorn.internal.ir.WhileNode;
  77 import jdk.nashorn.internal.ir.WithNode;
  78 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
  79 import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
  80 import jdk.nashorn.internal.parser.Token;
  81 import jdk.nashorn.internal.parser.TokenType;
  82 import jdk.nashorn.internal.runtime.Context;
  83 import jdk.nashorn.internal.runtime.ECMAErrors;
  84 import jdk.nashorn.internal.runtime.ErrorManager;
  85 import jdk.nashorn.internal.runtime.JSType;
  86 import jdk.nashorn.internal.runtime.Source;
  87 import jdk.nashorn.internal.runtime.logging.DebugLogger;
  88 import jdk.nashorn.internal.runtime.logging.Loggable;
  89 import jdk.nashorn.internal.runtime.logging.Logger;
  90 
  91 /**
  92  * Lower to more primitive operations. After lowering, an AST still has no symbols
  93  * and types, but several nodes have been turned into more low level constructs
  94  * and control flow termination criteria have been computed.
  95  *
  96  * We do things like code copying/inlining of finallies here, as it is much
  97  * harder and context dependent to do any code copying after symbols have been
  98  * finalized.
  99  */
 100 @Logger(name="lower")
 101 final class Lower extends NodeOperatorVisitor<BlockLexicalContext> implements Loggable {
 102 
 103     private final DebugLogger log;
 104     private final boolean es6;
 105     private final Source source;
 106 
 107     // Conservative pattern to test if element names consist of characters valid for identifiers.
 108     // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
 109     private static final Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*");
 110 
 111     /**
 112      * Constructor.
 113      */
 114     Lower(final Compiler compiler) {
 115         super(new BlockLexicalContext() {
 116 
 117             @Override
 118             public List<Statement> popStatements() {
 119                 final List<Statement> newStatements = new ArrayList<>();
 120                 boolean terminated = false;
 121 
 122                 final List<Statement> statements = super.popStatements();
 123                 for (final Statement statement : statements) {
 124                     if (!terminated) {
 125                         newStatements.add(statement);


 134             }
 135 
 136             @Override
 137             protected Block afterSetStatements(final Block block) {
 138                 final List<Statement> stmts = block.getStatements();
 139                 for(final ListIterator<Statement> li = stmts.listIterator(stmts.size()); li.hasPrevious();) {
 140                     final Statement stmt = li.previous();
 141                     // popStatements() guarantees that the only thing after a terminal statement are uninitialized
 142                     // VarNodes. We skip past those, and set the terminal state of the block to the value of the
 143                     // terminal state of the first statement that is not an uninitialized VarNode.
 144                     if(!(stmt instanceof VarNode && ((VarNode)stmt).getInit() == null)) {
 145                         return block.setIsTerminal(this, stmt.isTerminal());
 146                     }
 147                 }
 148                 return block.setIsTerminal(this, false);
 149             }
 150         });
 151 
 152         this.log = initLogger(compiler.getContext());
 153         this.es6 = compiler.getScriptEnvironment()._es6;
 154         this.source = compiler.getSource();
 155     }
 156 
 157     @Override
 158     public DebugLogger getLogger() {
 159         return log;
 160     }
 161 
 162     @Override
 163     public DebugLogger initLogger(final Context context) {
 164         return context.getLogger(this.getClass());
 165     }
 166 
 167     @Override
 168     public boolean enterBreakNode(final BreakNode breakNode) {
 169         addStatement(breakNode);
 170         return false;
 171     }
 172 
 173     @Override
 174     public Node leaveCallNode(final CallNode callNode) {


 230 
 231     @Override
 232     public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) {
 233         final Expression expr = expressionStatement.getExpression();
 234         ExpressionStatement node = expressionStatement;
 235 
 236         final FunctionNode currentFunction = lc.getCurrentFunction();
 237 
 238         if (currentFunction.isProgram()) {
 239             if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
 240                 node = expressionStatement.setExpression(
 241                     new BinaryNode(
 242                         Token.recast(
 243                             expressionStatement.getToken(),
 244                             TokenType.ASSIGN),
 245                         compilerConstant(RETURN),
 246                     expr));
 247             }
 248         }
 249 
 250         if (es6 && expressionStatement.destructuringDeclarationType() != null) {
 251             throwNotImplementedYet("es6.destructuring", expressionStatement);
 252         }
 253 
 254         return addStatement(node);
 255     }
 256 
 257     @Override
 258     public Node leaveBlockStatement(final BlockStatement blockStatement) {
 259         return addStatement(blockStatement);
 260     }
 261 
 262     @Override
 263     public Node leaveForNode(final ForNode forNode) {
 264         ForNode newForNode = forNode;
 265 
 266         final Expression test = forNode.getTest();
 267         if (!forNode.isForInOrOf() && isAlwaysTrue(test)) {
 268             newForNode = forNode.setTest(lc, null);
 269         }
 270 
 271         newForNode = checkEscape(newForNode);
 272         if(!es6 && newForNode.isForInOrOf()) {
 273             // Wrap it in a block so its internally created iterator is restricted in scope, unless we are running
 274             // in ES6 mode, in which case the parser already created a block to capture let/const declarations.
 275             addStatementEnclosedInBlock(newForNode);
 276         } else {
 277             addStatement(newForNode);
 278         }
 279         return newForNode;
 280     }
 281 
 282     @Override
 283     public boolean enterFunctionNode(final FunctionNode functionNode) {
 284         if (es6) {
 285             if (functionNode.getKind() == FunctionNode.Kind.MODULE) {
 286                 throwNotImplementedYet("es6.module", functionNode);
 287             }
 288 
 289             if (functionNode.getKind() == FunctionNode.Kind.GENERATOR) {
 290                 throwNotImplementedYet("es6.generator", functionNode);
 291             }
 292 
 293             int numParams = functionNode.getNumOfParams();
 294             if (numParams > 1) {
 295                 final IdentNode lastParam = functionNode.getParameter(numParams - 1);
 296                 if (lastParam.isRestParameter()) {
 297                     throwNotImplementedYet("es6.rest.param", lastParam);
 298                 }
 299             }
 300         }
 301 
 302         return super.enterFunctionNode(functionNode);
 303     }
 304 
 305     @Override
 306     public Node leaveFunctionNode(final FunctionNode functionNode) {
 307         log.info("END FunctionNode: ", functionNode.getName());
 308         return functionNode;
 309     }
 310 
 311     @Override
 312     public Node leaveIfNode(final IfNode ifNode) {
 313         return addStatement(ifNode);
 314     }
 315 
 316     @Override
 317     public Node leaveIN(final BinaryNode binaryNode) {
 318         return new RuntimeNode(binaryNode);
 319     }
 320 
 321     @Override
 322     public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
 323         return new RuntimeNode(binaryNode);
 324     }
 325 


 594         /*
 595          * Now that the transform is done, we have to go into the try and splice
 596          * the finally block in front of any statement that is outside the try
 597          */
 598         return (TryNode)lc.replace(tryNode, spliceFinally(newTryNode, rethrows.get(0), finallyBody));
 599     }
 600 
 601     private TryNode ensureUnconditionalCatch(final TryNode tryNode) {
 602         final List<CatchNode> catches = tryNode.getCatches();
 603         if(catches == null || catches.isEmpty() || catches.get(catches.size() - 1).getExceptionCondition() == null) {
 604             return tryNode;
 605         }
 606         // If the last catch block is conditional, add an unconditional rethrow block
 607         final List<Block> newCatchBlocks = new ArrayList<>(tryNode.getCatchBlocks());
 608 
 609         newCatchBlocks.add(catchAllBlock(tryNode));
 610         return tryNode.setCatchBlocks(lc, newCatchBlocks);
 611     }
 612 
 613     @Override
 614     public boolean enterUnaryNode(final UnaryNode unaryNode) {
 615         if (es6) {
 616             if (unaryNode.isTokenType(TokenType.YIELD) ||
 617                 unaryNode.isTokenType(TokenType.YIELD_STAR)) {
 618                 throwNotImplementedYet("es6.yield", unaryNode);
 619             } else if (unaryNode.isTokenType(TokenType.SPREAD_ARGUMENT) ||
 620                        unaryNode.isTokenType(TokenType.SPREAD_ARRAY)) {
 621                 throwNotImplementedYet("es6.spread", unaryNode);
 622             }
 623         }
 624 
 625         return super.enterUnaryNode(unaryNode);
 626     }
 627 
 628     @Override
 629     public Node leaveVarNode(final VarNode varNode) {
 630         addStatement(varNode);
 631         if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION)
 632                 && lc.getCurrentFunction().isProgram()
 633                 && ((FunctionNode) varNode.getInit()).isAnonymous()) {
 634             new ExpressionStatement(varNode.getLineNumber(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this);
 635         }
 636         return varNode;
 637     }
 638 
 639     @Override
 640     public Node leaveWhileNode(final WhileNode whileNode) {
 641         final Expression test = whileNode.getTest();
 642         final Block body = whileNode.getBody();
 643 
 644         if (isAlwaysTrue(test)) {
 645             //turn it into a for node without a test.
 646             final ForNode forNode = (ForNode)new ForNode(whileNode.getLineNumber(), whileNode.getToken(), whileNode.getFinish(), body, 0).accept(this);
 647             lc.replace(whileNode, forNode);
 648             return forNode;
 649         }
 650 
 651          return addStatement(checkEscape(whileNode));
 652     }
 653 
 654     @Override
 655     public Node leaveWithNode(final WithNode withNode) {
 656         return addStatement(withNode);
 657     }
 658 
 659     @Override
 660     public boolean enterClassNode(final ClassNode classNode) {
 661         throwNotImplementedYet("es6.class", classNode);
 662         return super.enterClassNode(classNode);
 663     }
 664 
 665     /**
 666      * Given a function node that is a callee in a CallNode, replace it with
 667      * the appropriate marker function. This is used by {@link CodeGenerator}
 668      * for fast scope calls
 669      *
 670      * @param function function called by a CallNode
 671      * @return transformed node to marker function or identity if not ident/access/indexnode
 672      */
 673     private static Expression markerFunction(final Expression function) {
 674         if (function instanceof IdentNode) {
 675             return ((IdentNode)function).setIsFunction();
 676         } else if (function instanceof BaseNode) {
 677             return ((BaseNode)function).setIsFunction();
 678         }
 679         return function;
 680     }
 681 
 682     /**
 683      * Calculate a synthetic eval location for a node for the stacktrace, for example src#17<eval>
 684      * @param node a node


 802         final Symbol symbol = ((IdentNode)expression).getSymbol();
 803         return symbol != null && symbol.isInternal();
 804     }
 805 
 806     /**
 807      * Is this an assignment to the special variable that hosts scripting eval
 808      * results, i.e. __return__?
 809      *
 810      * @param expression expression to check whether it is $evalresult = X
 811      * @return true if an assignment to eval result, false otherwise
 812      */
 813     private static boolean isEvalResultAssignment(final Node expression) {
 814         final Node e = expression;
 815         if (e instanceof BinaryNode) {
 816             final Node lhs = ((BinaryNode)e).lhs();
 817             if (lhs instanceof IdentNode) {
 818                 return ((IdentNode)lhs).getName().equals(RETURN.symbolName());
 819             }
 820         }
 821         return false;
 822     }
 823 
 824     private void throwNotImplementedYet(final String msgId, final Node node) {
 825         final long token = node.getToken();
 826         final int line = source.getLine(node.getStart());
 827         final int column = source.getColumn(node.getStart());
 828         final String message = ECMAErrors.getMessage("unimplemented." + msgId);
 829         final String formatted = ErrorManager.format(message, source, line, column, token);
 830         throw new RuntimeException(formatted);
 831     }
 832 }
< prev index next >