Skip to content

Commit

Permalink
Fix for codeplex issue #15 - Variable instantiation occurs too early
Browse files Browse the repository at this point in the history
  • Loading branch information
RupertAvery committed Jul 30, 2014
1 parent 0b7027c commit 3d4a6e2
Show file tree
Hide file tree
Showing 7 changed files with 171 additions and 122 deletions.
255 changes: 150 additions & 105 deletions CompiledExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public CompiledExpression()
public CompiledExpression(string expression)
{
Parser = new AntlrParser(expression);
Parser.ReturnType = typeof(TResult);
}

public Func<TResult> Compile(bool isCall = false)
Expand All @@ -31,6 +32,29 @@ public Func<TResult> Compile(bool isCall = false)
return Expression.Lambda<Func<TResult>>(Expression).Compile();
}

public Expression<T> GenerateLambda<T, TParam>(bool withScope, bool asCall)
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
var expression = withScope ? BuildTree(scopeParam, asCall) : BuildTree();
Expression = WrapExpression(expression, false);
return withScope ?
Expression.Lambda<T>(Expression, new ParameterExpression[] { scopeParam }) :
Expression.Lambda<T>(Expression)
;
}

private T Compile<T, TParam>(bool withScope, bool asCall)
{
return GenerateLambda<T, TParam>(withScope, asCall).Compile();
}

// public LambdaExpression GenerateLambda()
// {
// var scopeParam = Expression.Parameter(typeof(object), "scope");
// Expression = WrapExpression(BuildTree(scopeParam), true);
// return Expression.Lambda<Func<dynamic, object>>(Expression, new ParameterExpression[] { scopeParam });
// }

/// <summary>
/// Compiles the expression to a function that returns void
/// </summary>
Expand All @@ -41,31 +65,39 @@ public Action CompileCall()
return Expression.Lambda<Action>(Expression).Compile();
}

/// <summary>
/// Compiles the expression to a function that takes an object as a parameter and returns an object
/// </summary>
/// <returns></returns>
public Action<object> ScopeCompileCall()
{
return ScopeCompileCall<object>();
}

/// <summary>
/// Compiles the expression to a function that takes an object as a parameter and returns an object
/// </summary>s
/// <returns></returns>
public Action<TParam> ScopeCompileCall<TParam>()
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = BuildTree(scopeParam, true);
return Expression.Lambda<Action<TParam>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
return CompileWithScope<Action<TParam>, TParam>(true);
}


public Func<object, TResult> ScopeCompile()
{
var scopeParam = Expression.Parameter(typeof(object), "scope");
Expression = WrapExpression(BuildTree(scopeParam), false);
return Expression.Lambda<Func<dynamic, TResult>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
return ScopeCompile<object>();
}

public Func<TParam, TResult> ScopeCompile<TParam>()
{
return CompileWithScope<Func<TParam, TResult>, TParam>(false);
}

private T CompileWithScope<T, TParam>(bool asCall)
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = WrapExpression(BuildTree(scopeParam), false);
return Expression.Lambda<Func<TParam, TResult>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
Expression = BuildTree(scopeParam, asCall);
return Expression.Lambda<T>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}

protected override void ClearCompiledMethod()
Expand Down Expand Up @@ -99,120 +131,133 @@ public object Global
/// <summary>
/// Creates compiled expressions with return values that are cast to type Object
/// </summary>
public class CompiledExpression : ExpressionCompiler
public class CompiledExpression : CompiledExpression<object>
{
private Func<object> _compiledMethod = null;
private Action _compiledAction = null;

public CompiledExpression()
{
Parser = new AntlrParser();
Parser.ReturnType = typeof(object);
}

public CompiledExpression(string expression)
: base(expression)
{
Parser = new AntlrParser(expression);
}

/// <summary>
/// Compiles the expression to a function that returns an object
/// </summary>
/// <returns></returns>
public Func<object> Compile()
{
Expression = WrapExpression(BuildTree(), true);
return Expression.Lambda<Func<object>>(Expression).Compile();
}
}

/// <summary>
/// Compiles the expression to a function that returns void
/// </summary>
/// <returns></returns>
public Action CompileCall()
{
Expression = BuildTree(null, true);
return Expression.Lambda<Action>(Expression).Compile();
}
//public class CompiledExpression : ExpressionCompiler
//{
// private Func<object> _compiledMethod = null;
// private Action _compiledAction = null;

/// <summary>
/// Compiles the expression to a function that takes an object as a parameter and returns an object
/// </summary>
/// <returns></returns>
public Func<object, object> ScopeCompile()
{
var scopeParam = Expression.Parameter(typeof(object), "scope");
Expression = WrapExpression(BuildTree(scopeParam), true);
return Expression.Lambda<Func<dynamic, object>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}
// public CompiledExpression()
// {
// Parser = new AntlrParser();
// Parser.ReturnType = typeof(object);
// }

public LambdaExpression GenerateLambda()
{
var scopeParam = Expression.Parameter(typeof(object), "scope");
Expression = WrapExpression(BuildTree(scopeParam), true);
return Expression.Lambda<Func<dynamic, object>>(Expression, new ParameterExpression[] { scopeParam });
}
// public CompiledExpression(string expression)
// {
// Parser = new AntlrParser(expression);
// }

/// <summary>
/// Compiles the expression to a function that takes an object as a parameter and returns an object
/// </summary>
/// <returns></returns>
public Action<object> ScopeCompileCall()
{
var scopeParam = Expression.Parameter(typeof(object), "scope");
Expression = BuildTree(scopeParam, true);
return Expression.Lambda<Action<dynamic>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}
// /// <summary>
// /// Compiles the expression to a function that returns an object
// /// </summary>
// /// <returns></returns>
// public Func<object> Compile()
// {
// Expression = WrapExpression(BuildTree(), true);
// return Expression.Lambda<Func<object>>(Expression).Compile();
// }

/// <summary>
/// Compiles the expression to a function that takes an object as a parameter and returns an object
/// </summary>s
/// <returns></returns>
public Action<TParam> ScopeCompileCall<TParam>()
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = WrapToVoid(BuildTree(scopeParam));
return Expression.Lambda<Action<TParam>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}

/// <summary>
/// Compiles the expression to a function that takes an typed object as a parameter and returns an object
/// </summary>
/// <typeparam name="U"></typeparam>
/// <returns></returns>
public Func<TParam, object> ScopeCompile<TParam>()
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = WrapExpression(BuildTree(scopeParam), true);
return Expression.Lambda<Func<TParam, object>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}
// /// <summary>
// /// Compiles the expression to a function that returns void
// /// </summary>
// /// <returns></returns>
// public Action CompileCall()
// {
// Expression = BuildTree(null, true);
// return Expression.Lambda<Action>(Expression).Compile();
// }

protected override void ClearCompiledMethod()
{
_compiledMethod = null;
_compiledAction = null;
}
// /// <summary>
// /// Compiles the expression to a function that takes an object as a parameter and returns an object
// /// </summary>
// /// <returns></returns>
// public Func<object, object> ScopeCompile()
// {
// var scopeParam = Expression.Parameter(typeof(object), "scope");
// Expression = WrapExpression(BuildTree(scopeParam), true);
// return Expression.Lambda<Func<dynamic, object>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
// }

public object Eval()
{
if (_compiledMethod == null) _compiledMethod = Compile();
return _compiledMethod();
}
// public LambdaExpression GenerateLambda()
// {
// var scopeParam = Expression.Parameter(typeof(object), "scope");
// Expression = WrapExpression(BuildTree(scopeParam), true);
// return Expression.Lambda<Func<dynamic, object>>(Expression, new ParameterExpression[] { scopeParam });
// }

public void Call()
{
if (_compiledAction == null) _compiledAction = CompileCall();
_compiledAction();
}
// /// <summary>
// /// Compiles the expression to a function that takes an object as a parameter and returns an object
// /// </summary>
// /// <returns></returns>
// public Action<object> ScopeCompileCall()
// {
// var scopeParam = Expression.Parameter(typeof(object), "scope");
// Expression = BuildTree(scopeParam, true);
// return Expression.Lambda<Action<dynamic>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
// }

public object Global
{
set
{
Parser.Global = value;
}
}
// /// <summary>
// /// Compiles the expression to a function that takes an object as a parameter and returns an object
// /// </summary>s
// /// <returns></returns>
// public Action<TParam> ScopeCompileCall<TParam>()
// {
// var scopeParam = Expression.Parameter(typeof(TParam), "scope");
// Expression = WrapToVoid(BuildTree(scopeParam));
// return Expression.Lambda<Action<TParam>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
// }

}
// /// <summary>
// /// Compiles the expression to a function that takes an typed object as a parameter and returns an object
// /// </summary>
// /// <typeparam name="U"></typeparam>
// /// <returns></returns>
// public Func<TParam, object> ScopeCompile<TParam>()
// {
// var scopeParam = Expression.Parameter(typeof(TParam), "scope");
// Expression = WrapExpression(BuildTree(scopeParam), true);
// return Expression.Lambda<Func<TParam, object>>(Expression, new ParameterExpression[] { scopeParam }).Compile();
// }

// protected override void ClearCompiledMethod()
// {
// _compiledMethod = null;
// _compiledAction = null;
// }

// public object Eval()
// {
// if (_compiledMethod == null) _compiledMethod = Compile();
// return _compiledMethod();
// }

// public void Call()
// {
// if (_compiledAction == null) _compiledAction = CompileCall();
// _compiledAction();
// }

// public object Global
// {
// set
// {
// Parser.Global = value;
// }
// }

//}
}
9 changes: 9 additions & 0 deletions CompiledExpressionType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ExpressionEvaluator
{
public enum CompiledExpressionType
{
Expression = 0,
Statement = 1,
StatementList = 2
}
}
7 changes: 0 additions & 7 deletions ExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@

namespace ExpressionEvaluator
{
public enum CompiledExpressionType
{
Expression = 0,
Statement = 1,
StatementList = 2
}

public abstract class ExpressionCompiler
{
public Expression Expression { get; set; }
Expand Down
1 change: 1 addition & 0 deletions ExpressionEvaluator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="CompiledExpression.cs" />
<Compile Include="CompiledExpressionType.cs" />
<Compile Include="ExpressionCompiler.cs" />
<Compile Include="obj\Debug\ExprEvalLexer.cs" />
<Compile Include="obj\Debug\ExprEvalParser.cs" />
Expand Down
5 changes: 3 additions & 2 deletions Parser/ExprEval.g3
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,10 @@ public type_arguments returns [List<Type> value]
first=type { $value.Add(GetType($first.text)); } (',' succeeding=type { $value.Add(GetType($succeeding.text)); })* ;

public type returns [TypeOrGeneric value]:
((predefined_type | type_name) rank_specifiers) => (predefined_type | type_name) rank_specifiers '*'*
((predefined_type | type_name) rank_specifiers) => (predefined_type | type_name) rank_specifiers '*'*
| ((predefined_type | type_name) ('*'+ | '?')) => (predefined_type | type_name) ('*'+ | '?')
| (predefined_type { $value = new TypeOrGeneric() { Identifier = $predefined_type.text }; }| type_name { $value = $type_name.value; })
| (predefined_type { $value = new TypeOrGeneric() { Identifier = $predefined_type.text }; }
| type_name { $value = $type_name.value; })
| 'void' '*'+
;
public non_nullable_type:
Expand Down
3 changes: 2 additions & 1 deletion Parser/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ public static Expression GetPropertyIndex(Expression le, IEnumerable<Expression>

}


public static Expression Assign(Expression le, Expression re)
{
var type = le.Type;
Expand Down Expand Up @@ -553,6 +552,8 @@ private static Expression OldMethodHandler(Type type, Expression instance, TypeO

var targetType = lastParam2.ParameterType.GetElementType();

if (targetType == null) targetType = lastParam2.ParameterType.GetGenericArguments().Single();

newArgs2.Add(Expression.NewArrayInit(targetType,
paramArgs2.Select(x => TypeConversion.Convert(x, targetType))));
return Expression.Call(instance, info2.Item1, newArgs2);
Expand Down
Loading

0 comments on commit 3d4a6e2

Please sign in to comment.