ExpressionParser.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using System;
  2. using System.Collections.Generic;
  3. using FastReport.Code;
  4. using FastReport.Utils;
  5. using FastReport.Table;
  6. namespace FastReport.AdvMatrix
  7. {
  8. internal class ExpressionParser
  9. {
  10. private AdvMatrixObject matrix;
  11. internal static readonly string[] SpecialFunctionNames = {
  12. "ColumnTotal", "RowTotal", "GrandTotal", "GrandColumnTotal", "GrandRowTotal",
  13. "SpecificColumn", "SpecificRow", "FirstColumn", "FirstRow", "LastColumn", "LastRow", "PreviousColumn", "PreviousRow", "NextColumn", "NextRow",
  14. "ColumnMaxValue", "ColumnMinValue", "RowMaxValue", "RowMinValue",
  15. "PercentOfColumnTotal", "PercentOfRowTotal", "PercentOfGrandTotal", "PercentOfPreviousColumn", "PercentOfPreviousRow" };
  16. private bool IsAggregate(string ident)
  17. {
  18. return Aggregates.Find(ident) != null || ident.StartsWith("_");
  19. }
  20. private bool IsSpecialFunction(string ident)
  21. {
  22. foreach (string s in SpecialFunctionNames)
  23. {
  24. if (s == ident)
  25. return true;
  26. }
  27. return false;
  28. }
  29. private string ToSpecialFunctionCall(string name)
  30. {
  31. return matrix.Name + ".Data.Context.Get" + name;
  32. }
  33. // parse expression:
  34. // - search for aggregates and collect them in the aggregates list
  35. // - replace aggregate calls: AggrName(expression) -> MatrixName.Data.Context.GetAggregate("AggrName", "expression")
  36. // - search for special functions like "PreviousColumn(...)" and collect them in the specialFunctions list
  37. // - replace special function calls: PreviousColumn() -> MatrixName.Data.Context.GetPreviousColumn()
  38. private string Parse(string expression, AggregateExpressionPairList aggregates, List<string> specialFunctions)
  39. {
  40. FindTextArgs args = new FindTextArgs();
  41. args.Text = new FastString(expression);
  42. args.OpenBracket = "(";
  43. args.CloseBracket = ")";
  44. // search for method calls
  45. while (args.StartIndex < args.Text.Length)
  46. {
  47. if (CodeUtils.GetExpression(args, false) == null)
  48. break;
  49. // get identifier at the left of (
  50. int i = args.StartIndex;
  51. while (i > 0)
  52. {
  53. char c = args.Text[i - 1];
  54. if (!(char.IsLetterOrDigit(c) || c == '_'))
  55. break;
  56. i--;
  57. }
  58. string ident = args.Text.Substring(i, args.StartIndex - i);
  59. // if ident has preceding . symbol, ignore it
  60. if (i > 0 && args.Text[i - 1] == '.')
  61. ident = "";
  62. if (IsAggregate(ident))
  63. {
  64. // ident is either one of predefined aggregates or a user aggregate
  65. string newText = aggregates.AddUnique(ident, args.FoundText).ToAggregateCall();
  66. args.Text.Remove(i, args.EndIndex - i);
  67. args.Text.Insert(i, newText);
  68. args.StartIndex = i + newText.Length;
  69. }
  70. else if (IsSpecialFunction(ident))
  71. {
  72. // ident is a special function like PreviousColumn(...)
  73. if (specialFunctions != null)
  74. specialFunctions.Add(ident);
  75. string newText = ToSpecialFunctionCall(ident);
  76. args.Text.Remove(i, ident.Length);
  77. args.Text.Insert(i, newText);
  78. args.StartIndex = i + newText.Length;
  79. }
  80. else
  81. {
  82. string newText = "(" + Parse(args.FoundText, aggregates, specialFunctions) + ")";
  83. args.Text.Remove(args.StartIndex, args.EndIndex - args.StartIndex);
  84. args.Text.Insert(args.StartIndex, newText);
  85. args.StartIndex += newText.Length;
  86. }
  87. }
  88. return args.Text.ToString();
  89. }
  90. // parse expression with single aggregate
  91. public AggregateExpressionPair Parse(string expression)
  92. {
  93. AggregateExpressionPairList list = new AggregateExpressionPairList(matrix);
  94. Parse(expression, list, null);
  95. if (list.Count == 1)
  96. return list[0];
  97. return null;
  98. }
  99. public CellDescriptor ProcessCell(TableCell cell)
  100. {
  101. // create cell descriptor and attach it to a cell
  102. CellDescriptor cellDescriptor = new CellDescriptor(matrix, cell);
  103. string text = cell.Text;
  104. string[] brackets = cell.Brackets.Split(',');
  105. if (String.IsNullOrEmpty(text) || brackets.Length != 2)
  106. return cellDescriptor;
  107. // process all expressions in the cell's text
  108. FindTextArgs args = new FindTextArgs();
  109. args.Text = new FastString(text);
  110. args.OpenBracket = brackets[0];
  111. args.CloseBracket = brackets[1];
  112. while (args.StartIndex < args.Text.Length)
  113. {
  114. string expression = CodeUtils.GetExpression(args, false);
  115. if (expression == null)
  116. break;
  117. expression = Parse(expression, cellDescriptor.Aggregates, cellDescriptor.SpecialFunctions);
  118. cellDescriptor.Expressions.Add(expression);
  119. expression = brackets[0] + expression + brackets[1];
  120. args.Text.Remove(args.StartIndex, args.EndIndex - args.StartIndex);
  121. args.Text.Insert(args.StartIndex, expression);
  122. args.StartIndex += expression.Length;
  123. }
  124. // set the new text to the cell descriptor
  125. cellDescriptor.Text = args.Text.ToString();
  126. cellDescriptor.UpdateContentType();
  127. return cellDescriptor;
  128. }
  129. public ExpressionParser(AdvMatrixObject matrix)
  130. {
  131. this.matrix = matrix;
  132. }
  133. }
  134. }