Browse Source

Console: Binary operations

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4352 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 17 years ago
parent
commit
df042aa949
  1. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs
  2. 194
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs
  3. 19
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs
  4. 53
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/AstEvaluator.cs

@ -52,6 +52,8 @@ namespace Debugger.AddIn @@ -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();
}

194
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Expressions/EvaluateAstVisitor.cs

@ -149,15 +149,7 @@ namespace Debugger.AddIn @@ -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 @@ -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");
}
}
}

19
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Eval.cs

@ -258,7 +258,25 @@ namespace Debugger @@ -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 @@ -282,6 +300,7 @@ namespace Debugger
}
return v;
}
*/
#region Convenience methods

53
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AstEval.cs

@ -14,7 +14,10 @@ namespace Debugger.Tests.TestPrograms @@ -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 { @@ -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 { @@ -74,15 +95,31 @@ namespace Debugger.Tests {
<ProcessStarted />
<ModuleLoaded>mscorlib.dll (No symbols)</ModuleLoaded>
<ModuleLoaded>AstEval.exe (Has symbols)</ModuleLoaded>
<DebuggingPaused>Break AstEval.cs:24,4-24,40</DebuggingPaused>
<DebuggingPaused>Break AstEval.cs:27,4-27,40</DebuggingPaused>
<Eval> b = 1 </Eval>
<Eval> i = 4 </Eval>
<Eval> pi = 3.14 </Eval>
<Eval> pi - 3 = 0.140000104904175 </Eval>
<Eval> b + i = 5 </Eval>
<Eval> i + b = 5 </Eval>
<Eval> b + pi = 4.14000010490417 </Eval>
<Eval> pi + b = 4.14000010490417 </Eval>
<Eval> hi + pi = hi3.14 </Eval>
<Eval> pi + hi = 3.14hi </Eval>
<Eval> pi + " " + hi = 3.14 hi </Eval>
<Eval> (5 + 6) % (1 + 2) = 2 </Eval>
<Eval> b + 3 == i = True </Eval>
<Eval> b + 4 == i = False </Eval>
<Eval> true == true = True </Eval>
<Eval> true == false = False </Eval>
<Eval> array = Char[] {H, e, l, l, o} </Eval>
<Eval> arrays = Char[][] {Char[] {H, e, l, l, o}, Char[] {w, o, r, l, d}} </Eval>
<Eval> array[1] = e </Eval>
<Eval> array[index] = o </Eval>
<Eval> array[index - 1] = Error: BinaryOperator: Subtract </Eval>
<Eval> array[i] = o </Eval>
<Eval> array[i - 1] = l </Eval>
<Eval> list = System.Collections.Generic.List`1[System.Char] </Eval>
<Eval> list[1] = e </Eval>
<Eval> list[index] = o </Eval>
<Eval> list[i] = o </Eval>
<ProcessExited />
</Test>
</DebuggerTests>

Loading…
Cancel
Save