2
using System.Collections.Generic;
3
using System.Reflection;
4
using SimpleExpressionEvaluator.Compilation;
5
using SimpleExpressionEvaluator.Compilation.Functions;
6
using SimpleExpressionEvaluator.Compilation.Functions.AggregateFunctions;
7
using SimpleExpressionEvaluator.Utilities;
9
namespace SimpleExpressionEvaluator.Parser
11
public class ExpressionCompiler : IExpressionCompiler
13
protected DefaultExpressionNodeFactory ExpressionNodeFactory { get; set; }
16
public ExpressionCompiler(params Assembly[] assembliesToRegister)
18
ExpressionNodeFactory = new DefaultExpressionNodeFactory();
19
if (assembliesToRegister != null)
20
Array.ForEach(assembliesToRegister,RegisterAssembly);
23
public void RegisterAssembly(Assembly asm)
25
ExpressionNodeFactory.RegisterAssembly(asm);
28
#region IExpressionCompiler Members
30
public IExpression<T> CompileExpression<T>(string expression)
32
var s = new Scanner();
33
var parser = new Parser(s);
35
ParseTree ast = parser.Parse(expression);
37
return CompileExpression<T>(ast);
42
protected virtual IExpression<T> CompileExpression<T>(ParseNode root)
44
ParseNode expr = root.Nodes[0].Nodes[0];
45
IExpression rootNode = CompileExpressionNode(ExpressionNodeFactory,expr);
46
return new Expression<T>(rootNode);
47
//Expression<T> exp = new Expression<T>();
50
protected virtual IExpression CompileExpressionNode(IExpressionNodeFactory factory,ParseNode astNode)
52
switch (astNode.Token.Type)
55
if (astNode.Nodes[0].Token.Type == TokenType.BROPEN)
56
return CompileExpressionNode(factory, astNode.Nodes[1]);
57
return CompileExpressionNode(factory, astNode.Nodes[0]);
58
case TokenType.NUMBER:
59
case TokenType.INTEGER:
60
var num = TypeNormalizer.EnsureType<double>(astNode.Token.Text);
61
return factory.CreateLiteral(num);
62
case TokenType.STRING:
63
var str = TypeNormalizer.EnsureType<string>(astNode.Token.Text.Replace("\"",String.Empty));
64
return factory.CreateLiteral(str);
67
var bln = TypeNormalizer.EnsureType<bool>(astNode.Token.Text);
68
return factory.CreateLiteral(bln);
71
case TokenType.BooleanExpr:
72
case TokenType.CompareExpr:
73
case TokenType.AddExpr:
74
case TokenType.MultExpr:
75
case TokenType.PowerExpr:
76
return CompileBinaryOperator(factory,astNode);
77
case TokenType.QualifiedName:
78
return CompileQualifiedName(factory, null, Select(astNode.Nodes, TokenType.Identifier), 0);
79
case TokenType.Conditional:
80
var pieces = Select(astNode.Nodes, TokenType.BooleanExpr);
81
IExpression condition = CompileExpressionNode(factory,pieces[0]);
82
IExpression trueExpr = CompileExpressionNode(factory,pieces[1]);
83
IExpression falseExpr = (pieces.Count == 3) ? CompileExpressionNode(factory, pieces[2]) : null;
84
var func = new IfThen();
85
if (falseExpr != null)
86
func.AcceptArguments(condition, trueExpr, falseExpr);
89
func.AcceptArguments(condition, trueExpr);
92
case TokenType.UnaryExpr:
93
string token = astNode.Nodes[0].Token.Text;
94
IExpression left = CompileBinaryOperator(factory, astNode.Nodes[1]);
95
return factory.CreateUnaryOperator(token, left);
101
private IExpression CompileBinaryOperator(IExpressionNodeFactory factory,ParseNode opNode)
103
if (opNode.Nodes.Count == 0)
105
if (opNode.Nodes.Count == 1)
106
return CompileExpressionNode(factory, opNode.Nodes[0]);
107
if (opNode.Nodes.Count >= 3)
110
IExpression curLeft = CompileExpressionNode(factory, opNode.Nodes[0]);
112
while (curIndex < opNode.Nodes.Count)
114
string token = opNode.Nodes[curIndex].Token.Text;
115
IExpression right = CompileExpressionNode(factory, opNode.Nodes[curIndex + 1]);
116
curLeft = factory.CreateBinaryOperator(token, curLeft, right);
121
throw new Exception(opNode.Text + " has two children. Operators must have three or more children.");
126
private static IList<ParseNode> Select(IEnumerable<ParseNode> source,params TokenType[] types)
128
var found = new List<ParseNode>();
129
foreach (ParseNode node in source)
131
foreach(TokenType type in types)
133
if (node.Token.Type == type)
140
private IExpression CompileQualifiedName(IExpressionNodeFactory factory,IExpression curContext,IList<ParseNode> identifiers,int startIndex)
142
if (startIndex >= identifiers.Count)
145
int curIndex = startIndex;
147
ParseNode curNode = identifiers[curIndex].Nodes[0];
148
var nameParts = new List<string>();
150
while(curNode != null && curNode.Token.Type == TokenType.IDENTIFIER)
152
nameParts.Add(curNode.Token.Text);
154
curNode = (curIndex < identifiers.Count) ? identifiers[curIndex].Nodes[0] : null;
159
if (curNode.Token.Type == TokenType.Array)
161
nameParts.Add(curNode.Nodes[0].Token.Text);
162
IExpression arrayContext = new QualifiedName(curContext, nameParts.ToArray());
164
var arrayFunc = new ItemAtIndex();
165
IExpression index = CompileExpressionNode(factory, curNode.Nodes[2]);
166
arrayFunc.AcceptArguments(arrayContext,index);
167
return CompileQualifiedName(factory, arrayFunc, identifiers, curIndex+1);
170
if (curNode.Token.Type == TokenType.Method)
172
var methodContext = nameParts.Count > 0 ? new QualifiedName(curContext,nameParts.ToArray()) : curContext;
173
string methodName = curNode.Nodes[0].Token.Text;
175
IList<ParseNode> argNodes = Select(curNode.Nodes[2].Nodes, TokenType.BooleanExpr);
176
var args = new List<IExpression>();
177
if (methodContext != null)
178
args.Add(methodContext);
179
foreach (ParseNode argNode in argNodes)
180
args.Add(CompileExpressionNode(factory, argNode));
182
return CompileQualifiedName(factory,factory.CreateFunction(methodName, args.ToArray()),identifiers,curIndex+1);
186
if (curContext == null && nameParts.Count == 1)
187
return factory.CreateVariable(nameParts[0]);
188
return new QualifiedName(curContext, nameParts.ToArray());