Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
RupertAvery committed Aug 14, 2014
1 parent 9edc9f2 commit 6fd8e57
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 99 deletions.
45 changes: 37 additions & 8 deletions CompiledExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@

namespace ExpressionEvaluator
{
public class ParseException : Exception
{
public string Expression { get; private set; }

public ParseException(string expression, string message) : base(message)
{
Expression = expression;
}

public ParseException(string expression, string message, Exception innerException)
: base(message, innerException)
{
Expression = expression;
}
}

/// <summary>
/// Creates compiled expressions with return values that are of type T
Expand All @@ -13,7 +28,7 @@ public class CompiledExpression<TResult> : ExpressionCompiler
{
private Func<TResult> _compiledMethod = null;
private Action _compiledAction = null;

public CompiledExpression()
{
Parser = new AntlrParser();
Expand All @@ -28,8 +43,15 @@ public CompiledExpression(string expression)

public Func<TResult> Compile(bool isCall = false)
{
Expression = WrapExpression(BuildTree(), false);
return Expression.Lambda<Func<TResult>>(Expression).Compile();
try
{
Expression = WrapExpression(BuildTree(), false);
return Expression.Lambda<Func<TResult>>(Expression).Compile();
}
catch (Exception ex)
{
throw new ParseException(Parser.ExpressionString, "An error occured while parsing the expression. See the InnerException property for details", ex);
}
}

public Expression<T> GenerateLambda<T, TParam>(bool withScope, bool asCall)
Expand Down Expand Up @@ -95,13 +117,20 @@ public Func<TParam, TResult> ScopeCompile<TParam>()

private T CompileWithScope<T, TParam>(bool asCall)
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = BuildTree(scopeParam, asCall);
if (typeof(TResult) == typeof(object) && Expression.Type != typeof(object) && Expression.Type != typeof(void))
try
{
var scopeParam = Expression.Parameter(typeof(TParam), "scope");
Expression = BuildTree(scopeParam, asCall);
if (typeof(TResult) == typeof(object) && Expression.Type != typeof(object) && Expression.Type != typeof(void))
{
Expression = Expression.Convert(Expression, typeof(object));
}
return Expression.Lambda<T>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}
catch (Exception ex)
{
Expression = Expression.Convert(Expression, typeof(object));
throw new ParseException(Parser.ExpressionString, "An error occured while parsing the expression. See the InnerException property for details", ex);
}
return Expression.Lambda<T>(Expression, new ParameterExpression[] { scopeParam }).Compile();
}

protected override void ClearCompiledMethod()
Expand Down
8 changes: 4 additions & 4 deletions ExpressionCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ namespace ExpressionEvaluator
{
public abstract class ExpressionCompiler
{

public Expression Expression { get; set; }
public CompiledExpressionType ExpressionType { get; set; }
public LambdaExpression LambdaExpression { get; set; }
public string SubScope { get; set; }
public Type SubScopeType { get; set; }

protected AntlrParser Parser = null;
public TypeRegistry TypeRegistry { get; set; }

public Dictionary<string, Type> DynamicTypeLookup { get; set; }

protected string Pstr = null;

public string StringToParse
Expand All @@ -34,8 +35,7 @@ protected Expression BuildTree(Expression scopeParam = null, bool isCall = false
{
Parser.TypeRegistry = TypeRegistry;
Parser.ExpressionType = ExpressionType;
Parser.SubScope = SubScope;
Parser.SubScopeType = SubScopeType;
Parser.DynamicTypeLookup = DynamicTypeLookup;
return Expression = Parser.Parse(scopeParam, isCall);
}

Expand Down
19 changes: 3 additions & 16 deletions Parser/AntlrParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ public class AntlrParser
public Expression Expression { get; set; }

public TypeRegistry TypeRegistry { get; set; }

public Dictionary<string, Type> DynamicTypeLookup { get; set; }

public AntlrParser()
{
Expand All @@ -32,20 +34,8 @@ public Expression Parse(Expression scope, bool isCall = false)
var tokens = new TokenRewriteStream(lexer);
if (TypeRegistry == null) TypeRegistry = new TypeRegistry();

Expression subScope = null;
if (!string.IsNullOrEmpty(SubScope))
{
if (SubScopeType != null)
{
subScope = Expression.Convert(Expression.Property(scope, SubScope), SubScopeType);
}
else
{
subScope = Expression.Property(scope, SubScope);
}
}

var parser = new ExprEvalParser(tokens) { TypeRegistry = TypeRegistry, Scope = scope, IsCall = isCall, SubScope = subScope };
var parser = new ExprEvalParser(tokens) { TypeRegistry = TypeRegistry, Scope = scope, IsCall = isCall, DynamicTypeLookup = DynamicTypeLookup };
if (ExternalParameters != null)
{
parser.ParameterList.Add(ExternalParameters);
Expand Down Expand Up @@ -77,8 +67,5 @@ public Expression Parse(Expression scope, bool isCall = false)
public List<ParameterExpression> ExternalParameters { get; set; }
public Type ReturnType { get; set; }

public string SubScope { get; set; }

public Type SubScopeType { get; set; }
}
}
45 changes: 16 additions & 29 deletions Parser/ExprEval.g3
Original file line number Diff line number Diff line change
Expand Up @@ -153,41 +153,28 @@ public primary_expression returns [Expression value]

if($value == null)
{
if(SubScope != null)
{
$value = SubScope;

// if initial identifier not found, assume Scope variable
input.Rewind(savepoint);
fakedot = true;

$value = GetPrimaryExpressionPart(primary_expression_part(), input, $value, method, false);

if($value == null)
{
$value = Scope;
$value = Scope;

var text = $primary_expression_start.text;

var method1 = new TypeOrGeneric() { Identifier = "getVar" };
var args1 = new List<Expression>() { Expression.Constant(text, typeof(string)) };

var pe = (ParameterExpression)$value;

var type1 = GetPropertyType(Scope.Type, text);
var text = $primary_expression_start.text;

$value = Expression.Convert(ExpressionHelper.GetMethod($value, method1, args1, false), type1);

if($value == null)
{
throw new ExpressionParseException(string.Format("Cannot resolve symbol \"{0}\"", input.LT(-1).Text), input);
}
}
}
var method1 = new TypeOrGeneric() { Identifier = "getVar" };
var args1 = new List<Expression>() { Expression.Constant(text, typeof(string)) };
if(DynamicTypeLookup != null && DynamicTypeLookup.ContainsKey(text))
{
var type1 = DynamicTypeLookup[text];
$value = Expression.Convert(ExpressionHelper.GetMethod($value, method1, args1, false), type1);
}
else
{
$value = ExpressionHelper.GetMethod($value, method1, args1, false);
}

if($value == null)
{
throw new ExpressionParseException(string.Format("Cannot resolve symbol \"{0}\"", input.LT(-1).Text), input);
}

}
}
else
Expand Down Expand Up @@ -221,7 +208,7 @@ public primary_expression returns [Expression value]
{
if(method!=null)
{
$value = ExpressionHelper.GetMethod($value, method, ((Arguments)$primary_expression_part.value).Values, IsCall);
$value = ExpressionHelper.GetMethod($value, method, ((Arguments)$primary_expression_part.value).Values, false);
if($value==null)
{
throw new ExpressionParseException(string.Format("Cannot resolve symbol \"{0}\"", input.LT(-1).Text), input);
Expand Down
21 changes: 14 additions & 7 deletions Parser/ExprEval.g3.parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ public partial class ExprEvalParser
private CompilerState compilerState = new CompilerState();

public Expression Scope { get; set; }
public Expression SubScope { get; set; }

public bool IsCall { get; set; }
public LabelTarget ReturnTarget { get; set; }
public bool HasReturn { get; private set; }
public TypeRegistry TypeRegistry { get; set; }

public Dictionary<string, Type> DynamicTypeLookup { get; set; }

//partial void EnterRule(string ruleName, int ruleIndex)
//{
// base.TraceIn(ruleName, ruleIndex);
Expand All @@ -31,11 +33,16 @@ public partial class ExprEvalParser
// Debug.WriteLine("Out: {0} {1}", ruleName, ruleIndex);
//}

protected Type GetPropertyType(object instance, string propertyName)
{
var methodInfo = instance.GetType().GetMethod("getType", BindingFlags.Instance);
return (Type)methodInfo.Invoke(instance, new object[] { propertyName });
}
//protected Type GetPropertyType(Expression expression, string propertyName)
//{
// var pe = (ParameterExpression) expression;
// var methodInfo = pe.Type.GetMethod("getType", BindingFlags.Instance);
// if (methodInfo != null)
// {
// return (Type)methodInfo.Invoke(pe., new object[] { propertyName });
// }
// return null;
//}


protected Expression GetPrimaryExpressionPart(PrimaryExpressionPart primary_expression_part2, ITokenStream input, Expression value, TypeOrGeneric method, bool throwsException = true)
Expand Down Expand Up @@ -63,7 +70,7 @@ protected Expression GetPrimaryExpressionPart(PrimaryExpressionPart primary_expr
{
if (method != null)
{
value = ExpressionHelper.GetMethod(value, method, ((Arguments)primary_expression_part2).Values, IsCall);
value = ExpressionHelper.GetMethod(value, method, ((Arguments)primary_expression_part2).Values, false);
if (value == null && throwsException)
{
throw new ExpressionParseException(string.Format("Cannot resolve symbol \"{0}\"", input.LT(-1).Text), input);
Expand Down
5 changes: 3 additions & 2 deletions Parser/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public static Expression Assign(Expression le, Expression re)
var ce = (ConstantExpression) mc.Arguments[0];
var method1 = new TypeOrGeneric() { Identifier = "setVar" };
var args1 = new List<Expression>() { Expression.Constant(ce.Value, typeof(string)), Expression.Convert(re, typeof(object)) };
return GetMethod(mc.Object, method1, args1, true);
return GetMethod(mc.Object, method1, args1, false);
}
}

Expand Down Expand Up @@ -780,7 +780,7 @@ public static Expression BinaryOperator(Expression le, Expression re, Expression
else
{
re = TypeConversion.ImplicitConversion(le, re);

le = TypeConversion.DynamicConversion(re, le);
return GetBinaryOperator(le, re, expressionType);
}
}
Expand Down Expand Up @@ -988,6 +988,7 @@ public static Expression Condition(Expression condition, Expression ifTrue, Expr
}

// perform implicit conversion on known types ???
condition = TypeConversion.Convert(condition, typeof(bool));
TypeConversion.Convert(ref ifFalse, ref ifTrue);
return Expression.Condition(condition, ifTrue, ifFalse);
}
Expand Down
42 changes: 19 additions & 23 deletions Parser/TypeConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace ExpressionEvaluator.Parser
internal class TypeConversion
{
private static Dictionary<Type, List<Type>> ImplicitNumericConversions = new Dictionary<Type, List<Type>>();
private static List<Type> NumericTypes = new List<Type>();


//public static void ConvertType(ExpressionType expressionType, ref Expression a, ref Expression b, Type type, Type[] otherTypes, Type[] invalidTypes, Type targetType)
//{
Expand Down Expand Up @@ -83,6 +83,14 @@ internal static Expression Convert(Expression le, Type type)
{
if (Instance._typePrecedence[le.Type] < Instance._typePrecedence[type]) return Expression.Convert(le, type);
}
if (le.Type.IsNullable())
{
le = Expression.Property(le, "Value");
}
if (type == typeof (object))
{
return Expression.Convert(le, type);
}
return le;
}

Expand Down Expand Up @@ -150,18 +158,26 @@ public static Expression ImplicitConversion(Expression dest, Expression src)
{
if (dest.Type != src.Type)
{
if (IsNumericType(dest.Type) && IsNumericType(src.Type))
if (dest.Type.IsNumericType() && src.Type.IsNumericType())
{
src = ImplicitNumericConversion(src, dest.Type);
}
src = NullLiteralConverion(dest, src);
src = ReferenceConversion(dest, src);
src = BoxingConversion(dest, src);
src = DynamicConversion(dest, src);
}
return src;
}


public static Expression DynamicConversion(Expression dest, Expression src)
{
if (src.Type.IsObject())
{
return Expression.Convert(src, dest.Type);
}
return src;
}

// 6.1.2 Implicit numeric conversions

Expand All @@ -178,11 +194,6 @@ public static Expression ImplicitNumericConversion(Expression src, Type target)
return src;
}

public static bool IsNumericType(Type t)
{
return NumericTypes.Contains(t);
}

TypeConversion()
{
_typePrecedence = new Dictionary<Type, int>
Expand All @@ -197,21 +208,6 @@ public static bool IsNumericType(Type t)
{typeof (double), 7}
};

NumericTypes = new List<Type>()
{
typeof (sbyte),
typeof (byte),
typeof (short),
typeof (ushort),
typeof (int),
typeof (uint),
typeof (long),
typeof (ulong),
typeof (char),
typeof (float),
typeof (double)
};

ImplicitNumericConversions.Add(typeof(sbyte), new List<Type>() { typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(byte), new List<Type>() { typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(short), new List<Type>() { typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
Expand Down
Loading

0 comments on commit 6fd8e57

Please sign in to comment.