Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
81ccd75
add the possibility to check the IL in tests
jogibear9988 Sep 7, 2018
ddb5b4e
use collectionassert
jogibear9988 Sep 8, 2018
1e03dc7
check multiple constant returns are removed
jogibear9988 Sep 8, 2018
db67a26
Nullable -> Nullable convert
jogibear9988 Sep 8, 2018
9e5ddde
test for ldarg error
jogibear9988 Sep 8, 2018
e00efb3
bugfix ladarg
jogibear9988 Sep 8, 2018
62557ff
fixes for linq2db
jogibear9988 Sep 8, 2018
61de7c1
bugfixes for linq2db tests
jogibear9988 Sep 9, 2018
b64b296
more tests, more fixes
jogibear9988 Sep 9, 2018
9485794
support convert checked
jogibear9988 Sep 9, 2018
27c43af
bugfix more for linq2db
jogibear9988 Sep 9, 2018
8335feb
bugfix implement not
jogibear9988 Sep 10, 2018
69db8c5
try to reproduce 146
jogibear9988 Sep 10, 2018
8984a48
more test for 146
jogibear9988 Sep 10, 2018
8392052
work on issue #147
jogibear9988 Sep 10, 2018
f37a7e5
Merge branch 'master' of https://github.com/dadhi/FastExpressionCompiler
jogibear9988 Sep 11, 2018
ef5ed6e
bugfix remove instance access flag
jogibear9988 Sep 11, 2018
7e7c256
try fix byref for nested lambdas
jogibear9988 Sep 11, 2018
b5ed5fc
support custom expression nodes
jogibear9988 Sep 12, 2018
c43fe1b
support reduce
jogibear9988 Sep 12, 2018
3bb21ab
bugfix byref by new
jogibear9988 Sep 12, 2018
933b66e
support decimal
jogibear9988 Sep 13, 2018
2a65959
bugfix fix #153 const access
jogibear9988 Sep 13, 2018
1889265
bugfix 153
jogibear9988 Sep 13, 2018
a451680
fix rest of linq2db tests
jogibear9988 Sep 13, 2018
05533ce
comment for decimal
jogibear9988 Sep 13, 2018
3bba396
bugfix equality
jogibear9988 Sep 13, 2018
b83e807
bugfix reduced expressions, we should only reduce once, or parameters…
jogibear9988 Sep 13, 2018
58ff50e
bugfix support string +
jogibear9988 Sep 13, 2018
ef868a6
support typeas
jogibear9988 Sep 13, 2018
61c1cf0
bugfix nullable arithmetic
jogibear9988 Sep 13, 2018
ba85df0
support typeis
jogibear9988 Sep 13, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/FastExpressionCompiler.LightExpression/Expression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public abstract class Expression
/// <summary>Converts to Expression and outputs its as string</summary>
public override string ToString() => ToExpression().ToString();

/// <summary>Reduces the Expression to simple ones</summary>
public virtual Expression Reduce() => this;

public static ParameterExpression Parameter(Type type, string name = null) =>
new ParameterExpression(type.IsByRef ? type.GetElementType() : type, name, type.IsByRef);

Expand Down Expand Up @@ -159,12 +162,27 @@ public static LambdaExpression Lambda(Expression body, params ParameterExpressio
public static LambdaExpression Lambda(Type delegateType, Expression body, params ParameterExpression[] parameters) =>
new LambdaExpression(delegateType, body, parameters);

public static UnaryExpression Not(Expression operand) =>
new UnaryExpression(ExpressionType.Not, operand, operand.Type);

public static TypeBinaryExpression TypeAs(Expression operand, Type type) =>
new TypeBinaryExpression(ExpressionType.TypeAs, operand, type);

public static UnaryExpression TypeIs(Expression operand, Type type) =>
new UnaryExpression(ExpressionType.TypeIs, operand, type);

public static UnaryExpression Convert(Expression operand, Type targetType) =>
new UnaryExpression(ExpressionType.Convert, operand, targetType);

public static UnaryExpression Convert(Expression operand, Type targetType, MethodInfo method) =>
new UnaryExpression(ExpressionType.Convert, operand, targetType, method);

public static UnaryExpression ConvertChecked(Expression operand, Type targetType) =>
new UnaryExpression(ExpressionType.ConvertChecked, operand, targetType);

public static UnaryExpression ConvertChecked(Expression operand, Type targetType, MethodInfo method) =>
new UnaryExpression(ExpressionType.ConvertChecked, operand, targetType, method);

public static UnaryExpression PreIncrementAssign(Expression operand) =>
new UnaryExpression(ExpressionType.PreIncrementAssign, operand, operand.Type);

Expand Down Expand Up @@ -568,6 +586,26 @@ protected BinaryExpression(ExpressionType nodeType, Expression left, Expression
}
}

public class TypeBinaryExpression : Expression
{
public override ExpressionType NodeType { get; }
public override Type Type { get; }

public Type TypeOperand { get; }

public readonly Expression Expression;

public override SysExpr ToExpression() => SysExpr.TypeIs(Expression.ToExpression(), TypeOperand);

internal TypeBinaryExpression(ExpressionType nodeType, Expression expression, Type typeOperand)
{
NodeType = nodeType;
Expression = expression;
Type = typeof(bool);
TypeOperand = typeOperand;
}
}

public sealed class SimpleBinaryExpression : BinaryExpression
{
public override SysExpr ToExpression()
Expand Down
348 changes: 288 additions & 60 deletions src/FastExpressionCompiler/FastExpressionCompiler.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@
<ProjectReference Include="..\..\src\FastExpressionCompiler\FastExpressionCompiler.csproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="ILDebugging.Decoder">
<HintPath>..\libs\ILDebugging.Decoder.dll</HintPath>
</Reference>
</ItemGroup>

</Project>
78 changes: 78 additions & 0 deletions test/FastExpressionCompiler.IssueTests/Issue146_bool_par_error.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using NUnit.Framework;

#pragma warning disable IDE1006 // Naming Styles for linq2db
#pragma warning disable 649 // Unaasigned fields

#if LIGHT_EXPRESSION
using static FastExpressionCompiler.LightExpression.Expression;
namespace FastExpressionCompiler.LightExpression.UnitTests
#else
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.UnitTests
#endif
{
[TestFixture]
public class Issue146_bool_par_error
{

class MyObject
{
public bool a<b>(b i)
{
return Equals(i, false);
}
}


[Test]
public void Test1()
{
var objParam = Parameter(typeof(MyObject), "myObj");
var boolParam = Parameter(typeof(bool), "isSomething");
var myMethod = typeof(MyObject).GetMethod("a").MakeGenericMethod(typeof(bool));
var call = Call(objParam, myMethod, boolParam);

var lambda = Lambda<Func<MyObject, bool, bool>>(
call,
objParam,
boolParam);

var func = lambda.CompileFast();

var ret = func.Invoke(new MyObject(), false);

Assert.AreEqual(true, ret);
}


private class MyClass
{
public bool MyMethod<T>(bool i)
{
Console.WriteLine("Got " + i);

return Equals(i, false);
}
}

[Test]
public void Test2()
{
var objParam = Parameter(typeof(MyClass), "myObj");
var boolParam = Parameter(typeof(bool), "isSomething");
var myMethod = typeof(MyClass).GetMethod("MyMethod").MakeGenericMethod(typeof(object));
var call = Call(objParam, myMethod, boolParam);

var lambda = Lambda<Func<MyClass, bool, bool>>(
call,
objParam,
boolParam);

var func = lambda.CompileFast();

func.Invoke(new MyClass(), false);
}
}
}
67 changes: 67 additions & 0 deletions test/FastExpressionCompiler.IssueTests/Issue147_int_try_parse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Linq;
using System.Reflection;
using NUnit.Framework;

#pragma warning disable IDE1006 // Naming Styles for linq2db
#pragma warning disable 649 // Unaasigned fields

#if LIGHT_EXPRESSION
using static FastExpressionCompiler.LightExpression.Expression;
namespace FastExpressionCompiler.LightExpression.UnitTests
#else
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.UnitTests
#endif
{
[TestFixture]
public class Issue147_int_try_parse
{

class MyObject
{
public bool a<b>(b i)
{
return Equals(i, false);
}
}

#if !LIGHT_EXPRESSION
[Test]
public void Test1()
{
var intValueParameter = Parameter(typeof(int), "intValue");

var tryParseMethod = typeof(int)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.First(m => m.Name == "TryParse" && m.GetParameters().Length == 2);

var tryParseCall = Call(
tryParseMethod,
Constant("123", typeof(string)),
intValueParameter);

var parsedValueOrDefault = Condition(
tryParseCall,
intValueParameter,
Default(typeof(int)));

var conditionBlock = Block(new[] { intValueParameter }, parsedValueOrDefault);

var conditionLambda = Lambda<Func<int>>(conditionBlock);

var conditionFunc = conditionLambda.Compile();

var parsedValue = conditionFunc.Invoke();


var conditionFuncFast = conditionLambda.CompileFast();

var parsedValueFast = conditionFuncFast.Invoke();

Assert.AreEqual(parsedValue, parsedValueFast);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Collections.Generic;
using NUnit.Framework;
#pragma warning disable 659

#if LIGHT_EXPRESSION
using static FastExpressionCompiler.LightExpression.Expression;
namespace FastExpressionCompiler.LightExpression.UnitTests
#else
using static System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.UnitTests
#endif
{
using System;
using System.Linq;
using System.Reflection;

[TestFixture]
public class Issue150_New_AttemptToReadProtectedMemory
{
[Test]
public void Nested_Assignments_Should_Work()
{
// Builds:
//
// dsosToPpssData =>
// {
// var publicPropertyStruct_String = dsosToPpssData.Target;
// string valueKey;
// object value;
// publicPropertyStruct_String.Value = ((valueKey = dsosToPpssData.Source.Keys.FirstOrDefault(key => key.MatchesKey("Value"))) != null)
// ? ((value = dsosToPpssData.Source[valueKey]) != null) ? value.ToString() : null
// : null;

// return publicPropertyStruct_String;
// }

var mappingDataParameter = Parameter(
typeof(MappingData<Dictionary<string, int>, PublicPropertyStruct<string>>),
"dsosToPpssData");

var structVariable = Variable(typeof(PublicPropertyStruct<string>), "publicPropertyStruct_String");

var structVariableAssignment = Assign(structVariable, Property(mappingDataParameter, "Target"));

var sourceDictionary = Property(mappingDataParameter, "Source");
var nullString = Default(typeof(string));
var valueKeyVariable = Variable(typeof(string), "valueKey");

var linqFirstOrDefaultMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.First(m => m.Name == "FirstOrDefault" && m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(string));

var dictionaryKeys = Property(sourceDictionary, "Keys");

var keyParameter = Parameter(typeof(string), "key");
var matchesKeyMethod = typeof(MyIssueExtensions).GetMethod("MatchesKey");
var matchesKeyCall = Call(matchesKeyMethod, keyParameter, Constant("Value"));
var matchesKeyLambda = Lambda<Func<string, bool>>(matchesKeyCall, keyParameter);

var firstOrDefaultKeyCall = Call(linqFirstOrDefaultMethod, dictionaryKeys, matchesKeyLambda);

var valueKeyAssignment = Assign(valueKeyVariable, firstOrDefaultKeyCall);
var valueKeyNotNull = NotEqual(valueKeyAssignment, nullString);

var valueVariable = Variable(typeof(object), "value");

var dictionaryIndexer = sourceDictionary.Type.GetProperties().First(p => p.GetIndexParameters().Length != 0);
var dictionaryIndexAccess = MakeIndex(sourceDictionary, dictionaryIndexer, new[] { valueKeyVariable });
var dictionaryValueAsObject = Convert(dictionaryIndexAccess, typeof(object));

var valueAssignment = Assign(valueVariable, dictionaryValueAsObject);
var valueNotNull = NotEqual(valueAssignment, Default(valueVariable.Type));

var objectToStringMethod = valueVariable.Type.GetMethod("ToString");
var valueToString = Call(valueVariable, objectToStringMethod);

var valueToStringOrNull = Condition(valueNotNull, valueToString, nullString);

var dictionaryEntryOrNull = Condition(valueKeyNotNull, valueToStringOrNull, nullString);

var structValueProperty = Property(structVariable, "Value");

var structValueAssignment = Assign(structValueProperty, dictionaryEntryOrNull);

var structPopulation = Block(
new[] { valueKeyVariable, valueVariable },
structValueAssignment);

var structMapping = Block(
new[] { structVariable },
structVariableAssignment,
structPopulation,
structVariable);

var populationLambda = Lambda<Func<MappingData<Dictionary<string, int>, PublicPropertyStruct<string>>, PublicPropertyStruct<string>>>(
structMapping,
mappingDataParameter);

var populationFunc = populationLambda.CompileFast();
populationFunc.Invoke(new MappingData<Dictionary<string, int>, PublicPropertyStruct<string>>
{
Source = new Dictionary<string, int> { ["Value"] = 123 },
Target = new PublicPropertyStruct<string>()
});
}

public class MappingData<TSource, TTarget>
{
public TSource Source { get; set; }

public TTarget Target { get; set; }
}

public struct PublicPropertyStruct<T>
{
public T Value { get; set; }
}
}

public static class MyIssueExtensions
{
public static bool MatchesKey(this string value, string other) => value == other;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using NUnit.Framework;
#pragma warning disable 659
#if LIGHT_EXPRESSION
using static FastExpressionCompiler.LightExpression.Expression;
namespace FastExpressionCompiler.LightExpression.UnitTests
#else
using System.Linq.Expressions;
using static System.Linq.Expressions.Expression;
namespace FastExpressionCompiler.UnitTests
#endif
{
[TestFixture]
public class Issue153_MinValueMethodNotSupported
{
[Test]
public void Int_MinValue_Should_Work()
{
var minValueField = typeof(int).GetField("MinValue");
var minValue = Field(null, minValueField);
var minValueLambda = Lambda<Func<int>>(minValue);
var res = minValueLambda.CompileFast();
Assert.AreEqual(int.MinValue, res());
}
}
}
Loading