diff --git a/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs b/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs new file mode 100644 index 0000000..eb83805 --- /dev/null +++ b/src/GraphClimber.Debug/ExpressionCompiler/CSharpExpressionDescriber.cs @@ -0,0 +1,27 @@ +using System.IO; +using System.Linq.Expressions; +using GraphClimber.ExpressionCompiler; +using Mono.Linq.Expressions; + +namespace GraphClimber.Debug.ExpressionCompiler +{ + public class CSharpExpressionDescriber : IExpressionDescriber + { + public static readonly IExpressionDescriber Empty = new CSharpExpressionDescriber(); + + private CSharpExpressionDescriber() + { + + } + + public string Describe(Expression expression) + { + var stringWriter = new StringWriter(); + var csharpWriter = new CSharpWriter(new TextFormatter(stringWriter)); + + csharpWriter.Write(expression); + + return stringWriter.ToString(); + } + } +} \ No newline at end of file diff --git a/src/GraphClimber.Debug/GraphClimber.Debug.csproj b/src/GraphClimber.Debug/GraphClimber.Debug.csproj new file mode 100644 index 0000000..e4dd4d6 --- /dev/null +++ b/src/GraphClimber.Debug/GraphClimber.Debug.csproj @@ -0,0 +1,65 @@ + + + + + Debug + AnyCPU + {B003B6BA-6A13-403E-8C1E-D26AE60C58A0} + Library + Properties + GraphClimber.Debug + GraphClimber.Debug + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Mono.Linq.Expressions.1.2.0.0\lib\Mono.Linq.Expressions.dll + + + + + + + + + + + + + + + + {f7fa4635-c6c6-4d82-b344-b737438e1651} + GraphClimber + + + + + + + + \ No newline at end of file diff --git a/src/GraphClimber.Debug/Properties/AssemblyInfo.cs b/src/GraphClimber.Debug/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4538988 --- /dev/null +++ b/src/GraphClimber.Debug/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GraphClimber.Debug")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GraphClimber.Debug")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8e268eed-bd81-4354-be31-618dd525e6fa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/GraphClimber.Debug/packages.config b/src/GraphClimber.Debug/packages.config new file mode 100644 index 0000000..7c2d45b --- /dev/null +++ b/src/GraphClimber.Debug/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/GraphClimber.sln b/src/GraphClimber.sln index 43b6d9d..ad77fe3 100644 --- a/src/GraphClimber.sln +++ b/src/GraphClimber.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.22310.1 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber", "GraphClimber\GraphClimber.csproj", "{F7FA4635-C6C6-4D82-B344-B737438E1651}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.Tests", "GraphClimber.Tests\GraphClimber.Tests.csproj", "{99B3FD79-4D4B-4536-9F6B-2F53E86F8603}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GraphClimber.Debug", "GraphClimber.Debug\GraphClimber.Debug.csproj", "{B003B6BA-6A13-403E-8C1E-D26AE60C58A0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Debug|Any CPU.Build.0 = Debug|Any CPU {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Release|Any CPU.ActiveCfg = Release|Any CPU {99B3FD79-4D4B-4536-9F6B-2F53E86F8603}.Release|Any CPU.Build.0 = Release|Any CPU + {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B003B6BA-6A13-403E-8C1E-D26AE60C58A0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs b/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs index f252528..8f3c869 100644 --- a/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs +++ b/src/GraphClimber/ExpressionCompiler/AccessPrivateFieldVisitor.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; +using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber.ExpressionCompiler { @@ -93,21 +94,21 @@ protected override Expression VisitMethodCall(MethodCallExpression node) if (!node.Method.IsPublic) { // In case of static methods, instance should be null. - var reflectionInstance = node.Object ?? Expression.Constant(null); + var reflectionInstance = node.Object ?? ExpressionExtensions.Null; // In case of generic method, // we create an array of the assembly qualified names of the generic arguments. var genericArgumentTypes = node.Method.IsGenericMethod - ? (Expression)Expression.NewArrayInit(typeof(string), node.Method.GetGenericArguments().Select(t => Expression.Constant(t.AssemblyQualifiedName))) - : Expression.Constant(null); + ? (Expression)Expression.NewArrayInit(typeof(string), node.Method.GetGenericArguments().Select(t => t.AssemblyQualifiedName.Constant())) + : ExpressionExtensions.Null; return - Expression.Convert(Expression.Call(null, typeof(AccessPrivateFieldVisitor).GetMethod("CallMethod"), - Expression.Constant(node.Method.DeclaringType.AssemblyQualifiedName), - Expression.Constant(node.Method.Name), + Expression.Call(null, typeof(AccessPrivateFieldVisitor).GetMethod("CallMethod"), + node.Method.DeclaringType.AssemblyQualifiedName.Constant(), + node.Method.Name.Constant(), genericArgumentTypes, reflectionInstance, - Expression.NewArrayInit(typeof(object), node.Arguments)), node.Type); + Expression.NewArrayInit(typeof(object), node.Arguments)).Convert(node.Type); } return base.VisitMethodCall(node); @@ -140,12 +141,13 @@ private static Expression VisitFieldMemberExpression(MemberExpression node, Fiel if (isPrivateField) { - var argument = node.Expression ?? Expression.Constant(null); + var argument = node.Expression ?? ExpressionExtensions.Null; - return Expression.Convert(Expression.Call(null, + return Expression.Call(null, typeof (AccessPrivateFieldVisitor).GetMethod("GetFieldValue"), - Expression.Constant(fieldInfo.DeclaringType.AssemblyQualifiedName), - Expression.Constant(fieldInfo.Name), argument), node.Type); + fieldInfo.DeclaringType.AssemblyQualifiedName.Constant(), + fieldInfo.Name.Constant(), + argument).Convert(node.Type); } return node; @@ -160,12 +162,13 @@ private static Expression VisitPropertyMemberExpression(MemberExpression node, P if (isPrivate) { - var argument = node.Expression ?? Expression.Constant(null); + var argument = node.Expression ?? ExpressionExtensions.Null; - return Expression.Convert(Expression.Call(null, + return Expression.Call(null, typeof (AccessPrivateFieldVisitor).GetMethod("GetPropertyValue"), - Expression.Constant(propertyInfo.DeclaringType.AssemblyQualifiedName), - Expression.Constant(propertyInfo.Name), argument), node.Type); + propertyInfo.DeclaringType.AssemblyQualifiedName.Constant(), + propertyInfo.Name.Constant(), + argument).Convert(node.Type); } return node; diff --git a/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs b/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs index c18e015..e9ad593 100644 --- a/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs +++ b/src/GraphClimber/ExpressionCompiler/DebugExpressionVistor.cs @@ -45,12 +45,11 @@ public override Expression Visit(Expression node) return node; } - Expression innerExpression = base.Visit(node); // Unsymboled is not symboled, the node children are. if (ContainsType(_unsymboledExpressionTypes, node)) { - return innerExpression; + return base.Visit(node); } Range range = GetCurrentExpressionRange(node); @@ -62,6 +61,8 @@ public override Expression Visit(Expression node) range.End.Line + 1, range.End.Column + 1); + Expression innerExpression = base.Visit(node); + return Expression.Block(debugInfoExpression, innerExpression); } @@ -71,7 +72,8 @@ private Range GetCurrentExpressionRange(Expression node) string[] debugViewLines = debugView.Split(_newLineSeperator, StringSplitOptions.RemoveEmptyEntries); string firstDebugViewLine = debugViewLines.First(); - _currentIndex = _initialDebugView.IndexOf(firstDebugViewLine, _currentIndex, StringComparison.Ordinal); + var newIndex = _initialDebugView.IndexOf(firstDebugViewLine, _currentIndex, StringComparison.Ordinal); + _currentIndex = newIndex; Position start = _initialDebugView.GetPosition(_currentIndex); int spacing = _initialDebugView.Split(_newLineSeperator, StringSplitOptions.RemoveEmptyEntries)[start.Line].IndexOfNot(' '); diff --git a/src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs b/src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs new file mode 100644 index 0000000..5e23a33 --- /dev/null +++ b/src/GraphClimber/ExpressionCompiler/Extensions/ExpressionExtensions.cs @@ -0,0 +1,55 @@ +using System; +using System.Linq.Expressions; + +namespace GraphClimber.ExpressionCompiler.Extensions +{ + /// + /// Provides extension methods to create + /// expressions easier. + /// + public static class ExpressionExtensions + { + + /// + /// Expression of Null. + /// + public static readonly ConstantExpression Null = Expression.Constant(null); + + /// + /// Creates an + /// with the given value + /// + /// + /// + /// + public static Expression Constant(this T value) + { + return Expression.Constant(value, typeof (T)); + } + + /// + /// Converts the expression value to the given type + /// . + /// + /// + /// + /// + public static Expression Convert(this Expression expression) + { + return expression.Convert(typeof (T)); + } + + /// + /// Converts the expression value to the given + /// + /// + /// + /// + /// + public static Expression Convert(this Expression expression, Type newType) + { + return Expression.Convert(expression, newType); + } + + } +} diff --git a/src/GraphClimber/GraphClimber.csproj b/src/GraphClimber/GraphClimber.csproj index 169f2ea..d2c7030 100644 --- a/src/GraphClimber/GraphClimber.csproj +++ b/src/GraphClimber/GraphClimber.csproj @@ -85,6 +85,7 @@ + diff --git a/src/GraphClimber/Program.cs b/src/GraphClimber/Program.cs index f52d9f6..d21f985 100644 --- a/src/GraphClimber/Program.cs +++ b/src/GraphClimber/Program.cs @@ -8,6 +8,7 @@ using System.Xml.Linq; using GraphClimber.Examples; using GraphClimber.ExpressionCompiler; +using GraphClimber.ExpressionCompiler.Extensions; using GraphClimber.ValueDescriptor; namespace GraphClimber @@ -57,11 +58,12 @@ public static void Play() var variable = Expression.Variable(typeof(int), "myInt"); var @break = Expression.Label(); Expression exp = Expression.Assign(variable, Expression.Divide(propertyOrField, Expression.Subtract(property, method))); - exp = Expression.Block(new[] { variable }, exp, Expression.Add(Expression.Constant(2), Expression.Constant(5)), Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), Expression.Constant("Hello Worlda")), - Expression.Goto(@break)); + exp = Expression.Block(new[] { variable }, exp, Expression.Add(2.Constant(), 5.Constant()), Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), Expression.Constant("Hello Worlda"))); - exp = Expression.Loop(exp, @break); + var iVariable = Expression.Variable(typeof(int), "i"); + // exp = CustomExpression.For(iVariable, 0.Constant(), Expression.LessThan(iVariable, 5.Constant()), Expression.PostIncrementAssign(iVariable), exp); + exp = Expression.Block(exp, Expression.Call(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }), Expression.Constant("Goodbye"))); @@ -88,7 +90,7 @@ public static void DoSomething(StrongBox hello) static void Main(string[] args) { - // ExpressionDebugGames.Play(); + ExpressionDebugGames.Play(); //IStore store = new TrivialStore(); //store.Set("A", 5); diff --git a/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs b/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs index 0d9d30b..433fb0b 100644 --- a/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs +++ b/src/GraphClimber/ValueDescriptor/DelegateStateMember.cs @@ -1,6 +1,7 @@ using System; using System.Linq.Expressions; using System.Runtime.CompilerServices; +using GraphClimber.ExpressionCompiler.Extensions; namespace GraphClimber.ValueDescriptor { @@ -32,7 +33,7 @@ public Type MemberType public Expression GetGetExpression(Expression obj) { - return Expression.Constant(_value); + return _value.Constant(); } public Expression GetSetExpression(Expression obj, Expression value) @@ -149,12 +150,12 @@ public Type MemberType public Expression GetGetExpression(Expression obj) { - return Expression.Invoke(Expression.Constant(_getValue)); + return Expression.Invoke(_getValue.Constant()); } public Expression GetSetExpression(Expression obj, Expression value) { - return Expression.Invoke(Expression.Constant(_setValue), value); + return Expression.Invoke(_setValue.Constant(), value); } public bool IsArrayElement @@ -216,12 +217,12 @@ public Type MemberType public Expression GetGetExpression(Expression obj) { - return Expression.Invoke(Expression.Constant(_getValue)); + return Expression.Invoke(_getValue.Constant()); } public Expression GetSetExpression(Expression obj, Expression value) { - return Expression.Invoke(Expression.Constant(_setValue), value); + return Expression.Invoke(_setValue.Constant(), value); } public bool IsArrayElement