in AjaxMinDll/JavaScript/EvaluateLiteralVisitor.cs [400:547]
private void EvalToTheLeft(BinaryOperator node, ConstantWrapper thisConstant, ConstantWrapper otherConstant, BinaryOperator leftOperator)
{
if (leftOperator.OperatorToken == JSToken.Plus && node.OperatorToken == JSToken.Plus)
{
// plus-plus
// the other operation goes first, so if the other constant is a string, then we know that
// operation will do a string concatenation, which will force our operation to be a string
// concatenation. If the other constant is not a string, then we won't know until runtime and
// we can't combine them.
if (otherConstant.IsStringLiteral)
{
// the other constant is a string -- so we can do the string concat and combine them
ConstantWrapper newLiteral = StringConcat(otherConstant, thisConstant);
if (newLiteral != null)
{
RotateFromLeft(node, leftOperator, newLiteral);
}
}
}
else if (leftOperator.OperatorToken == JSToken.Minus)
{
if (node.OperatorToken == JSToken.Plus)
{
// minus-plus
// the minus operator goes first and will always convert to number.
// if our constant is not a string, then it will be a numeric addition and we can combine them.
// if our constant is a string, then we'll end up doing a string concat, so we can't combine
if (!thisConstant.IsStringLiteral)
{
// two numeric operators. a-n1+n2 is the same as a-(n1-n2)
ConstantWrapper newLiteral = Minus(otherConstant, thisConstant);
if (newLiteral != null && NoOverflow(newLiteral))
{
// a-(-n) is numerically equivalent as a+n -- and takes fewer characters to represent.
// BUT we can't do that because that might change a numeric operation (the original minus)
// to a string concatenation if the unknown operand turns out to be a string!
RotateFromLeft(node, leftOperator, newLiteral);
}
else
{
// if the left-left is a constant, then we can try combining with it
ConstantWrapper leftLeft = leftOperator.Operand1 as ConstantWrapper;
if (leftLeft != null)
{
EvalFarToTheLeft(node, thisConstant, leftLeft, leftOperator);
}
}
}
}
else if (node.OperatorToken == JSToken.Minus)
{
// minus-minus. Both operations are numeric.
// (a-n1)-n2 => a-(n1+n2), so we can add the two constants and subtract from
// the left-hand non-constant.
ConstantWrapper newLiteral = NumericAddition(otherConstant, thisConstant);
if (newLiteral != null && NoOverflow(newLiteral))
{
// make it the new right-hand literal for the left-hand operator
// and make the left-hand operator replace our operator
RotateFromLeft(node, leftOperator, newLiteral);
}
else
{
// if the left-left is a constant, then we can try combining with it
ConstantWrapper leftLeft = leftOperator.Operand1 as ConstantWrapper;
if (leftLeft != null)
{
EvalFarToTheLeft(node, thisConstant, leftLeft, leftOperator);
}
}
}
}
else if (leftOperator.OperatorToken == node.OperatorToken
&& (node.OperatorToken == JSToken.Multiply || node.OperatorToken == JSToken.Divide))
{
// either multiply-multiply or divide-divide
// either way, we use the other operand and the product of the two constants.
// if the product blows up to an infinte value, then don't combine them because that
// could change the way the program goes at runtime, depending on the unknown value.
ConstantWrapper newLiteral = Multiply(otherConstant, thisConstant);
if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral))
{
RotateFromLeft(node, leftOperator, newLiteral);
}
}
else if ((leftOperator.OperatorToken == JSToken.Multiply && node.OperatorToken == JSToken.Divide)
|| (leftOperator.OperatorToken == JSToken.Divide && node.OperatorToken == JSToken.Multiply))
{
if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
{
// get the two division operators
ConstantWrapper otherOverThis = Divide(otherConstant, thisConstant);
ConstantWrapper thisOverOther = Divide(thisConstant, otherConstant);
// get the lengths
int otherOverThisLength = otherOverThis != null ? NodeLength(otherOverThis) : int.MaxValue;
int thisOverOtherLength = thisOverOther != null ? NodeLength(thisOverOther) : int.MaxValue;
// we'll want to use whichever one is shorter, and whichever one does NOT involve an overflow
// or possible underflow
if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis)
&& (thisOverOther == null || otherOverThisLength < thisOverOtherLength))
{
// but only if it's smaller than the original expression
if (otherOverThisLength <= NodeLength(otherConstant) + NodeLength(thisConstant) + 1)
{
// same operator
RotateFromLeft(node, leftOperator, otherOverThis);
}
}
else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther))
{
// but only if it's smaller than the original expression
if (thisOverOtherLength <= NodeLength(otherConstant) + NodeLength(thisConstant) + 1)
{
// opposite operator
leftOperator.OperatorToken = leftOperator.OperatorToken == JSToken.Multiply ? JSToken.Divide : JSToken.Multiply;
RotateFromLeft(node, leftOperator, thisOverOther);
}
}
}
}
else if (node.OperatorToken == leftOperator.OperatorToken
&& (node.OperatorToken == JSToken.BitwiseAnd || node.OperatorToken == JSToken.BitwiseOr || node.OperatorToken == JSToken.BitwiseXor))
{
// identical bitwise operators can be combined
ConstantWrapper newLiteral = null;
switch (node.OperatorToken)
{
case JSToken.BitwiseAnd:
newLiteral = BitwiseAnd(otherConstant, thisConstant);
break;
case JSToken.BitwiseOr:
newLiteral = BitwiseOr(otherConstant, thisConstant);
break;
case JSToken.BitwiseXor:
newLiteral = BitwiseXor(otherConstant, thisConstant);
break;
}
if (newLiteral != null)
{
RotateFromLeft(node, leftOperator, newLiteral);
}
}
}