From df042aa94989e08df958b04bb6ea2c0d680a8791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Wed, 24 Jun 2009 02:58:16 +0000 Subject: [PATCH] Console: Binary operations git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4352 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Expressions/AstEvaluator.cs | 2 + .../Src/Expressions/EvaluateAstVisitor.cs | 194 ++++++++++++++---- .../Debugger.Core/Project/Src/Control/Eval.cs | 19 ++ .../Project/Src/TestPrograms/AstEval.cs | 53 ++++- 4 files changed, 222 insertions(+), 46 deletions(-) diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs index b8a50c2cba..a4c61e2b86 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs @@ -52,6 +52,8 @@ namespace Debugger.AddIn } sb.Append("}"); return sb.ToString(); + } else if (val.Type.IsPrimitive) { + return val.PrimitiveValue.ToString(); } else { return val.InvokeToString(); } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs index 4971429a7d..32c0368f57 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs @@ -149,15 +149,7 @@ namespace Debugger.AddIn public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { - if (primitiveExpression.Value == null) { - return Eval.CreateValue(context.Process, null); - } else if (primitiveExpression.Value is string) { - return Eval.NewString(context.Process, primitiveExpression.Value as string); - } else { - Value val = Eval.NewObjectNoConstructor(DebugType.Create(context.Process, null, primitiveExpression.Value.GetType().FullName)); - val.PrimitiveValue = primitiveExpression.Value; - return val; - } + return Eval.CreateValue(context.Process, primitiveExpression.Value); } public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data) @@ -170,41 +162,167 @@ namespace Debugger.AddIn Value left = ((Value)binaryOperatorExpression.Left.AcceptVisitor(this, null)).GetPermanentReference(); Value right = ((Value)binaryOperatorExpression.Right.AcceptVisitor(this, null)).GetPermanentReference(); - if (!left.IsReference && left.Type.FullName != right.Type.FullName) { - throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName)); + object result = VisitBinaryOperatorExpressionInternal(left, right, binaryOperatorExpression.Op); + // Conver long to int if possible + if (result is long && int.MinValue <= (long)result && (long)result <= int.MaxValue) result = (int)(long)result; + return Eval.CreateValue(context.Process, result); + } + + public object VisitBinaryOperatorExpressionInternal(Value leftValue, Value rightValue, BinaryOperatorType op) + { + object left = leftValue.Type.IsPrimitive ? leftValue.PrimitiveValue : null; + object right = rightValue.Type.IsPrimitive ? rightValue.PrimitiveValue : null; + + // Both are classes - do reference comparison + if (left == null && right == null) { + if (leftValue.IsNull || rightValue.IsNull) { + return leftValue.IsNull && rightValue.IsNull; + } else { + // TODO: Make sure this works for byrefs and arrays + return leftValue.Address == rightValue.Address; + } } - Value val = Eval.NewObjectNoConstructor(DebugType.Create(context.Process, null, typeof(bool).FullName)); + if (left == null && right != null) { + throw new GetValueException("The left side of binary operation is not primitive value"); + } + + if (left != null && right == null) { + throw new GetValueException("The right side of binary operation is not primitive value"); + } - try { - switch (binaryOperatorExpression.Op) - { - case BinaryOperatorType.Equality : - val.PrimitiveValue = Equals(right.PrimitiveValue, left.PrimitiveValue); - break; - case BinaryOperatorType.InEquality : - val.PrimitiveValue = !Equals(right.PrimitiveValue, left.PrimitiveValue); - break; -// case BinaryOperatorType.Add : -// val.PrimitiveValue = (right.PrimitiveValue.ToString() + left.PrimitiveValue.ToString()); -// break; -// case BinaryOperatorType.GreaterThan : -// val.PrimitiveValue = (right.PrimitiveValue > left.PrimitiveValue); -// break; -// case BinaryOperatorType.LessThanOrEqual : -// val.PrimitiveValue = (right.PrimitiveValue <= left.PrimitiveValue); -// break; -// case BinaryOperatorType.GreaterThanOrEqual : -// val.PrimitiveValue = (right.PrimitiveValue >= left.PrimitiveValue); -// break; - default: - throw new NotImplementedException("BinaryOperator: " + binaryOperatorExpression.Op); + // Both are primitive - do value the operation + if (left != null && right != null) { + try { + // Note the order of these tests is significant (eg "5" + 6: "56" or 11?) + + // String operation + if (left is string || right is string) { + string a = Convert.ToString(left); + string b = Convert.ToString(right); + switch (op) { + case BinaryOperatorType.Equality: return a == b; + case BinaryOperatorType.InEquality: return a != b; + case BinaryOperatorType.Add: return a + b; + case BinaryOperatorType.ReferenceEquality: return a == b; + case BinaryOperatorType.ReferenceInequality: return a != b; + case BinaryOperatorType.NullCoalescing: return a ?? b; + } + } + + // Bool operation + if (left is bool || right is bool) { + bool a = Convert.ToBoolean(left); + bool b = Convert.ToBoolean(right); + switch (op) { + case BinaryOperatorType.BitwiseAnd: return a & b; + case BinaryOperatorType.BitwiseOr: return a | b; + case BinaryOperatorType.LogicalAnd: return a && b; + case BinaryOperatorType.LogicalOr: return a || b; + case BinaryOperatorType.ExclusiveOr: return a ^ b; + + case BinaryOperatorType.Equality: return a == b; + case BinaryOperatorType.InEquality: return a != b; + + case BinaryOperatorType.ReferenceEquality: return a == b; + case BinaryOperatorType.ReferenceInequality: return a != b; + } + } + + // Float operation + if (left is double || left is float || right is double || right is float) { + double a = Convert.ToDouble(left); + double b = Convert.ToDouble(right); + switch (op) { + case BinaryOperatorType.GreaterThan: return a > b; + case BinaryOperatorType.GreaterThanOrEqual: return a >= b; + case BinaryOperatorType.Equality: return a == b; + case BinaryOperatorType.InEquality: return a != b; + case BinaryOperatorType.LessThan: return a < b; + case BinaryOperatorType.LessThanOrEqual: return a <= b; + + case BinaryOperatorType.Add: return a + b; + case BinaryOperatorType.Subtract: return a - b; + case BinaryOperatorType.Multiply: return a * b; + case BinaryOperatorType.Divide: return a / b; + case BinaryOperatorType.Modulus: return a % b; + case BinaryOperatorType.Concat: return a + b; + + case BinaryOperatorType.ReferenceEquality: return a == b; + case BinaryOperatorType.ReferenceInequality: return a != b; + } + } + + // Integer operation + if (left is byte || left is sbyte || left is int || left is uint || left is long || left is ulong || + right is byte || right is sbyte || right is int || right is uint || right is long || right is ulong) { + long a = Convert.ToInt64(left); + long b = Convert.ToInt64(right); + switch (op) { + case BinaryOperatorType.BitwiseAnd: return a & b; + case BinaryOperatorType.BitwiseOr: return a | b; + case BinaryOperatorType.ExclusiveOr: return a ^ b; + + case BinaryOperatorType.GreaterThan: return a > b; + case BinaryOperatorType.GreaterThanOrEqual: return a >= b; + case BinaryOperatorType.Equality: return a == b; + case BinaryOperatorType.InEquality: return a != b; + case BinaryOperatorType.LessThan: return a < b; + case BinaryOperatorType.LessThanOrEqual: return a <= b; + + case BinaryOperatorType.Add: return a + b; + case BinaryOperatorType.Subtract: return a - b; + case BinaryOperatorType.Multiply: return a * b; + case BinaryOperatorType.Divide: return a / b; + case BinaryOperatorType.Modulus: return a % b; + case BinaryOperatorType.Concat: return a + b; + case BinaryOperatorType.ShiftLeft: return a << Convert.ToInt32(b); + case BinaryOperatorType.ShiftRight: return a >> Convert.ToInt32(b); + + case BinaryOperatorType.ReferenceEquality: return a == b; + case BinaryOperatorType.ReferenceInequality: return a != b; + } + } + + // Char operation + if (left is char || right is char) { + char a = Convert.ToChar(left); + char b = Convert.ToChar(right); + switch (op) { + case BinaryOperatorType.BitwiseAnd: return a & b; + case BinaryOperatorType.BitwiseOr: return a | b; + case BinaryOperatorType.ExclusiveOr: return a ^ b; + + case BinaryOperatorType.GreaterThan: return a > b; + case BinaryOperatorType.GreaterThanOrEqual: return a >= b; + case BinaryOperatorType.Equality: return a == b; + case BinaryOperatorType.InEquality: return a != b; + case BinaryOperatorType.LessThan: return a < b; + case BinaryOperatorType.LessThanOrEqual: return a <= b; + + case BinaryOperatorType.Add: return a + b; + case BinaryOperatorType.Subtract: return a - b; + case BinaryOperatorType.Multiply: return a * b; + case BinaryOperatorType.Divide: return a / b; + case BinaryOperatorType.Modulus: return a % b; + case BinaryOperatorType.Concat: return a + b; + case BinaryOperatorType.ShiftLeft: return a << b; + case BinaryOperatorType.ShiftRight: return a >> b; + + case BinaryOperatorType.ReferenceEquality: return a == b; + case BinaryOperatorType.ReferenceInequality: return a != b; + } + } + } catch(FormatException e) { + throw new GetValueException("Conversion error: " + e.Message); + } catch(InvalidCastException e) { + throw new GetValueException("Conversion error: " + e.Message); + } catch(OverflowException e) { + throw new GetValueException("Conversion error: " + e.Message); } - } catch (System.Exception e) { - throw new GetValueException(e.Message); } - return val; + throw new DebuggerException("Unreachable code"); } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs index d7c1ee71f0..0c67f9a2d3 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs @@ -258,7 +258,25 @@ namespace Debugger (uint)corArgs.Count, corArgs.ToArray() ); } + + public static Value CreateValue(Process process, object value) + { + if (value == null) { + ICorDebugClass corClass = DebugType.Create(process, null, typeof(object).FullName).CorType.Class; + ICorDebugEval corEval = CreateCorEval(process); + ICorDebugValue corValue = corEval.CreateValue((uint)CorElementType.CLASS, corClass); + return new Value(process, new Expressions.PrimitiveExpression(value), corValue); + } else if (value is string) { + return Eval.NewString(process, (string)value); + } else { + // TODO: Check if it is primitive type + Value val = Eval.NewObjectNoConstructor(DebugType.Create(process, null, value.GetType().FullName)); + val.PrimitiveValue = value; + return val; + } + } + /* // The following function create values only for the purpuse of evalutaion // They actually do not allocate memory on the managed heap // The advantage is that it does not continue the process @@ -282,6 +300,7 @@ namespace Debugger } return v; } + */ #region Convenience methods diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs index 872929a76e..801939ec0f 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs @@ -14,7 +14,10 @@ namespace Debugger.Tests.TestPrograms { public static void Main() { - int index = 4; + byte b = 1; + int i = 4; + float pi = 3.14f; + string hi = "hi"; char[] array = "Hello".ToCharArray(); char[] array2 = "world".ToCharArray(); @@ -39,14 +42,32 @@ namespace Debugger.Tests { { StartTest("AstEval.cs"); + Eval("b"); + Eval("i"); + Eval("pi"); + Eval("pi - 3"); + Eval("b + i"); + Eval("i + b"); + Eval("b + pi"); + Eval("pi + b"); + Eval("hi + pi"); + Eval("pi + hi"); + Eval("pi + \" \" + hi"); + + Eval("(5 + 6) % (1 + 2)"); + Eval("b + 3 == i"); + Eval("b + 4 == i"); + Eval("true == true"); + Eval("true == false"); + Eval("array"); Eval("arrays"); Eval("array[1]"); - Eval("array[index]"); - Eval("array[index - 1]"); + Eval("array[i]"); + Eval("array[i - 1]"); Eval("list"); Eval("list[1]"); - Eval("list[index]"); + Eval("list[i]"); EndTest(); } @@ -74,15 +95,31 @@ namespace Debugger.Tests { mscorlib.dll (No symbols) AstEval.exe (Has symbols) - Break AstEval.cs:24,4-24,40 + Break AstEval.cs:27,4-27,40 + b = 1 + i = 4 + pi = 3.14 + pi - 3 = 0.140000104904175 + b + i = 5 + i + b = 5 + b + pi = 4.14000010490417 + pi + b = 4.14000010490417 + hi + pi = hi3.14 + pi + hi = 3.14hi + pi + " " + hi = 3.14 hi + (5 + 6) % (1 + 2) = 2 + b + 3 == i = True + b + 4 == i = False + true == true = True + true == false = False array = Char[] {H, e, l, l, o} arrays = Char[][] {Char[] {H, e, l, l, o}, Char[] {w, o, r, l, d}} array[1] = e - array[index] = o - array[index - 1] = Error: BinaryOperator: Subtract + array[i] = o + array[i - 1] = l list = System.Collections.Generic.List`1[System.Char] list[1] = e - list[index] = o + list[i] = o