private void EvalToTheRight(JsBinaryOperator node, JsConstantWrapper thisConstant, JsConstantWrapper otherConstant, JsBinaryOperator rightOperator) { if (node.OperatorToken == JsToken.Plus) { if (rightOperator.OperatorToken == JsToken.Plus && otherConstant.IsStringLiteral) { // plus-plus, and the other constant is a string. So the right operator will be a string-concat // that generates a string. And since this is a plus-operator, then this operator will be a string- // concat as well. So we can just combine the strings now and replace our node with the right-hand // operation JsConstantWrapper newLiteral = StringConcat(thisConstant, otherConstant); if (newLiteral != null) { RotateFromRight(node, rightOperator, newLiteral); } } else if (rightOperator.OperatorToken == JsToken.Minus && !thisConstant.IsStringLiteral) { // plus-minus. Now, the minus operation happens first, and it will perform a numeric // operation. The plus is NOT string, so that means it will also be a numeric operation // and we can combine the operators numericly. JsConstantWrapper newLiteral = NumericAddition(thisConstant, otherConstant); if (newLiteral != null && NoOverflow(newLiteral)) { RotateFromRight(node, rightOperator, newLiteral); } else { JsConstantWrapper rightRight = rightOperator.Operand2 as JsConstantWrapper; if (rightRight != null) { EvalFarToTheRight(node, thisConstant, rightRight, rightOperator); } } } } else if (node.OperatorToken == JsToken.Minus && rightOperator.OperatorToken == JsToken.Minus) { // minus-minus // both operations are numeric, so we can combine the constant operands. However, we // can't combine them into a plus, so make sure we do the minus in the opposite direction JsConstantWrapper newLiteral = Minus(otherConstant, thisConstant); if (newLiteral != null && NoOverflow(newLiteral)) { rightOperator.SwapOperands(); RotateFromLeft(node, rightOperator, newLiteral); } else { JsConstantWrapper rightRight = rightOperator.Operand2 as JsConstantWrapper; if (rightRight != null) { EvalFarToTheRight(node, thisConstant, rightRight, rightOperator); } } } else if (node.OperatorToken == JsToken.Multiply && (rightOperator.OperatorToken == JsToken.Multiply || rightOperator.OperatorToken == JsToken.Divide)) { // multiply-divide or multiply-multiply // multiply the operands and use the right-hand operator JsConstantWrapper newLiteral = Multiply(thisConstant, otherConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral)) { RotateFromRight(node, rightOperator, newLiteral); } } else if (node.OperatorToken == JsToken.Divide) { if (rightOperator.OperatorToken == JsToken.Multiply) { // divide-multiply JsConstantWrapper newLiteral = Divide(thisConstant, otherConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral) && newLiteral.ToCode().Length < thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // flip the operator: multiply becomes divide; devide becomes multiply rightOperator.OperatorToken = JsToken.Divide; RotateFromRight(node, rightOperator, newLiteral); } } else if (rightOperator.OperatorToken == JsToken.Divide) { // divide-divide // get constants for left/right and for right/left JsConstantWrapper leftOverRight = Divide(thisConstant, otherConstant); JsConstantWrapper rightOverLeft = Divide(otherConstant, thisConstant); // get the lengths of the resulting code int leftOverRightLength = leftOverRight != null ? leftOverRight.ToCode().Length : int.MaxValue; int rightOverLeftLength = rightOverLeft != null ? rightOverLeft.ToCode().Length : int.MaxValue; // try whichever is smaller if (leftOverRight != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, leftOverRight) && (rightOverLeft == null || leftOverRightLength < rightOverLeftLength)) { // use left-over-right. // but only if the resulting value is smaller than the original expression if (leftOverRightLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // We don't need to swap the operands, but we do need to switch the operator rightOperator.OperatorToken = JsToken.Multiply; RotateFromRight(node, rightOperator, leftOverRight); } } else if (rightOverLeft != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, rightOverLeft)) { // but only if the resulting value is smaller than the original expression if (rightOverLeftLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // use right-over-left. Keep the operator, but swap the operands rightOperator.SwapOperands(); RotateFromLeft(node, rightOperator, rightOverLeft); } } } } }
private void EvalFarToTheRight(JsBinaryOperator node, JsConstantWrapper thisConstant, JsConstantWrapper otherConstant, JsBinaryOperator rightOperator) { if (rightOperator.OperatorToken == JsToken.Minus) { if (node.OperatorToken == JsToken.Plus) { // plus-minus // our constant cannot be a string, though if (!thisConstant.IsStringLiteral) { JsConstantWrapper newLiteral = Minus(otherConstant, thisConstant); if (newLiteral != null && NoOverflow(newLiteral)) { RotateFromLeft(node, rightOperator, newLiteral); } } } else if (node.OperatorToken == JsToken.Minus) { // minus-minus JsConstantWrapper newLiteral = NumericAddition(thisConstant, otherConstant); if (newLiteral != null && NoOverflow(newLiteral)) { // but we need to swap the left and right operands first rightOperator.SwapOperands(); // then rotate the node up after replacing old with new RotateFromRight(node, rightOperator, newLiteral); } } } else if (node.OperatorToken == JsToken.Multiply) { if (rightOperator.OperatorToken == JsToken.Multiply) { // mult-mult JsConstantWrapper newLiteral = Multiply(thisConstant, otherConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral)) { RotateFromLeft(node, rightOperator, newLiteral); } } else if (rightOperator.OperatorToken == JsToken.Divide) { // mult-divide JsConstantWrapper otherOverThis = Divide(otherConstant, thisConstant); JsConstantWrapper thisOverOther = Divide(thisConstant, otherConstant); int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue; int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : int.MaxValue; if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis) && (thisOverOther == null || otherOverThisLength < thisOverOtherLength)) { if (otherOverThisLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // swap the operands, but keep the operator RotateFromLeft(node, rightOperator, otherOverThis); } } else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther)) { if (thisOverOtherLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // swap the operands and opposite operator rightOperator.SwapOperands(); rightOperator.OperatorToken = JsToken.Multiply; RotateFromRight(node, rightOperator, thisOverOther); } } } } else if (node.OperatorToken == JsToken.Divide) { if (rightOperator.OperatorToken == JsToken.Multiply) { // divide-mult JsConstantWrapper newLiteral = Divide(thisConstant, otherConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral) && newLiteral.ToCode().Length <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // swap the operands rightOperator.SwapOperands(); // change the operator rightOperator.OperatorToken = JsToken.Divide; RotateFromRight(node, rightOperator, newLiteral); } } else if (rightOperator.OperatorToken == JsToken.Divide) { // divide-divide JsConstantWrapper newLiteral = Multiply(thisConstant, otherConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral)) { // but we need to swap the left and right operands first rightOperator.SwapOperands(); // then rotate the node up after replacing old with new RotateFromRight(node, rightOperator, newLiteral); } } } }
private void EvalToTheLeft(JsBinaryOperator node, JsConstantWrapper thisConstant, JsConstantWrapper otherConstant, JsBinaryOperator 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 JsConstantWrapper 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) JsConstantWrapper 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 JsConstantWrapper leftLeft = leftOperator.Operand1 as JsConstantWrapper; 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. JsConstantWrapper 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 JsConstantWrapper leftLeft = leftOperator.Operand1 as JsConstantWrapper; 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. JsConstantWrapper 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(JsTreeModifications.EvaluateNumericExpressions)) { // get the two division operators JsConstantWrapper otherOverThis = Divide(otherConstant, thisConstant); JsConstantWrapper thisOverOther = Divide(thisConstant, otherConstant); // get the lengths int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue; int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : 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 <= otherConstant.ToCode().Length + thisConstant.ToCode().Length + 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 <= otherConstant.ToCode().Length + thisConstant.ToCode().Length + 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 JsConstantWrapper 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); } } }
private void EvalFarToTheLeft(JsBinaryOperator node, JsConstantWrapper thisConstant, JsConstantWrapper otherConstant, JsBinaryOperator leftOperator) { if (leftOperator.OperatorToken == JsToken.Minus) { if (node.OperatorToken == JsToken.Plus) { // minus-plus // the minus will be a numeric operator, but if this constant is a string, it will be a // string concatenation and we can't combine it. if (thisConstant.PrimitiveType != JsPrimitiveType.String && thisConstant.PrimitiveType != JsPrimitiveType.Other) { JsConstantWrapper newLiteral = NumericAddition(otherConstant, thisConstant); if (newLiteral != null && NoOverflow(newLiteral)) { RotateFromRight(node, leftOperator, newLiteral); } } } else if (node.OperatorToken == JsToken.Minus) { // minus-minus JsConstantWrapper newLiteral = Minus(otherConstant, thisConstant); if (newLiteral != null && NoOverflow(newLiteral)) { RotateFromRight(node, leftOperator, newLiteral); } } } else if (node.OperatorToken == JsToken.Multiply) { if (leftOperator.OperatorToken == JsToken.Multiply || leftOperator.OperatorToken == JsToken.Divide) { JsConstantWrapper newLiteral = Multiply(otherConstant, thisConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral)) { RotateFromRight(node, leftOperator, newLiteral); } } } else if (node.OperatorToken == JsToken.Divide) { if (leftOperator.OperatorToken == JsToken.Divide) { // divide-divide JsConstantWrapper newLiteral = Divide(otherConstant, thisConstant); if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral) && newLiteral.ToCode().Length <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { RotateFromRight(node, leftOperator, newLiteral); } } else if (leftOperator.OperatorToken == JsToken.Multiply) { // mult-divide JsConstantWrapper otherOverThis = Divide(otherConstant, thisConstant); JsConstantWrapper thisOverOther = Divide(thisConstant, otherConstant); int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue; int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : int.MaxValue; if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis) && (thisOverOther == null || otherOverThisLength < thisOverOtherLength)) { if (otherOverThisLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { RotateFromRight(node, leftOperator, otherOverThis); } } else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther)) { if (thisOverOtherLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1) { // swap the operands leftOperator.SwapOperands(); // operator is the opposite leftOperator.OperatorToken = JsToken.Divide; RotateFromLeft(node, leftOperator, thisOverOther); } } } } }