~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/AddIns/Misc/Reports/ICSharpCode.Reports.Core/Project/Expressions/SimpleExpressionEvaluator/Parser/ExpressionCompiler.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
using System;
 
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;
 
8
 
 
9
namespace SimpleExpressionEvaluator.Parser
 
10
{
 
11
    public class ExpressionCompiler : IExpressionCompiler
 
12
    {
 
13
        protected DefaultExpressionNodeFactory ExpressionNodeFactory { get; set; }
 
14
        
 
15
 
 
16
        public ExpressionCompiler(params Assembly[] assembliesToRegister)
 
17
        {
 
18
            ExpressionNodeFactory = new DefaultExpressionNodeFactory();
 
19
            if (assembliesToRegister != null)
 
20
                Array.ForEach(assembliesToRegister,RegisterAssembly);
 
21
        }
 
22
 
 
23
        public void RegisterAssembly(Assembly asm)
 
24
        {
 
25
            ExpressionNodeFactory.RegisterAssembly(asm);
 
26
        }
 
27
 
 
28
        #region IExpressionCompiler Members
 
29
 
 
30
        public IExpression<T> CompileExpression<T>(string expression)
 
31
        {
 
32
            var s = new Scanner();
 
33
            var parser = new Parser(s);
 
34
 
 
35
            ParseTree ast = parser.Parse(expression);
 
36
 
 
37
            return CompileExpression<T>(ast);
 
38
        }
 
39
 
 
40
        #endregion
 
41
 
 
42
        protected virtual IExpression<T> CompileExpression<T>(ParseNode root)
 
43
        {
 
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>();
 
48
        }
 
49
 
 
50
        protected virtual IExpression CompileExpressionNode(IExpressionNodeFactory factory,ParseNode astNode)
 
51
        {
 
52
            switch (astNode.Token.Type)
 
53
            {
 
54
                case TokenType.Atom:
 
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);
 
65
                case TokenType.TRUE:
 
66
                case TokenType.FALSE:
 
67
                    var bln = TypeNormalizer.EnsureType<bool>(astNode.Token.Text);
 
68
                    return factory.CreateLiteral(bln);
 
69
                case TokenType.NULL:
 
70
                    return null;
 
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);
 
87
                    else
 
88
                    {
 
89
                        func.AcceptArguments(condition, trueExpr);
 
90
                    }
 
91
                    return func;
 
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);
 
96
 
 
97
            }
 
98
            return null;
 
99
        }
 
100
 
 
101
        private IExpression CompileBinaryOperator(IExpressionNodeFactory factory,ParseNode opNode)
 
102
        {
 
103
            if (opNode.Nodes.Count == 0)
 
104
                return null;
 
105
            if (opNode.Nodes.Count == 1)
 
106
                return CompileExpressionNode(factory, opNode.Nodes[0]);
 
107
            if (opNode.Nodes.Count >= 3)
 
108
            {
 
109
                int curIndex = 1;
 
110
                IExpression curLeft = CompileExpressionNode(factory, opNode.Nodes[0]);
 
111
 
 
112
                while (curIndex < opNode.Nodes.Count)
 
113
                {
 
114
                    string token = opNode.Nodes[curIndex].Token.Text;
 
115
                    IExpression right = CompileExpressionNode(factory, opNode.Nodes[curIndex + 1]);
 
116
                    curLeft = factory.CreateBinaryOperator(token, curLeft, right);
 
117
                    curIndex += 2;
 
118
                }
 
119
                return curLeft;
 
120
            }
 
121
            throw new Exception(opNode.Text + " has two children. Operators must have three or more children.");
 
122
 
 
123
 
 
124
 
 
125
        }
 
126
        private static IList<ParseNode> Select(IEnumerable<ParseNode> source,params TokenType[] types)
 
127
        {
 
128
            var found = new List<ParseNode>();
 
129
            foreach (ParseNode node in source)
 
130
            {
 
131
                foreach(TokenType type in types)
 
132
                {
 
133
                    if (node.Token.Type == type)
 
134
                        found.Add(node);
 
135
                }
 
136
            }
 
137
            return found;
 
138
        }
 
139
 
 
140
        private IExpression CompileQualifiedName(IExpressionNodeFactory factory,IExpression curContext,IList<ParseNode> identifiers,int startIndex)
 
141
        {
 
142
            if (startIndex >= identifiers.Count)
 
143
                return curContext;
 
144
 
 
145
            int curIndex = startIndex;
 
146
 
 
147
            ParseNode curNode = identifiers[curIndex].Nodes[0];
 
148
            var nameParts = new List<string>();
 
149
 
 
150
            while(curNode != null && curNode.Token.Type == TokenType.IDENTIFIER)
 
151
            {
 
152
                nameParts.Add(curNode.Token.Text);
 
153
                curIndex += 1;
 
154
                curNode = (curIndex < identifiers.Count) ? identifiers[curIndex].Nodes[0] : null;
 
155
            }
 
156
 
 
157
            if (curNode != null)
 
158
            {
 
159
                if (curNode.Token.Type == TokenType.Array)
 
160
                {
 
161
                    nameParts.Add(curNode.Nodes[0].Token.Text);
 
162
                    IExpression arrayContext = new QualifiedName(curContext, nameParts.ToArray());
 
163
                    
 
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);
 
168
                }
 
169
                
 
170
                if (curNode.Token.Type == TokenType.Method)
 
171
                {
 
172
                    var methodContext = nameParts.Count > 0 ? new QualifiedName(curContext,nameParts.ToArray()) : curContext;
 
173
                    string methodName = curNode.Nodes[0].Token.Text;
 
174
 
 
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));
 
181
 
 
182
                    return CompileQualifiedName(factory,factory.CreateFunction(methodName, args.ToArray()),identifiers,curIndex+1);
 
183
                }
 
184
            }
 
185
 
 
186
            if (curContext == null && nameParts.Count == 1)
 
187
                return factory.CreateVariable(nameParts[0]);
 
188
            return new QualifiedName(curContext, nameParts.ToArray());
 
189
        }
 
190
        
 
191
    }
 
192
}