public override void Visit(IfNode node) { if (node != null) { if (m_parser.Settings.StripDebugStatements && m_parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements)) { if (node.TrueBlock != null && node.TrueBlock.IsDebuggerStatement) { node.ReplaceChild(node.TrueBlock, null); } if (node.FalseBlock != null && node.FalseBlock.IsDebuggerStatement) { node.ReplaceChild(node.FalseBlock, null); } } // recurse.... base.Visit(node); // now check to see if the two branches are now empty. // if they are, null them out. if (node.TrueBlock != null && node.TrueBlock.Count == 0) { node.ReplaceChild(node.TrueBlock, null); } if (node.FalseBlock != null && node.FalseBlock.Count == 0) { node.ReplaceChild(node.FalseBlock, null); } // if there is no true branch but a false branch, then // put a not on the condition and move the false branch to the true branch. if (node.TrueBlock == null && node.FalseBlock != null && m_parser.Settings.IsModificationAllowed(TreeModifications.IfConditionFalseToIfNotConditionTrue)) { // logical-not the condition var logicalNot = new LogicalNot(node.Condition, m_parser); logicalNot.Apply(); // and swap the branches node.SwapBranches(); } else if (node.TrueBlock != null && node.FalseBlock != null) { // see if logical-notting the condition produces something smaller var logicalNot = new LogicalNot(node.Condition, m_parser); if (logicalNot.Measure() < 0) { // it does -- not the condition and swap the branches logicalNot.Apply(); node.SwapBranches(); } // see if the true- and false-branches each contain only a single statement if (node.TrueBlock.Count == 1 && node.FalseBlock.Count == 1) { // they do -- see if the true-branch's statement is a return-statement var trueReturn = node.TrueBlock[0] as ReturnNode; if (trueReturn != null && trueReturn.Operand != null) { // it is -- see if the false-branch is also a return statement var falseReturn = node.FalseBlock[0] as ReturnNode; if (falseReturn != null && falseReturn.Operand != null) { // transform: if(cond)return expr1;else return expr2 to return cond?expr1:expr2 var conditional = new Conditional(null, m_parser, node.Condition, trueReturn.Operand, falseReturn.Operand); // create a new return node from the conditional and replace // our if-node with it var returnNode = new ReturnNode( node.Context, m_parser, conditional); node.Parent.ReplaceChild( node, returnNode); Optimize(conditional); } } } } else if (node.TrueBlock == null && node.FalseBlock == null && m_parser.Settings.IsModificationAllowed(TreeModifications.IfEmptyToExpression)) { // NEITHER branches have anything now! // something we can do in the future: as long as the condition doesn't // contain calls or assignments, we should be able to completely delete // the statement altogether rather than changing it to an expression // statement on the condition. // I'm just not doing it yet because I don't // know what the effect will be on the iteration of block statements. // if we're on item, 5, for instance, and we delete it, will the next // item be item 6, or will it return the NEW item 5 (since the old item // 5 was deleted and everything shifted up)? // We don't know what it is and what the side-effects may be, so // just change this statement into an expression statement by replacing us with // the expression node.Parent.ReplaceChild(node, node.Condition); // no need to analyze -- we already recursed } // if the true block is not empty, but it's an expression, there are a couple more // optimizations we can make if (node.TrueBlock != null && node.TrueBlock.IsExpression && m_parser.Settings.IsModificationAllowed(TreeModifications.IfExpressionsToExpression)) { if (node.FalseBlock != null && node.FalseBlock.IsExpression) { // if this statement has both true and false blocks, and they are both expressions, // then we can simplify this to a conditional expression. // because the blocks are expressions, we know they only have ONE statement in them, // so we can just dereference them directly. Conditional conditional; var logicalNot = new LogicalNot(node.Condition, m_parser); if (logicalNot.Measure() < 0) { // applying a logical-not makes the condition smaller -- reverse the branches logicalNot.Apply(); conditional = new Conditional( node.Context, m_parser, node.Condition, node.FalseBlock[0], node.TrueBlock[0]); } else { // regular order conditional = new Conditional( node.Context, m_parser, node.Condition, node.TrueBlock[0], node.FalseBlock[0]); } node.Parent.ReplaceChild( node, conditional); Optimize(conditional); } else if (node.FalseBlock == null && m_parser.Settings.IsModificationAllowed(TreeModifications.IfConditionCallToConditionAndCall)) { // but first -- which operator to use? if(a)b --> a&&b, and if(!a)b --> a||b // so determine which one is smaller: a or !a // assume we'll use the logical-and, since that doesn't require changing the condition var newOperator = JSToken.LogicalAnd; var logicalNot = new LogicalNot(node.Condition, m_parser); if (logicalNot.Measure() < 0) { // !a is smaller, so apply it and use the logical-or operator logicalNot.Apply(); newOperator = JSToken.LogicalOr; } // because the true block is an expression, we know it must only have // ONE statement in it, so we can just dereference it directly. var binaryOp = new BinaryOperator( node.Context, m_parser, node.Condition, node.TrueBlock[0], newOperator ); // we don't need to analyse this new node because we've already analyzed // the pieces parts as part of the if. And this visitor's method for the BinaryOperator // doesn't really do anything else. Just replace our current node with this // new node node.Parent.ReplaceChild(node, binaryOp); } } } }
public override void Visit(IfNode node) { if (node != null) { // depth-first base.Visit(node); if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions)) { // if the if-condition is a constant, we can eliminate one of the two branches ConstantWrapper constantCondition = node.Condition as ConstantWrapper; if (constantCondition != null) { // instead, replace the condition with a 1 if it's always true or a 0 if it's always false if (constantCondition.IsNotOneOrPositiveZero) { try { node.ReplaceChild(node.Condition, new ConstantWrapper(constantCondition.ToBoolean() ? 1 : 0, PrimitiveType.Number, node.Condition.Context, m_parser)); } catch (InvalidCastException) { // ignore any invalid cast exceptions } } } } } }