Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs @ 12074

Last change on this file since 12074 was 12074, checked in by sraggl, 9 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 9.2 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 * ******************************************************************************
29 * Mats Alm                       Added                   2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
30 *******************************************************************************/
31using System;
32using System.Collections.Generic;
33using System.Linq;
34using System.Text;
35using OfficeOpenXml.FormulaParsing.Excel.Operators;
36using OfficeOpenXml.FormulaParsing.Exceptions;
37using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
38using OfficeOpenXml.FormulaParsing.Excel;
39using OfficeOpenXml.FormulaParsing;
40
41namespace OfficeOpenXml.FormulaParsing.ExpressionGraph
42{
43    public class ExpressionGraphBuilder :IExpressionGraphBuilder
44    {
45        private readonly ExpressionGraph _graph = new ExpressionGraph();
46        private readonly IExpressionFactory _expressionFactory;
47        private readonly ParsingContext _parsingContext;
48        private int _tokenIndex = 0;
49        private bool _negateNextExpression;
50
51        public ExpressionGraphBuilder(ExcelDataProvider excelDataProvider, ParsingContext parsingContext)
52            : this(new ExpressionFactory(excelDataProvider, parsingContext), parsingContext)
53        {
54
55        }
56
57        public ExpressionGraphBuilder(IExpressionFactory expressionFactory, ParsingContext parsingContext)
58        {
59            _expressionFactory = expressionFactory;
60            _parsingContext = parsingContext;
61        }
62
63        public ExpressionGraph Build(IEnumerable<Token> tokens)
64        {
65            _tokenIndex = 0;
66            _graph.Reset();
67            var tokensArr = tokens != null ? tokens.ToArray() : new Token[0];
68            BuildUp(tokensArr, null);
69            return _graph;
70        }
71
72        private void BuildUp(Token[] tokens, Expression parent)
73        {
74            while (_tokenIndex < tokens.Length)
75            {
76                var token = tokens[_tokenIndex];
77                IOperator op = null;
78                if (token.TokenType == TokenType.Operator && OperatorsDict.Instance.TryGetValue(token.Value, out op))
79                {
80                    SetOperatorOnExpression(parent, op);
81                }
82                else if (token.TokenType == TokenType.Function)
83                {
84                    BuildFunctionExpression(tokens, parent, token.Value);
85                }
86                else if (token.TokenType == TokenType.OpeningEnumerable)
87                {
88                    _tokenIndex++;
89                    BuildEnumerableExpression(tokens, parent);
90                }
91                else if (token.TokenType == TokenType.OpeningParenthesis)
92                {
93                    _tokenIndex++;
94                    BuildGroupExpression(tokens, parent);
95                    //if (parent is FunctionExpression)
96                    //{
97                    //    return;
98                    //}
99                }
100                else if (token.TokenType == TokenType.ClosingParenthesis || token.TokenType == TokenType.ClosingEnumerable)
101                {
102                    break;
103                }
104                else if (token.TokenType == TokenType.Negator)
105                {
106                    _negateNextExpression = true;
107                }
108                else if(token.TokenType == TokenType.Percent)
109                {
110                    SetOperatorOnExpression(parent, Operator.Percent);
111                    if (parent == null)
112                    {
113                        _graph.Add(ConstantExpressions.Percent);
114                    }
115                    else
116                    {
117                        parent.AddChild(ConstantExpressions.Percent);
118                    }
119                }
120                else
121                {
122                    CreateAndAppendExpression(ref parent, token);
123                }
124                _tokenIndex++;
125            }
126        }
127
128        private void BuildEnumerableExpression(Token[] tokens, Expression parent)
129        {
130            if (parent == null)
131            {
132                _graph.Add(new EnumerableExpression());
133                BuildUp(tokens, _graph.Current);
134            }
135            else
136            {
137                var enumerableExpression = new EnumerableExpression();
138                parent.AddChild(enumerableExpression);
139                BuildUp(tokens, enumerableExpression);
140            }
141        }
142
143        private void CreateAndAppendExpression(ref Expression parent, Token token)
144        {
145            if (IsWaste(token)) return;
146            if (parent != null &&
147                (token.TokenType == TokenType.Comma || token.TokenType == TokenType.SemiColon))
148            {
149                parent = parent.PrepareForNextChild();
150                return;
151            }
152            if (_negateNextExpression)
153            {
154                token.Negate();
155                _negateNextExpression = false;
156            }
157            var expression = _expressionFactory.Create(token);
158            if (parent == null)
159            {
160                _graph.Add(expression);
161            }
162            else
163            {
164                parent.AddChild(expression);
165            }
166        }
167
168        private bool IsWaste(Token token)
169        {
170            if (token.TokenType == TokenType.String)
171            {
172                return true;
173            }
174            return false;
175        }
176
177        private void BuildFunctionExpression(Token[] tokens, Expression parent, string funcName)
178        {
179            if (parent == null)
180            {
181                _graph.Add(new FunctionExpression(funcName, _parsingContext, _negateNextExpression));
182                _negateNextExpression = false;
183                HandleFunctionArguments(tokens, _graph.Current);
184            }
185            else
186            {
187                var func = new FunctionExpression(funcName, _parsingContext, _negateNextExpression);
188                _negateNextExpression = false;
189                parent.AddChild(func);
190                HandleFunctionArguments(tokens, func);
191            }
192        }
193
194        private void HandleFunctionArguments(Token[] tokens, Expression function)
195        {
196            _tokenIndex++;
197            var token = tokens.ElementAt(_tokenIndex);
198            if (token.TokenType != TokenType.OpeningParenthesis)
199            {
200                throw new ExcelErrorValueException(eErrorType.Value);
201            }
202            _tokenIndex++;
203            BuildUp(tokens, function.Children.First());
204        }
205
206        private void BuildGroupExpression(Token[] tokens, Expression parent)
207        {
208            if (parent == null)
209            {
210                _graph.Add(new GroupExpression());
211                BuildUp(tokens, _graph.Current);
212            }
213            else
214            {
215                if (parent.IsGroupedExpression || parent is FunctionArgumentExpression)
216                {
217                    var newGroupExpression = new GroupExpression();
218                    parent.AddChild(newGroupExpression);
219                    BuildUp(tokens, newGroupExpression);
220                }
221                 BuildUp(tokens, parent);
222            }
223        }
224
225        private void SetOperatorOnExpression(Expression parent, IOperator op)
226        {
227            if (parent == null)
228            {
229                _graph.Current.Operator = op;
230            }
231            else
232            {
233                Expression candidate;
234                if (parent is FunctionArgumentExpression)
235                {
236                    candidate = parent.Children.Last();
237                }
238                else
239                {
240                    candidate = parent.Children.Last();
241                    if (candidate is FunctionArgumentExpression)
242                    {
243                        candidate = candidate.Children.Last();
244                    }
245                }
246                candidate.Operator = op;
247            }
248        }
249    }
250}
Note: See TracBrowser for help on using the repository browser.