-
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathCompileExpression.cs
More file actions
90 lines (75 loc) · 3.54 KB
/
CompileExpression.cs
File metadata and controls
90 lines (75 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using SM = StringMath.Expressions;
using System;
using System.Linq.Expressions;
using System.Linq;
using System.Collections.Generic;
namespace StringMath
{
internal class CompileExpression
{
private static readonly ParameterExpression _contextParam = Expression.Parameter(typeof(IMathContext), "__internal_ctx");
private List<ParameterExpression> _parameters = new List<ParameterExpression>();
private readonly IVariablesCollection _variables;
public CompileExpression(IVariablesCollection variables)
{
_variables = variables;
}
public T Compile<T>(SM.IExpression expression, params string[] parameters)
=> VisitWithParameters<T>(expression, parameters).Compile();
private Expression<T> VisitWithParameters<T>(SM.IExpression expression, params string[] parameters)
{
_parameters = new List<ParameterExpression>(1 + parameters.Length)
{
_contextParam
};
foreach (var parameter in parameters)
{
_parameters.Add(Expression.Parameter(typeof(double), parameter));
}
var result = Visit(expression);
return Expression.Lambda<T>(result, _parameters);
}
public Expression Visit(SM.IExpression expression)
{
Expression result = expression switch
{
SM.BinaryExpression binaryExpr => VisitBinaryExpr(binaryExpr),
SM.ConstantExpression constantExpr => VisitConstantExpr(constantExpr),
SM.UnaryExpression unaryExpr => VisitUnaryExpr(unaryExpr),
SM.VariableExpression variableExpr => VisitVariableExpr(variableExpr),
SM.InvocationExpression invocationExpr => VisitInvocationExpr(invocationExpr),
_ => throw new NotImplementedException($"'{expression?.GetType().Name}' Convertor is not implemented.")
};
return result;
}
private Expression VisitVariableExpr(SM.VariableExpression variableExpr)
{
var parameter = _parameters.FirstOrDefault(x => x.Name == variableExpr.Name);
if (parameter != null)
return parameter;
if(_variables.TryGetValue(variableExpr.Name, out var variable))
return Expression.Constant(variable);
throw MathException.MissingVariable(variableExpr.Name);
}
private Expression VisitConstantExpr(SM.ConstantExpression constantExpr) => Expression.Constant(constantExpr.Value);
private Expression VisitBinaryExpr(SM.BinaryExpression binaryExpr) =>
Expression.Call(_contextParam,
nameof(IMathContext.EvaluateBinary),
null,
Expression.Constant(binaryExpr.OperatorName), Visit(binaryExpr.Left), Visit(binaryExpr.Right));
private Expression VisitUnaryExpr(SM.UnaryExpression unaryExpr) =>
Expression.Call(_contextParam,
nameof(IMathContext.EvaluateUnary),
null,
Expression.Constant(unaryExpr.OperatorName), Visit(unaryExpr.Operand));
private Expression VisitInvocationExpr(SM.InvocationExpression invocationExpr)
{
var args = invocationExpr.Arguments.Select(Visit).ToArray();
return Expression.Call(_contextParam,
nameof(IMathContext.InvokeFunction),
null,
Expression.Constant(invocationExpr.Name),
Expression.NewArrayInit(typeof(double), args));
}
}
}