You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			545 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			545 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | using System; | ||
|  | using System.CodeDom; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Diagnostics; | ||
|  | using System.Globalization; | ||
|  | using System.Reflection; | ||
|  | using System.Text; | ||
|  | using System.Workflow.ComponentModel; | ||
|  | 
 | ||
|  | namespace System.Workflow.Activities.Rules | ||
|  | { | ||
|  |     internal static class RuleDecompiler | ||
|  |     { | ||
|  |         #region Decompile literals | ||
|  | 
 | ||
|  |         internal static void DecompileObjectLiteral(StringBuilder decompilation, object primitiveValue) | ||
|  |         { | ||
|  |             if (primitiveValue == null) | ||
|  |             { | ||
|  |                 decompilation.Append("null"); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 Type primitiveType = primitiveValue.GetType(); | ||
|  | 
 | ||
|  |                 if (primitiveType == typeof(string)) | ||
|  |                     DecompileStringLiteral(decompilation, (string)primitiveValue); | ||
|  |                 else if (primitiveType == typeof(char)) | ||
|  |                     DecompileCharacterLiteral(decompilation, (char)primitiveValue); | ||
|  |                 else if (primitiveType == typeof(long)) | ||
|  |                     DecompileSuffixedIntegerLiteral(decompilation, primitiveValue, "L"); | ||
|  |                 else if (primitiveType == typeof(uint)) | ||
|  |                     DecompileSuffixedIntegerLiteral(decompilation, primitiveValue, "U"); | ||
|  |                 else if (primitiveType == typeof(ulong)) | ||
|  |                     DecompileSuffixedIntegerLiteral(decompilation, primitiveValue, "UL"); | ||
|  |                 else if (primitiveType == typeof(float)) | ||
|  |                     DecompileFloatingPointLiteral(decompilation, primitiveValue, 'f'); | ||
|  |                 else if (primitiveType == typeof(double)) | ||
|  |                     DecompileFloatingPointLiteral(decompilation, primitiveValue, 'd'); | ||
|  |                 else if (primitiveType == typeof(decimal)) | ||
|  |                     DecompileFloatingPointLiteral(decompilation, primitiveValue, 'm'); | ||
|  |                 else | ||
|  |                     decompilation.Append(primitiveValue.ToString()); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void DecompileFloatingPointLiteral(StringBuilder decompilation, object value, char suffix) | ||
|  |         { | ||
|  |             // Make sure decimal point isn't converted to a comma in European locales. | ||
|  |             string svalue = Convert.ToString(value, CultureInfo.InvariantCulture); | ||
|  |             decompilation.Append(svalue); | ||
|  | 
 | ||
|  |             if (suffix == 'd') | ||
|  |             { | ||
|  |                 // Don't append 'd' suffixes, they're ugly.  Only if the string-ified value contains | ||
|  |                 // no decimal and no exponent do we need to append a ".0" to make it a double (as | ||
|  |                 // opposed to an integer). | ||
|  | 
 | ||
|  |                 bool hasDecimal = svalue.IndexOf('.') >= 0; | ||
|  |                 bool hasExponent = svalue.IndexOfAny(new char[] { 'e', 'E' }) >= 0; | ||
|  | 
 | ||
|  |                 if (!hasDecimal && !hasExponent) | ||
|  |                     decompilation.Append(".0"); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 decompilation.Append(suffix); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void DecompileSuffixedIntegerLiteral(StringBuilder decompilation, object value, string suffix) | ||
|  |         { | ||
|  |             decompilation.Append(value.ToString()); | ||
|  |             decompilation.Append(suffix); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void DecompileStringLiteral(StringBuilder decompilation, string strValue) | ||
|  |         { | ||
|  |             decompilation.Append("\""); | ||
|  |             for (int i = 0; i < strValue.Length; ++i) | ||
|  |             { | ||
|  |                 char c = strValue[i]; | ||
|  | 
 | ||
|  |                 // is this character a surrogate pair? | ||
|  |                 if ((char.IsHighSurrogate(c)) && (i + 1 < strValue.Length) && (char.IsLowSurrogate(strValue[i + 1]))) | ||
|  |                 { | ||
|  |                     // yes, so leave the two characters unchanged | ||
|  |                     decompilation.Append(c); | ||
|  |                     ++i; | ||
|  |                     decompilation.Append(strValue[i]); | ||
|  |                 } | ||
|  |                 else | ||
|  |                     AppendCharacter(decompilation, c, '"'); | ||
|  |             } | ||
|  |             decompilation.Append("\""); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void DecompileCharacterLiteral(StringBuilder decompilation, char charValue) | ||
|  |         { | ||
|  |             decompilation.Append("'"); | ||
|  |             AppendCharacter(decompilation, charValue, '\''); | ||
|  |             decompilation.Append("'"); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void AppendCharacter(StringBuilder decompilation, char charValue, char quoteCharacter) | ||
|  |         { | ||
|  |             if (charValue == quoteCharacter) | ||
|  |             { | ||
|  |                 decompilation.Append("\\"); | ||
|  |                 decompilation.Append(quoteCharacter); | ||
|  |             } | ||
|  |             else if (charValue == '\\') | ||
|  |             { | ||
|  |                 decompilation.Append("\\\\"); | ||
|  |             } | ||
|  |             else if ((charValue >= ' ' && charValue < '\u007f') || char.IsLetterOrDigit(charValue) || char.IsPunctuation(charValue)) | ||
|  |             { | ||
|  |                 decompilation.Append(charValue); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 string escapeSequence = null; | ||
|  |                 switch (charValue) | ||
|  |                 { | ||
|  |                     case '\0': | ||
|  |                         escapeSequence = "\\0"; | ||
|  |                         break; | ||
|  |                     case '\n': | ||
|  |                         escapeSequence = "\\n"; | ||
|  |                         break; | ||
|  |                     case '\r': | ||
|  |                         escapeSequence = "\\r"; | ||
|  |                         break; | ||
|  |                     case '\b': | ||
|  |                         escapeSequence = "\\b"; | ||
|  |                         break; | ||
|  |                     case '\a': | ||
|  |                         escapeSequence = "\\a"; | ||
|  |                         break; | ||
|  |                     case '\t': | ||
|  |                         escapeSequence = "\\t"; | ||
|  |                         break; | ||
|  |                     case '\f': | ||
|  |                         escapeSequence = "\\f"; | ||
|  |                         break; | ||
|  |                     case '\v': | ||
|  |                         escapeSequence = "\\v"; | ||
|  |                         break; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (escapeSequence != null) | ||
|  |                 { | ||
|  |                     decompilation.Append(escapeSequence); | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     decompilation.Append("\\u"); | ||
|  | 
 | ||
|  |                     UInt16 cv = (UInt16)charValue; | ||
|  |                     for (int i = 12; i >= 0; i -= 4) | ||
|  |                     { | ||
|  |                         int mask = 0xF << i; | ||
|  |                         byte c = (byte)((cv & mask) >> i); | ||
|  |                         decompilation.Append("0123456789ABCDEF"[c]); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         #endregion | ||
|  | 
 | ||
|  |         #region Type decompilation | ||
|  | 
 | ||
|  |         internal static string DecompileType(Type type) | ||
|  |         { | ||
|  |             if (type == null) | ||
|  |                 return string.Empty; | ||
|  | 
 | ||
|  |             StringBuilder sb = new StringBuilder(); | ||
|  |             DecompileType_Helper(sb, type); | ||
|  |             return sb.ToString(); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void DecompileType_Helper(StringBuilder decompilation, Type type) | ||
|  |         { | ||
|  |             int i; | ||
|  | 
 | ||
|  |             if (type.HasElementType) | ||
|  |             { | ||
|  |                 DecompileType_Helper(decompilation, type.GetElementType()); | ||
|  | 
 | ||
|  |                 if (type.IsArray) | ||
|  |                 { | ||
|  |                     decompilation.Append("["); | ||
|  |                     decompilation.Append(',', type.GetArrayRank() - 1); | ||
|  |                     decompilation.Append("]"); | ||
|  |                 } | ||
|  |                 else if (type.IsByRef) | ||
|  |                 { | ||
|  |                     decompilation.Append('&'); | ||
|  |                 } | ||
|  |                 else if (type.IsPointer) | ||
|  |                 { | ||
|  |                     decompilation.Append('*'); | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 string typeName = type.FullName; | ||
|  |                 if (typeName == null) // Full name may be null for an unbound generic. | ||
|  |                     typeName = type.Name; | ||
|  | 
 | ||
|  |                 typeName = UnmangleTypeName(typeName); | ||
|  |                 decompilation.Append(typeName); | ||
|  | 
 | ||
|  |                 if (type.IsGenericType) | ||
|  |                 { | ||
|  |                     decompilation.Append("<"); | ||
|  | 
 | ||
|  |                     Type[] typeArgs = type.GetGenericArguments(); | ||
|  | 
 | ||
|  |                     DecompileType_Helper(decompilation, typeArgs[0]); // decompile the first type arg | ||
|  |                     for (i = 1; i < typeArgs.Length; ++i) | ||
|  |                     { | ||
|  |                         decompilation.Append(", "); | ||
|  |                         DecompileType_Helper(decompilation, typeArgs[i]); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     decompilation.Append(">"); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         internal static void DecompileType(StringBuilder decompilation, CodeTypeReference typeRef) | ||
|  |         { | ||
|  |             // Remove any back-tick decorations on generic types, if present. | ||
|  |             string baseType = UnmangleTypeName(typeRef.BaseType); | ||
|  |             decompilation.Append(baseType); | ||
|  | 
 | ||
|  |             if (typeRef.TypeArguments != null && typeRef.TypeArguments.Count > 0) | ||
|  |             { | ||
|  |                 decompilation.Append("<"); | ||
|  | 
 | ||
|  |                 bool first = true; | ||
|  |                 foreach (CodeTypeReference argTypeRef in typeRef.TypeArguments) | ||
|  |                 { | ||
|  |                     if (!first) | ||
|  |                         decompilation.Append(", "); | ||
|  |                     first = false; | ||
|  | 
 | ||
|  |                     DecompileType(decompilation, argTypeRef); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 decompilation.Append(">"); | ||
|  |             } | ||
|  | 
 | ||
|  |             if (typeRef.ArrayRank > 0) | ||
|  |             { | ||
|  |                 do | ||
|  |                 { | ||
|  |                     decompilation.Append("["); | ||
|  |                     for (int i = 1; i < typeRef.ArrayRank; ++i) | ||
|  |                         decompilation.Append(","); | ||
|  |                     decompilation.Append("]"); | ||
|  | 
 | ||
|  |                     typeRef = typeRef.ArrayElementType; | ||
|  |                 } while (typeRef.ArrayRank > 0); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Dictionary<string, string> knownTypeMap = InitializeKnownTypeMap(); | ||
|  | 
 | ||
|  |         private static Dictionary<string, string> InitializeKnownTypeMap() | ||
|  |         { | ||
|  |             Dictionary<string, string> map = new Dictionary<string, string>(); | ||
|  |             map.Add("System.Char", "char"); | ||
|  |             map.Add("System.Byte", "byte"); | ||
|  |             map.Add("System.SByte", "sbyte"); | ||
|  |             map.Add("System.Int16", "short"); | ||
|  |             map.Add("System.UInt16", "ushort"); | ||
|  |             map.Add("System.Int32", "int"); | ||
|  |             map.Add("System.UInt32", "uint"); | ||
|  |             map.Add("System.Int64", "long"); | ||
|  |             map.Add("System.UInt64", "ulong"); | ||
|  |             map.Add("System.Single", "float"); | ||
|  |             map.Add("System.Double", "double"); | ||
|  |             map.Add("System.Decimal", "decimal"); | ||
|  |             map.Add("System.Boolean", "bool"); | ||
|  |             map.Add("System.String", "string"); | ||
|  |             map.Add("System.Object", "object"); | ||
|  |             map.Add("System.Void", "void"); | ||
|  |             return map; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static string TryReplaceKnownTypes(string typeName) | ||
|  |         { | ||
|  |             string newTypeName = null; | ||
|  |             if (!knownTypeMap.TryGetValue(typeName, out newTypeName)) | ||
|  |                 newTypeName = typeName; | ||
|  |             return newTypeName; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static string UnmangleTypeName(string typeName) | ||
|  |         { | ||
|  |             int tickIndex = typeName.IndexOf('`'); | ||
|  |             if (tickIndex > 0) | ||
|  |                 typeName = typeName.Substring(0, tickIndex); | ||
|  | 
 | ||
|  |             // Replace the '+' for a nested type with a '.' | ||
|  |             typeName = typeName.Replace('+', '.'); | ||
|  | 
 | ||
|  |             typeName = TryReplaceKnownTypes(typeName); | ||
|  | 
 | ||
|  |             return typeName; | ||
|  |         } | ||
|  | 
 | ||
|  |         #endregion | ||
|  | 
 | ||
|  |         #region Method decompilation | ||
|  | 
 | ||
|  |         internal static string DecompileMethod(MethodInfo method) | ||
|  |         { | ||
|  |             if (method == null) | ||
|  |                 return string.Empty; | ||
|  | 
 | ||
|  |             StringBuilder sb = new StringBuilder(); | ||
|  |             string operatorName; | ||
|  |             DecompileType_Helper(sb, method.DeclaringType); | ||
|  |             sb.Append('.'); | ||
|  |             if (knownOperatorMap.TryGetValue(method.Name, out operatorName)) | ||
|  |                 sb.Append(operatorName); | ||
|  |             else | ||
|  |                 sb.Append(method.Name); | ||
|  |             sb.Append('('); | ||
|  |             ParameterInfo[] parms = method.GetParameters(); | ||
|  |             for (int i = 0; i < parms.Length; ++i) | ||
|  |             { | ||
|  |                 DecompileType_Helper(sb, parms[i].ParameterType); | ||
|  |                 if (i != parms.Length - 1) | ||
|  |                     sb.Append(", "); | ||
|  |             } | ||
|  |             sb.Append(')'); | ||
|  |             return sb.ToString(); | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Dictionary<string, string> knownOperatorMap = InitializeKnownOperatorMap(); | ||
|  | 
 | ||
|  |         private static Dictionary<string, string> InitializeKnownOperatorMap() | ||
|  |         { | ||
|  |             Dictionary<string, string> map = new Dictionary<string, string>(27); | ||
|  | 
 | ||
|  |             // unary operators | ||
|  |             map.Add("op_UnaryPlus", "operator +"); | ||
|  |             map.Add("op_UnaryNegation", "operator -"); | ||
|  |             map.Add("op_OnesComplement", "operator ~"); | ||
|  |             map.Add("op_LogicalNot", "operator !"); | ||
|  |             map.Add("op_Increment", "operator ++"); | ||
|  |             map.Add("op_Decrement", "operator --"); | ||
|  |             map.Add("op_True", "operator true"); | ||
|  |             map.Add("op_False", "operator false"); | ||
|  |             map.Add("op_Implicit", "implicit operator"); | ||
|  |             map.Add("op_Explicit", "explicit operator"); | ||
|  | 
 | ||
|  |             // binary operators | ||
|  |             map.Add("op_Equality", "operator =="); | ||
|  |             map.Add("op_Inequality", "operator !="); | ||
|  |             map.Add("op_GreaterThan", "operator >"); | ||
|  |             map.Add("op_GreaterThanOrEqual", "operator >="); | ||
|  |             map.Add("op_LessThan", "operator <"); | ||
|  |             map.Add("op_LessThanOrEqual", "operator <="); | ||
|  |             map.Add("op_Addition", "operator +"); | ||
|  |             map.Add("op_Subtraction", "operator -"); | ||
|  |             map.Add("op_Multiply", "operator *"); | ||
|  |             map.Add("op_Division", "operator /"); | ||
|  |             map.Add("op_IntegerDivision", "operator \\"); | ||
|  |             map.Add("op_Modulus", "operator %"); | ||
|  |             map.Add("op_LeftShift", "operator <<"); | ||
|  |             map.Add("op_RightShift", "operator >>"); | ||
|  |             map.Add("op_BitwiseAnd", "operator &"); | ||
|  |             map.Add("op_BitwiseOr", "operator |"); | ||
|  |             map.Add("op_ExclusiveOr", "operator ^"); | ||
|  |             return map; | ||
|  |         } | ||
|  |         #endregion | ||
|  | 
 | ||
|  |         #region Operator Precedence | ||
|  | 
 | ||
|  |         // These operations are sorted in order of precedence, lowest-to-highest | ||
|  |         private enum Operation | ||
|  |         { | ||
|  |             RootExpression, | ||
|  |             LogicalOr,          // || | ||
|  |             LogicalAnd,         // && | ||
|  |             BitwiseOr,          // | | ||
|  |             BitwiseAnd,         // & | ||
|  |             Equality,           // ==  != | ||
|  |             Comparitive,        // <  <=  >  >= | ||
|  |             Additive,           // +  - | ||
|  |             Multiplicative,     // *  /  % | ||
|  |             Unary,              // -  !  (cast) | ||
|  |             Postfix,            // field/property ref and method call | ||
|  |             NoParentheses       // Highest | ||
|  |         } | ||
|  | 
 | ||
|  |         private delegate Operation ComputePrecedence(CodeExpression expresssion); | ||
|  | 
 | ||
|  |         private static Dictionary<Type, ComputePrecedence> precedenceMap = InitializePrecedenceMap(); | ||
|  | 
 | ||
|  | 
 | ||
|  |         private static Dictionary<Type, ComputePrecedence> InitializePrecedenceMap() | ||
|  |         { | ||
|  |             Dictionary<Type, ComputePrecedence> map = new Dictionary<Type, ComputePrecedence>(7); | ||
|  |             map.Add(typeof(CodeBinaryOperatorExpression), GetBinaryPrecedence); | ||
|  |             map.Add(typeof(CodeCastExpression), GetCastPrecedence); | ||
|  |             map.Add(typeof(CodeFieldReferenceExpression), GetPostfixPrecedence); | ||
|  |             map.Add(typeof(CodePropertyReferenceExpression), GetPostfixPrecedence); | ||
|  |             map.Add(typeof(CodeMethodInvokeExpression), GetPostfixPrecedence); | ||
|  |             map.Add(typeof(CodeObjectCreateExpression), GetPostfixPrecedence); | ||
|  |             map.Add(typeof(CodeArrayCreateExpression), GetPostfixPrecedence); | ||
|  |             return map; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Operation GetPostfixPrecedence(CodeExpression expression) | ||
|  |         { | ||
|  |             return Operation.Postfix; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Operation GetCastPrecedence(CodeExpression expression) | ||
|  |         { | ||
|  |             return Operation.Unary; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Operation GetBinaryPrecedence(CodeExpression expression) | ||
|  |         { | ||
|  |             CodeBinaryOperatorExpression binaryExpr = (CodeBinaryOperatorExpression)expression; | ||
|  | 
 | ||
|  |             Operation operation = Operation.NoParentheses; | ||
|  |             switch (binaryExpr.Operator) | ||
|  |             { | ||
|  |                 case CodeBinaryOperatorType.Multiply: | ||
|  |                 case CodeBinaryOperatorType.Divide: | ||
|  |                 case CodeBinaryOperatorType.Modulus: | ||
|  |                     operation = Operation.Multiplicative; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.Subtract: | ||
|  |                 case CodeBinaryOperatorType.Add: | ||
|  |                     operation = Operation.Additive; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.LessThan: | ||
|  |                 case CodeBinaryOperatorType.LessThanOrEqual: | ||
|  |                 case CodeBinaryOperatorType.GreaterThan: | ||
|  |                 case CodeBinaryOperatorType.GreaterThanOrEqual: | ||
|  |                     operation = Operation.Comparitive; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.IdentityEquality: | ||
|  |                 case CodeBinaryOperatorType.ValueEquality: | ||
|  |                 case CodeBinaryOperatorType.IdentityInequality: | ||
|  |                     operation = Operation.Equality; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.BitwiseAnd: | ||
|  |                     operation = Operation.BitwiseAnd; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.BitwiseOr: | ||
|  |                     operation = Operation.BitwiseOr; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.BooleanAnd: | ||
|  |                     operation = Operation.LogicalAnd; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 case CodeBinaryOperatorType.BooleanOr: | ||
|  |                     operation = Operation.LogicalOr; | ||
|  |                     break; | ||
|  | 
 | ||
|  |                 default: | ||
|  |                     string message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, binaryExpr.Operator.ToString()); | ||
|  |                     NotSupportedException exception = new NotSupportedException(message); | ||
|  |                     exception.Data[RuleUserDataKeys.ErrorObject] = binaryExpr; | ||
|  |                     throw exception; | ||
|  |             } | ||
|  | 
 | ||
|  |             return operation; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static Operation GetPrecedence(CodeExpression expression) | ||
|  |         { | ||
|  |             // Assume the operation needs no parentheses. | ||
|  |             Operation operation = Operation.NoParentheses; | ||
|  | 
 | ||
|  |             ComputePrecedence computePrecedence; | ||
|  |             if (precedenceMap.TryGetValue(expression.GetType(), out computePrecedence)) | ||
|  |                 operation = computePrecedence(expression); | ||
|  | 
 | ||
|  |             return operation; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal static bool MustParenthesize(CodeExpression childExpr, CodeExpression parentExpr) | ||
|  |         { | ||
|  |             // No parent... we're at the root, so no need to parenthesize the root. | ||
|  |             if (parentExpr == null) | ||
|  |                 return false; | ||
|  | 
 | ||
|  |             Operation childOperation = GetPrecedence(childExpr); | ||
|  |             Operation parentOperation = GetPrecedence(parentExpr); | ||
|  | 
 | ||
|  |             if (parentOperation == childOperation) | ||
|  |             { | ||
|  |                 CodeBinaryOperatorExpression parentBinary = parentExpr as CodeBinaryOperatorExpression; | ||
|  |                 if (parentBinary != null) | ||
|  |                 { | ||
|  |                     if (childExpr == parentBinary.Right) | ||
|  |                     { | ||
|  |                         // Something like 2 - (3 - 4) needs parentheses. | ||
|  |                         return true; | ||
|  |                     } | ||
|  |                     else | ||
|  |                     { | ||
|  |                         // Something like (2 - 3) - 4 doesn't need parentheses. | ||
|  |                         return false; | ||
|  |                     } | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |             } | ||
|  |             else if (parentOperation > childOperation) | ||
|  |             { | ||
|  |                 return true; | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 return false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         #endregion | ||
|  |     } | ||
|  | } |