Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2915-AbsoluteSymbol/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/FormulaParsing/FormulaParser.cs @ 15943

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

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 9.9 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.ExpressionGraph;
36using OfficeOpenXml.FormulaParsing;
37using OfficeOpenXml.FormulaParsing.Excel.Operators;
38using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
39using OfficeOpenXml.FormulaParsing.Excel;
40using OfficeOpenXml.FormulaParsing.Excel.Functions;
41using OfficeOpenXml.FormulaParsing.ExcelUtilities;
42using OfficeOpenXml.FormulaParsing.Logging;
43using OfficeOpenXml.FormulaParsing.Utilities;
44using System.Diagnostics;
45using OfficeOpenXml.FormulaParsing.Exceptions;
46
47namespace OfficeOpenXml.FormulaParsing
48{
49    public class FormulaParser : IDisposable
50    {
51        private readonly ParsingContext _parsingContext;
52        private readonly ExcelDataProvider _excelDataProvider;
53
54        public FormulaParser(ExcelDataProvider excelDataProvider)
55            : this(excelDataProvider, ParsingContext.Create())
56        {
57           
58        }
59
60        public FormulaParser(ExcelDataProvider excelDataProvider, ParsingContext parsingContext)
61        {
62            parsingContext.Parser = this;
63            parsingContext.ExcelDataProvider = excelDataProvider;
64            parsingContext.NameValueProvider = new EpplusNameValueProvider(excelDataProvider);
65            parsingContext.RangeAddressFactory = new RangeAddressFactory(excelDataProvider);
66            _parsingContext = parsingContext;
67            _excelDataProvider = excelDataProvider;
68            Configure(configuration =>
69            {
70                configuration
71                    .SetLexer(new Lexer(_parsingContext.Configuration.FunctionRepository, _parsingContext.NameValueProvider))
72                    .SetGraphBuilder(new ExpressionGraphBuilder(excelDataProvider, _parsingContext))
73                    .SetExpresionCompiler(new ExpressionCompiler())
74                    .FunctionRepository.LoadModule(new BuiltInFunctions());
75            });
76        }
77
78        public void Configure(Action<ParsingConfiguration> configMethod)
79        {
80            configMethod.Invoke(_parsingContext.Configuration);
81            _lexer = _parsingContext.Configuration.Lexer ?? _lexer;
82            _graphBuilder = _parsingContext.Configuration.GraphBuilder ?? _graphBuilder;
83            _compiler = _parsingContext.Configuration.ExpressionCompiler ?? _compiler;
84        }
85
86        private ILexer _lexer;
87        private IExpressionGraphBuilder _graphBuilder;
88        private IExpressionCompiler _compiler;
89
90        public ILexer Lexer { get { return _lexer; } }
91        public IEnumerable<string> FunctionNames { get { return _parsingContext.Configuration.FunctionRepository.FunctionNames; } }
92
93        internal virtual object Parse(string formula, RangeAddress rangeAddress)
94        {
95            using (var scope = _parsingContext.Scopes.NewScope(rangeAddress))
96            {
97                var tokens = _lexer.Tokenize(formula);
98                var graph = _graphBuilder.Build(tokens);
99                if (graph.Expressions.Count() == 0)
100                {
101                    return null;
102                }
103                return _compiler.Compile(graph.Expressions).Result;
104            }
105        }
106
107        internal virtual object Parse(IEnumerable<Token> tokens, string worksheet, string address)
108        {
109            var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
110            using (var scope = _parsingContext.Scopes.NewScope(rangeAddress))
111            {
112                var graph = _graphBuilder.Build(tokens);
113                if (graph.Expressions.Count() == 0)
114                {
115                    return null;
116                }
117                return _compiler.Compile(graph.Expressions).Result;
118            }
119        }
120        internal virtual object ParseCell(IEnumerable<Token> tokens, string worksheet, int row, int column)
121        {
122            var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row);
123            using (var scope = _parsingContext.Scopes.NewScope(rangeAddress))
124            {
125                //    _parsingContext.Dependencies.AddFormulaScope(scope);
126                var graph = _graphBuilder.Build(tokens);
127                if (graph.Expressions.Count() == 0)
128                {
129                    return 0d;
130                }
131                try
132                {
133                    var compileResult = _compiler.Compile(graph.Expressions);
134                    // quick solution for the fact that an excelrange can be returned.
135                    var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo;
136                    if (rangeInfo == null)
137                    {
138                        return compileResult.Result ?? 0d;
139                    }
140                    else
141                    {
142                        if (rangeInfo.IsEmpty)
143                        {
144                            return 0d;
145                        }
146                        if (!rangeInfo.IsMulti)
147                        {
148                            return rangeInfo.First().Value ?? 0d;
149                        }
150                        // ok to return multicell if it is a workbook scoped name.
151                        if (string.IsNullOrEmpty(worksheet))
152                        {
153                            return rangeInfo;
154                        }
155                        if (_parsingContext.Debug)
156                        {
157                            var msg = string.Format("A range with multiple cell was returned at row {0}, column {1}",
158                                row, column);
159                            _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
160                        }
161                        return ExcelErrorValue.Create(eErrorType.Value);
162                    }
163                }
164                catch(ExcelErrorValueException ex)
165                {
166                    if (_parsingContext.Debug)
167                    {
168                        _parsingContext.Configuration.Logger.Log(_parsingContext, ex);
169                    }
170                    return ex.ErrorValue;
171                }
172            }
173        }
174
175        public virtual object Parse(string formula, string address)
176        {
177            return Parse(formula, _parsingContext.RangeAddressFactory.Create(address));
178        }
179       
180        public virtual object Parse(string formula)
181        {
182            return Parse(formula, RangeAddress.Empty);
183        }
184
185        public virtual object ParseAt(string address)
186        {
187            Require.That(address).Named("address").IsNotNullOrEmpty();
188            var rangeAddress = _parsingContext.RangeAddressFactory.Create(address);
189            return ParseAt(rangeAddress.Worksheet, rangeAddress.FromRow, rangeAddress.FromCol);
190        }
191
192        public virtual object ParseAt(string worksheetName, int row, int col)
193        {
194            var f = _excelDataProvider.GetRangeFormula(worksheetName, row, col);
195            if (string.IsNullOrEmpty(f))
196            {
197                return _excelDataProvider.GetRangeValue(worksheetName, row, col);
198            }
199            else
200            {
201                return Parse(f, _parsingContext.RangeAddressFactory.Create(worksheetName,col,row));
202            }
203            //var dataItem = _excelDataProvider.GetRangeValues(address).FirstOrDefault();
204            //if (dataItem == null /*|| (dataItem.Value == null && dataItem.Formula == null)*/) return null;
205            //if (!string.IsNullOrEmpty(dataItem.Formula))
206            //{
207            //    return Parse(dataItem.Formula, _parsingContext.RangeAddressFactory.Create(address));
208            //}
209            //return Parse(dataItem.Value.ToString(), _parsingContext.RangeAddressFactory.Create(address));
210        }
211
212
213        internal void InitNewCalc()
214        {
215            if(_excelDataProvider!=null)
216            {
217                _excelDataProvider.Reset();
218            }
219        }
220
221        public IFormulaParserLogger Logger
222        {
223            get { return _parsingContext.Configuration.Logger; }
224        }
225
226        public void Dispose()
227        {
228            if (_parsingContext.Debug)
229            {
230                _parsingContext.Configuration.Logger.Dispose();
231            }
232        }
233    }
234}
Note: See TracBrowser for help on using the repository browser.