blob: 908459166bc2d262df80df8cfabb7e5b8c5b5333 [file] [log] [blame]
/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
* Copyright (C) 2011 Jan Källman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*
* Code change notes:
*
* Author Change Date
* ******************************************************************************
* Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser)
* Jan Källman Replaced Adress validate 2013-03-01
* *******************************************************************************/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
namespace EpplusFormulaParser;
internal static partial class TokenFactory {
public static Token Create(List<Token> tokens, string token) {
if (TokenSeparatorProvider.Tokens.TryGetValue(token, out var tokenSeparator)) {
return tokenSeparator;
}
var tokenList = (IList<Token>)tokens;
//Address with worksheet-string before /JK
if (token.StartsWith('!') && tokenList[^1].TokenType == TokenType.String) {
var i = tokenList.Count - 2;
if (i > 0) {
string addr;
if (tokenList[i].TokenType == TokenType.StringContent) {
addr = "'" + tokenList[i].Value.Replace("'", "''") + "'";
} else {
throw new ArgumentException($"Invalid formula token sequence near {token}");
}
//Remove the string tokens and content
tokenList.RemoveAt(tokenList.Count - 1);
tokenList.RemoveAt(tokenList.Count - 1);
tokenList.RemoveAt(tokenList.Count - 1);
return new(addr + token, TokenType.ExcelAddress);
}
throw new ArgumentException($"Invalid formula token sequence near {token}");
}
if (tokens.Count != 0 && tokens.Last().TokenType == TokenType.String) {
return new(token, TokenType.StringContent);
}
if (!string.IsNullOrEmpty(token)) {
token = token.Trim();
}
if (DecimalRegex().IsMatch(token)) {
return new(token, TokenType.Decimal);
}
if (IntegerRegex().IsMatch(token)) {
return new(token, TokenType.Integer);
}
if (BooleanRegex().IsMatch(token)) {
return new(token, TokenType.Boolean);
}
if (token.Contains("#REF!", StringComparison.InvariantCultureIgnoreCase)) {
return new(token, TokenType.InvalidReference);
}
if (token.Equals("#NUM!", StringComparison.InvariantCultureIgnoreCase)) {
return new(token, TokenType.NumericError);
}
if (token.Equals("#VALUE!", StringComparison.InvariantCultureIgnoreCase)) {
return new(token, TokenType.ValueDataTypeError);
}
if (token.Equals("#NULL!", StringComparison.InvariantCultureIgnoreCase)) {
return new(token, TokenType.Null);
}
if (FunctionRepository.IsFunctionName(token)) {
return new(token, TokenType.Function);
}
if (tokenList.Count > 0 && tokenList[^1].TokenType == TokenType.OpeningEnumerable) {
return new(token, TokenType.Enumerable);
}
var at = ExcelAddressUtilities.IsValid(token);
if (at == ExcelAddressUtilities.AddressType.InternalAddress) {
return new(token.ToUpper(CultureInfo.InvariantCulture), TokenType.ExcelAddress);
}
return new(token, TokenType.Unrecognized);
}
[GeneratedRegex(@"^[0-9]+\.[0-9]+$")]
private static partial Regex DecimalRegex();
[GeneratedRegex("^[0-9]+$")]
private static partial Regex IntegerRegex();
[GeneratedRegex("^(true|false)$", RegexOptions.IgnoreCase)]
private static partial Regex BooleanRegex();
}