Establishes the foundational structure, core Excel functionality, and tooling. - Implements base components for cells, ranges, columns, and rows. - Integrates a custom calculation engine with a wide range of Excel functions. - Adds comprehensive support for styling, conditional formatting, data validation, comments, pictures, and charts. - Configures build setup, project metadata (NuGet), and developer guidelines. - Includes editor and Git attributes for consistent code style and line endings.
217 lines
6.4 KiB
C#
217 lines
6.4 KiB
C#
using ClosedXML.Excel.CalcEngine.Exceptions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
|
|
namespace ClosedXML.Excel.CalcEngine.Functions
|
|
{
|
|
internal static class Information
|
|
{
|
|
public static void Register(CalcEngine ce)
|
|
{
|
|
//TODO: Add documentation
|
|
ce.RegisterFunction("ERRORTYPE", 1, ErrorType);
|
|
ce.RegisterFunction("ISBLANK", 1, int.MaxValue, IsBlank);
|
|
ce.RegisterFunction("ISERR", 1, int.MaxValue, IsErr);
|
|
ce.RegisterFunction("ISERROR", 1, int.MaxValue, IsError);
|
|
ce.RegisterFunction("ISEVEN", 1, IsEven);
|
|
ce.RegisterFunction("ISLOGICAL", 1, int.MaxValue, IsLogical);
|
|
ce.RegisterFunction("ISNA", 1, int.MaxValue, IsNa);
|
|
ce.RegisterFunction("ISNONTEXT", 1, int.MaxValue, IsNonText);
|
|
ce.RegisterFunction("ISNUMBER", 1, int.MaxValue, IsNumber);
|
|
ce.RegisterFunction("ISODD", 1, IsOdd);
|
|
ce.RegisterFunction("ISREF", 1, int.MaxValue, IsRef);
|
|
ce.RegisterFunction("ISTEXT", 1, int.MaxValue, IsText);
|
|
ce.RegisterFunction("N", 1, N);
|
|
ce.RegisterFunction("NA", 0, NA);
|
|
ce.RegisterFunction("TYPE", 1, Type);
|
|
}
|
|
|
|
static IDictionary<ErrorExpression.ExpressionErrorType, int> errorTypes = new Dictionary<ErrorExpression.ExpressionErrorType, int>()
|
|
{
|
|
[ErrorExpression.ExpressionErrorType.NullValue] = 1,
|
|
[ErrorExpression.ExpressionErrorType.DivisionByZero] = 2,
|
|
[ErrorExpression.ExpressionErrorType.CellValue] = 3,
|
|
[ErrorExpression.ExpressionErrorType.CellReference] = 4,
|
|
[ErrorExpression.ExpressionErrorType.NameNotRecognized] = 5,
|
|
[ErrorExpression.ExpressionErrorType.NumberInvalid] = 6,
|
|
[ErrorExpression.ExpressionErrorType.NoValueAvailable] = 7
|
|
};
|
|
|
|
static object ErrorType(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
|
|
if (v is ErrorExpression.ExpressionErrorType)
|
|
return errorTypes[(ErrorExpression.ExpressionErrorType)v];
|
|
else
|
|
throw new NoValueAvailableException();
|
|
}
|
|
|
|
static object IsBlank(List<Expression> p)
|
|
{
|
|
var v = (string) p[0];
|
|
var isBlank = string.IsNullOrEmpty(v);
|
|
|
|
|
|
if (isBlank && p.Count > 1) {
|
|
var sublist = p.GetRange(1, p.Count);
|
|
isBlank = (bool)IsBlank(sublist);
|
|
}
|
|
|
|
return isBlank;
|
|
}
|
|
|
|
static object IsErr(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
|
|
return v is ErrorExpression.ExpressionErrorType
|
|
&& ((ErrorExpression.ExpressionErrorType)v) != ErrorExpression.ExpressionErrorType.NoValueAvailable;
|
|
}
|
|
|
|
static object IsError(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
|
|
return v is ErrorExpression.ExpressionErrorType;
|
|
}
|
|
|
|
static object IsEven(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
if (v is double)
|
|
{
|
|
return Math.Abs((double) v%2) < 1;
|
|
}
|
|
//TODO: Error Exceptions
|
|
throw new ArgumentException("Expression doesn't evaluate to double");
|
|
}
|
|
|
|
static object IsLogical(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
var isLogical = v is bool;
|
|
|
|
if (isLogical && p.Count > 1)
|
|
{
|
|
var sublist = p.GetRange(1, p.Count);
|
|
isLogical = (bool) IsLogical(sublist);
|
|
}
|
|
|
|
return isLogical;
|
|
}
|
|
|
|
static object IsNa(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
|
|
return v is ErrorExpression.ExpressionErrorType
|
|
&& ((ErrorExpression.ExpressionErrorType)v) == ErrorExpression.ExpressionErrorType.NoValueAvailable;
|
|
}
|
|
|
|
static object IsNonText(List<Expression> p)
|
|
{
|
|
return !(bool) IsText(p);
|
|
}
|
|
|
|
static object IsNumber(List<Expression> p)
|
|
{
|
|
var v = p[0].Evaluate();
|
|
|
|
var isNumber = v is double; //Normal number formatting
|
|
if (!isNumber)
|
|
{
|
|
isNumber = v is DateTime; //Handle DateTime Format
|
|
}
|
|
if (!isNumber)
|
|
{
|
|
//Handle Number Styles
|
|
try
|
|
{
|
|
var stringValue = (string) v;
|
|
return double.TryParse(stringValue.TrimEnd('%', ' '), NumberStyles.Any, null, out double dv);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
isNumber = false;
|
|
}
|
|
}
|
|
|
|
if (isNumber && p.Count > 1)
|
|
{
|
|
var sublist = p.GetRange(1, p.Count);
|
|
isNumber = (bool)IsNumber(sublist);
|
|
}
|
|
|
|
return isNumber;
|
|
}
|
|
|
|
static object IsOdd(List<Expression> p)
|
|
{
|
|
return !(bool) IsEven(p);
|
|
}
|
|
|
|
static object IsRef(List<Expression> p)
|
|
{
|
|
var oe = p[0] as XObjectExpression;
|
|
if (oe == null)
|
|
return false;
|
|
|
|
var crr = oe.Value as CellRangeReference;
|
|
|
|
return crr != null;
|
|
}
|
|
|
|
static object IsText(List<Expression> p)
|
|
{
|
|
//Evaluate Expressions
|
|
var isText = !(bool) IsBlank(p);
|
|
if (isText)
|
|
{
|
|
isText = !(bool) IsNumber(p);
|
|
}
|
|
if (isText)
|
|
{
|
|
isText = !(bool) IsLogical(p);
|
|
}
|
|
return isText;
|
|
}
|
|
|
|
static object N(List<Expression> p)
|
|
{
|
|
return (double) p[0];
|
|
}
|
|
|
|
static object NA(List<Expression> p)
|
|
{
|
|
return ErrorExpression.ExpressionErrorType.NoValueAvailable;
|
|
}
|
|
|
|
static object Type(List<Expression> p)
|
|
{
|
|
if ((bool) IsNumber(p))
|
|
{
|
|
return 1;
|
|
}
|
|
if ((bool) IsText(p))
|
|
{
|
|
return 2;
|
|
}
|
|
if ((bool) IsLogical(p))
|
|
{
|
|
return 4;
|
|
}
|
|
if ((bool) IsError(p))
|
|
{
|
|
return 16;
|
|
}
|
|
if(p.Count > 1)
|
|
{
|
|
return 64;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|