From 334a93ac49003a56290c3fa73578097101dbab42 Mon Sep 17 00:00:00 2001 From: Elemar Rodrigues Severo Junior Date: Wed, 28 Oct 2015 17:48:17 -0200 Subject: [PATCH] Support to expressions in bellvue and fixing float32 support --- demo/bellevue/Bellevue/Program.cs | 18 +- demo/bellevue/Bellevue/sample.txt | 4 +- src/FluentIL/Emitters/DynamicMethodBody.cs | 9 +- .../DynamicMethodBody.Expression.cs | 58 +++--- src/FluentIL/Emitters/ILEmitter.cs | 191 +++++++++--------- src/FluentIL/Emitters/ReflectionILEmitter.cs | 5 + .../Emitters/T4/DynamicMethodBody.Emit.cs | 15 +- src/FluentIL/ExpressionParser/ParseResult.cs | 22 ++ src/FluentIL/ExpressionParser/Parser.cs | 22 +- src/FluentIL/FluentIL.csproj | 1 + test/FluentIL.Tests/MathStudies.cs | 14 ++ 11 files changed, 224 insertions(+), 135 deletions(-) create mode 100644 src/FluentIL/ExpressionParser/ParseResult.cs diff --git a/demo/bellevue/Bellevue/Program.cs b/demo/bellevue/Bellevue/Program.cs index cb3e66e..44292ea 100644 --- a/demo/bellevue/Bellevue/Program.cs +++ b/demo/bellevue/Bellevue/Program.cs @@ -1,10 +1,8 @@ using System; -using System.Globalization; using System.IO; - -using FluentIL; - using Bellevue.Parser; +using FluentIL; +using FluentIL.ExpressionParser; namespace Bellevue { @@ -51,11 +49,11 @@ static void Main(string[] args) } else if (block.IsFormula) { + ParseResult result; var formula = ((Tokens.Formula) block).Item; - // TODO: Which version of write should it use?! body - .Parse(formula) - .Write(); + .Parse(formula, out result) + .Write(result.ExpressionType); } } body.Ret(); @@ -64,9 +62,11 @@ static void Main(string[] args) assembly.Save(); } - static string Number() + public float Print(float input) { - return (3.1415).ToString(CultureInfo.InvariantCulture); + return input/2; } + + } } diff --git a/demo/bellevue/Bellevue/sample.txt b/demo/bellevue/Bellevue/sample.txt index fee485d..11e686d 100644 --- a/demo/bellevue/Bellevue/sample.txt +++ b/demo/bellevue/Bellevue/sample.txt @@ -2,6 +2,8 @@ Hello World! @*this is a comment*@ This source text @*this is a comment*@will be compiled into an executable. - Yeap. It works! @{2+2/2} + Int operation: @{2+2/2} + Int operation: @{5/2} + Float operation: @{7.0/2} Bye! diff --git a/src/FluentIL/Emitters/DynamicMethodBody.cs b/src/FluentIL/Emitters/DynamicMethodBody.cs index 8532bb8..2a552c8 100644 --- a/src/FluentIL/Emitters/DynamicMethodBody.cs +++ b/src/FluentIL/Emitters/DynamicMethodBody.cs @@ -39,13 +39,20 @@ public DynamicMethodBody Write(string message) } public DynamicMethodBody Write() + { + return Write(typeof (T)); + } + + public DynamicMethodBody Write(Type t) { var minfo = typeof(Console).GetMethod( "Write", - new[] { typeof(T) }); + new[] { t }); return Call(minfo); } + + public object Invoke(params object[] args) { return _methodInfo.AsDynamicMethod.Invoke(null, args); diff --git a/src/FluentIL/Emitters/FluentHelpers/DynamicMethodBody.Expression.cs b/src/FluentIL/Emitters/FluentHelpers/DynamicMethodBody.Expression.cs index 3b093be..302a304 100644 --- a/src/FluentIL/Emitters/FluentHelpers/DynamicMethodBody.Expression.cs +++ b/src/FluentIL/Emitters/FluentHelpers/DynamicMethodBody.Expression.cs @@ -1,26 +1,32 @@ -using System.Linq.Expressions; -using FluentIL.ExpressionInterpreter; -using FluentIL.ExpressionParser; - -// ReSharper disable CheckNamespace -namespace FluentIL.Emitters -// ReSharper restore CheckNamespace -{ - partial class DynamicMethodBody - { - public DynamicMethodBody Parse(string expression) - { - Parser.Parse(expression, this); - return this; - } - - public DynamicMethodBody Expression(Expression expression) - { - expression = new ExpressionSimplifierVisitor().Visit(expression); - new ILEmitterVisitor(this).Visit( - expression - ); - return this; - } - } -} +using System.Linq.Expressions; +using FluentIL.ExpressionInterpreter; +using FluentIL.ExpressionParser; + +// ReSharper disable CheckNamespace +namespace FluentIL.Emitters +// ReSharper restore CheckNamespace +{ + partial class DynamicMethodBody + { + public DynamicMethodBody Parse(string expression) + { + Parser.Parse(expression, this); + return this; + } + + public DynamicMethodBody Parse(string expression, out ParseResult result) + { + result = Parser.Parse(expression, this); + return this; + } + + public DynamicMethodBody Expression(Expression expression) + { + expression = new ExpressionSimplifierVisitor().Visit(expression); + new ILEmitterVisitor(this).Visit( + expression + ); + return this; + } + } +} diff --git a/src/FluentIL/Emitters/ILEmitter.cs b/src/FluentIL/Emitters/ILEmitter.cs index 13e1737..6cf34e3 100644 --- a/src/FluentIL/Emitters/ILEmitter.cs +++ b/src/FluentIL/Emitters/ILEmitter.cs @@ -1,93 +1,100 @@ -using System; -using System.Reflection; -using System.Reflection.Emit; - -namespace FluentIL.Emitters -{ - public abstract class ILEmitter - { - public void DeclareLocal(Type type) - { - OnDeclareLocal(type); - } - - protected abstract void OnDeclareLocal(Type type); - - public void MarkLabel(Label label) - { - OnMarkLabel(label); - } - - protected abstract void OnMarkLabel(Label label); - - public Label DefineLabel() - { - return OnDefineLabel(); - } - - protected abstract Label OnDefineLabel(); - - public void Emit(OpCode opcode) - { - OnEmit(opcode); - } - - protected abstract void OnEmit(OpCode opcode); - - public void Emit(OpCode opcode, string arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, string arg); - - public void Emit(OpCode opcode, int arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, int arg); - - public void Emit(OpCode opcode, double arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, double arg); - - public void Emit(OpCode opcode, Label arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, Label arg); - - public void Emit(OpCode opcode, MethodInfo arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, MethodInfo arg); - - public void Emit(OpCode opcode, ConstructorInfo arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, ConstructorInfo arg); - - public void Emit(OpCode opcode, FieldInfo arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, FieldInfo arg); - - public void Emit(OpCode opcode, Type arg) - { - OnEmit(opcode, arg); - } - - protected abstract void OnEmit(OpCode opcode, Type arg); - } +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace FluentIL.Emitters +{ + public abstract class ILEmitter + { + public void DeclareLocal(Type type) + { + OnDeclareLocal(type); + } + + protected abstract void OnDeclareLocal(Type type); + + public void MarkLabel(Label label) + { + OnMarkLabel(label); + } + + protected abstract void OnMarkLabel(Label label); + + public Label DefineLabel() + { + return OnDefineLabel(); + } + + protected abstract Label OnDefineLabel(); + + public void Emit(OpCode opcode) + { + OnEmit(opcode); + } + + protected abstract void OnEmit(OpCode opcode); + + public void Emit(OpCode opcode, string arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, string arg); + + public void Emit(OpCode opcode, int arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, int arg); + + public void Emit(OpCode opcode, double arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, double arg); + + public void Emit(OpCode opcode, float arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, float arg); + + public void Emit(OpCode opcode, Label arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, Label arg); + + public void Emit(OpCode opcode, MethodInfo arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, MethodInfo arg); + + public void Emit(OpCode opcode, ConstructorInfo arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, ConstructorInfo arg); + + public void Emit(OpCode opcode, FieldInfo arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, FieldInfo arg); + + public void Emit(OpCode opcode, Type arg) + { + OnEmit(opcode, arg); + } + + protected abstract void OnEmit(OpCode opcode, Type arg); + } } \ No newline at end of file diff --git a/src/FluentIL/Emitters/ReflectionILEmitter.cs b/src/FluentIL/Emitters/ReflectionILEmitter.cs index 163dfe1..37372c2 100644 --- a/src/FluentIL/Emitters/ReflectionILEmitter.cs +++ b/src/FluentIL/Emitters/ReflectionILEmitter.cs @@ -27,6 +27,11 @@ protected override void OnEmit(OpCode opcode, int arg) _ilGenerator.Emit(opcode, arg); } + protected override void OnEmit(OpCode opcode, float arg) + { + _ilGenerator.Emit(opcode, arg); + } + protected override void OnEmit(OpCode opcode, double arg) { _ilGenerator.Emit(opcode, arg); diff --git a/src/FluentIL/Emitters/T4/DynamicMethodBody.Emit.cs b/src/FluentIL/Emitters/T4/DynamicMethodBody.Emit.cs index ad22182..51c7a79 100644 --- a/src/FluentIL/Emitters/T4/DynamicMethodBody.Emit.cs +++ b/src/FluentIL/Emitters/T4/DynamicMethodBody.Emit.cs @@ -58,7 +58,20 @@ public DynamicMethodBody Emit(OpCode opcode, int arg) return this; } - public DynamicMethodBody Emit(OpCode opcode, double arg) + public DynamicMethodBody Emit(OpCode opcode, float arg) + { + ExecutePreEmitActions(); +#if DEBUG + Console.WriteLine("\t{0} {1}", opcode, arg); +#endif + + _methodInfo.GetILEmitter() + .Emit(opcode, arg); + + return this; + } + + public DynamicMethodBody Emit(OpCode opcode, double arg) { ExecutePreEmitActions(); #if DEBUG diff --git a/src/FluentIL/ExpressionParser/ParseResult.cs b/src/FluentIL/ExpressionParser/ParseResult.cs new file mode 100644 index 0000000..0fff40e --- /dev/null +++ b/src/FluentIL/ExpressionParser/ParseResult.cs @@ -0,0 +1,22 @@ +using System; + +namespace FluentIL.ExpressionParser +{ + public class ParseResult + { + public Type ExpressionType { get; internal set; } + + internal void AnalyzeType(Type type) + { + var shouldUse = + (ExpressionType == null) || + (type == typeof(bool)) || + (type == typeof(double) && ExpressionType == typeof(int)); + + if (shouldUse) + { + ExpressionType = type; + } + } + } +} \ No newline at end of file diff --git a/src/FluentIL/ExpressionParser/Parser.cs b/src/FluentIL/ExpressionParser/Parser.cs index 623287a..d53a54f 100644 --- a/src/FluentIL/ExpressionParser/Parser.cs +++ b/src/FluentIL/ExpressionParser/Parser.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using FluentIL.Emitters; namespace FluentIL.ExpressionParser @@ -41,17 +42,17 @@ private Token GetNextToken() return new Token("EOP", "EOP"); } - - public static void Parse(string expression, + public static ParseResult Parse(string expression, DynamicMethodBody methodBody = null) { - new Parser( + return new Parser( new ExpressionScanner().Scan(expression), methodBody ).Parse(); } - public void Parse() + readonly ParseResult _result = new ParseResult(); + public ParseResult Parse() { _sourceEnumerator?.Dispose(); @@ -61,6 +62,8 @@ public void Parse() LogicalExpression(); Match("EOP"); End(); + + return _result; } private void LogicalExpression() @@ -347,20 +350,26 @@ private void EmitOp(string operation) break; case "lt": MethodBody.Clt(); + _result.AnalyzeType(typeof(bool)); break; case "leq": MethodBody.Cle(); + _result.AnalyzeType(typeof(bool)); break; case "gt": MethodBody.Cgt(); + _result.AnalyzeType(typeof(bool)); break; case "geq": MethodBody.Cge(); + _result.AnalyzeType(typeof(bool)); break; case "eq": MethodBody.Ceq(); + _result.AnalyzeType(typeof(bool)); break; case "neq": + _result.AnalyzeType(typeof(bool)); MethodBody .Ceq() .Ldc(0) @@ -526,6 +535,7 @@ private void UnaryExpression() case "not": Match("not"); PrimaryExpression(); + _result.AnalyzeType(typeof(bool)); MethodBody?.Ldc(0).Ceq(); break; case "minus": @@ -556,12 +566,14 @@ private void PrimaryExpression() Match("rparen"); break; case "float": - MethodBody?.Ldc(float.Parse(_inputToken.Value)); + MethodBody?.Ldc(float.Parse(_inputToken.Value, CultureInfo.InvariantCulture)); Match("float"); + _result.AnalyzeType(typeof(float)); break; case "integer": MethodBody?.Ldc(int.Parse(_inputToken.Value)); Match("integer"); + _result.AnalyzeType(typeof(int)); break; case "identifier": MethodBody?.LdArgOrLoc(_inputToken.Value); diff --git a/src/FluentIL/FluentIL.csproj b/src/FluentIL/FluentIL.csproj index 7531e8b..3371db4 100644 --- a/src/FluentIL/FluentIL.csproj +++ b/src/FluentIL/FluentIL.csproj @@ -46,6 +46,7 @@ + diff --git a/test/FluentIL.Tests/MathStudies.cs b/test/FluentIL.Tests/MathStudies.cs index 54d6ebe..dd1735d 100644 --- a/test/FluentIL.Tests/MathStudies.cs +++ b/test/FluentIL.Tests/MathStudies.cs @@ -375,6 +375,20 @@ public void AddToVar() result.Should().Be(25); } + + [Test] + public void SevenByTwo() + { + var result = IL.NewMethod() + .Returns() + .Ldc(7f) + .Ldc(2f) + .Div() + .Ret() + .Invoke(); + + result.Should().Be(3.5f); + } } }