CPF/CPF.ReoGrid/Formula/FormulaRefactor.cs
2024-06-24 10:15:59 +08:00

278 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
namespace CPF.ReoGrid.Formula
{
internal class FormulaRefactor
{
internal static string Generate(string input, STNode node)
{
return FormulaRefactor.Generate(input, node, FormulaFormatFlag.Default);
}
internal static string Generate(string input, STNode node, FormulaFormatFlag flag)
{
StringBuilder stringBuilder = new StringBuilder();
FormulaRefactor.GenerateExpression(stringBuilder, input, node, flag);
bool flag2 = stringBuilder[stringBuilder.Length - 1] == ' ';
if (flag2)
{
stringBuilder.Remove(stringBuilder.Length - 1, 1);
}
return stringBuilder.ToString();
}
private static void GenerateExpression(StringBuilder sb, string input, STNode node, FormulaFormatFlag flag)
{
switch (node.Type)
{
case STNodeType.CONNECT:
FormulaRefactor.GenerateOperatorString(sb, input, "&", node, flag);
break;
default:
sb.Append(node.ToString());
break;
case STNodeType.NUMBER:
sb.Append(((STNumberNode)node).Value);
break;
case STNodeType.STRING:
sb.Append(((STStringNode)node).Text);
break;
case STNodeType.IDENTIFIER:
sb.Append(((STIdentifierNode)node).Identifier);
break;
case STNodeType.RANGE:
sb.Append(((STRangeNode)node).Range.ToAddress());
break;
case STNodeType.CELL:
sb.Append(((STCellNode)node).Position.ToAddress());
break;
case STNodeType.FUNCTION_CALL:
{
STFunctionNode stfunctionNode = (STFunctionNode)node;
string name = stfunctionNode.Name;
bool flag2 = (flag & FormulaFormatFlag.FunctionNameAutoUppercase) == FormulaFormatFlag.FunctionNameAutoUppercase;
if (flag2)
{
sb.Append(name.ToUpper());
}
else
{
sb.Append(name);
}
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceAfterFunctionName);
sb.Append('(');
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceBeforeParameterList);
for (int i = 0; i < node.Children.Count; i++)
{
bool flag3 = i > 0;
if (flag3)
{
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceBeforeComma);
sb.Append(',');
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceAfterComma);
}
FormulaRefactor.GenerateExpression(sb, input, node.Children[i], flag);
}
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceAfterParameterList);
sb.Append(')');
break;
}
case STNodeType.ADD:
FormulaRefactor.GenerateOperatorString(sb, input, "+", node, flag);
break;
case STNodeType.SUB:
FormulaRefactor.GenerateOperatorString(sb, input, "-", node, flag);
break;
case STNodeType.MUL:
FormulaRefactor.GenerateOperatorString(sb, input, "*", node, flag);
break;
case STNodeType.DIV:
FormulaRefactor.GenerateOperatorString(sb, input, "/", node, flag);
break;
case STNodeType.POW:
FormulaRefactor.GenerateOperatorString(sb, input, "^", node, flag);
break;
case STNodeType.EQUALS:
FormulaRefactor.GenerateOperatorString(sb, input, "=", node, flag);
break;
case STNodeType.GREAT_THAN:
FormulaRefactor.GenerateOperatorString(sb, input, ">", node, flag);
break;
case STNodeType.LESS_THAN:
FormulaRefactor.GenerateOperatorString(sb, input, "<", node, flag);
break;
case STNodeType.GREAT_EQUALS:
FormulaRefactor.GenerateOperatorString(sb, input, ">=", node, flag);
break;
case STNodeType.LESS_EQUALS:
FormulaRefactor.GenerateOperatorString(sb, input, "<=", node, flag);
break;
case STNodeType.UNARY_MINUS:
sb.Append('-');
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceAfterMinus);
FormulaRefactor.GenerateExpression(sb, input, node.Children[0], flag);
break;
case STNodeType.UNARY_PERCENT:
FormulaRefactor.GenerateExpression(sb, input, node.Children[0], flag);
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceBeforePercent);
sb.Append('%');
break;
case STNodeType.SUB_EXPR:
sb.Append('(');
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceBeforeSubExpression);
FormulaRefactor.GenerateExpression(sb, input, node.Children[0], flag);
FormulaRefactor.AddSpaceIfFlag(sb, flag, FormulaFormatFlag.SpaceAfterSubExpression);
sb.Append(')');
break;
}
}
private static void AddSpaceIfFlag(StringBuilder sb, FormulaFormatFlag flag, FormulaFormatFlag target)
{
bool flag2 = (flag & target) == target && (sb.Length == 0 || sb[sb.Length - 1] != ' ');
if (flag2)
{
sb.Append(' ');
}
}
private static void GenerateOperatorString(StringBuilder sb, string input, string op, STNode node, FormulaFormatFlag flag)
{
STNode node2 = node.Children[0];
STNode node3 = node.Children[1];
FormulaRefactor.GenerateExpression(sb, input, node2, flag);
bool flag2 = (flag & FormulaFormatFlag.SpaceBeforeOperator) == FormulaFormatFlag.SpaceBeforeOperator;
if (flag2)
{
sb.Append(' ');
}
sb.Append(op);
bool flag3 = (flag & FormulaFormatFlag.SpaceAfterOperator) == FormulaFormatFlag.SpaceAfterOperator;
if (flag3)
{
sb.Append(' ');
}
FormulaRefactor.GenerateExpression(sb, input, node3, flag);
}
internal static void Reuse(Worksheet sheet, CellPosition fromPosition, RangePosition toRange)
{
fromPosition = sheet.FixPos(fromPosition);
toRange = sheet.FixRange(toRange);
Cell cell = sheet.cells[fromPosition.Row, fromPosition.Col];
bool flag = cell == null || string.IsNullOrEmpty(cell.InnerFormula) || cell.FormulaTree == null;
if (flag)
{
throw new InvalidOperationException("cannot found formula from specified position, try reset formula for the cell again");
}
bool flag2 = cell.formulaStatus > FormulaStatus.Normal;
if (flag2)
{
throw new InvalidOperationException("formula in specified cell contains errors, correct the formula firstly");
}
bool flag3 = toRange.Contains(fromPosition);
if (flag3)
{
throw new ArgumentException("toRange should not contain the position of the formula to be reused");
}
ReplacableString rs = new ReplacableString(cell.InnerFormula);
STNode formulaTree = cell.FormulaTree;
Stack<List<Cell>> dirtyCells = new Stack<List<Cell>>();
for (int i = toRange.Row; i <= toRange.EndRow; i++)
{
int j = toRange.Col;
while (j <= toRange.EndCol)
{
Cell cell2 = sheet.CreateAndGetCell(i, j);
bool flag4 = cell2.Colspan <= 0;
if (flag4)
{
j++;
}
else
{
FormulaRefactor.CopyFormula(fromPosition, formulaTree, cell2, rs, dirtyCells);
j += (int)cell.Colspan;
}
}
}
}
internal static void CopyFormula(CellPosition fromPosition, STNode fromNode, Cell toCell, ReplacableString rs, Stack<List<Cell>> dirtyCells)
{
Worksheet sheet = toCell.Worksheet;
STNode node = (STNode)fromNode.Clone();
int r = toCell.Row;
int c = toCell.Column;
rs.Restore();
STNode.RecursivelyIterate(node, delegate(STNode n)
{
STNodeType type = n.Type;
STNodeType stnodeType = type;
if (stnodeType != STNodeType.RANGE)
{
if (stnodeType == STNodeType.CELL)
{
STCellNode stcellNode = (STCellNode)n;
CellPosition position = stcellNode.Position;
bool flag2 = position.RowProperty == PositionProperty.Relative;
if (flag2)
{
position.Row += r - fromPosition.Row;
}
bool flag3 = position.ColumnProperty == PositionProperty.Relative;
if (flag3)
{
position.Col += c - fromPosition.Col;
}
bool flag4 = position.Row < 0 || position.Col < 0 || position.Row >= sheet.rows.Count || position.Col >= sheet.cols.Count;
if (flag4)
{
toCell.formulaStatus = FormulaStatus.InvalidReference;
}
stcellNode.Position = position;
n.Start += rs.Offset;
int num = rs.Replace(n.Start, n.Length, position.ToAddress());
n.Length += num;
}
}
else
{
STRangeNode strangeNode = (STRangeNode)n;
RangePosition range = strangeNode.Range;
int num2 = r - fromPosition.Row;
int num3 = c - fromPosition.Col;
bool flag5 = range.StartRowProperty == PositionProperty.Relative;
if (flag5)
{
range.Row += num2;
}
bool flag6 = range.StartColumnProperty == PositionProperty.Relative;
if (flag6)
{
range.Col += num3;
}
bool flag7 = range.Row < 0 || range.Col < 0 || range.Row >= sheet.rows.Count || range.Col >= sheet.cols.Count || range.EndRow < 0 || range.EndCol < 0 || range.EndRow >= sheet.rows.Count || range.EndCol >= sheet.cols.Count;
if (flag7)
{
toCell.formulaStatus = FormulaStatus.InvalidReference;
}
strangeNode.Range = range;
n.Start += rs.Offset;
int num4 = rs.Replace(n.Start, n.Length, range.ToAddress());
n.Length += num4;
}
});
toCell.InnerFormula = rs.ToString();
sheet.SetCellFormula(toCell, node);
bool flag = toCell.formulaStatus == FormulaStatus.Normal;
if (flag)
{
sheet.RecalcCell(toCell, dirtyCells);
}
}
}
}