672 lines
24 KiB
C#
672 lines
24 KiB
C#
using System.Text;
|
|
using Strata.SqlTools.SqlBreakdown.Classes;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Arithmetic;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Comparisons;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Conditional.Logical;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Functions;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Aggregate;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Functions.Conditional;
|
|
using Strata.SqlTools.SqlBreakdown.Expressions.Literals;
|
|
using Strata.SqlTools.SqlBreakdown.Interfaces.Core;
|
|
|
|
namespace Strata.SqlTools.Markdown.Expressions;
|
|
|
|
/// <summary>
|
|
/// Generates markdown documentation for Expression trees.
|
|
/// Creates human-readable documentation with expression structure, type information, and visual representations.
|
|
/// </summary>
|
|
public class ExpressionGenerator : IVisitor<string>
|
|
{
|
|
private int _indentLevel = 0;
|
|
private readonly string _indentString = " ";
|
|
|
|
/// <summary>
|
|
/// Generates markdown documentation from an Expression tree.
|
|
/// </summary>
|
|
/// <param name="expression">The expression to document.</param>
|
|
/// <param name="title">Optional title for the documentation.</param>
|
|
/// <returns>A markdown formatted string documenting the expression.</returns>
|
|
public string GenerateMarkdown(Expression expression, string? title = null)
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
if (!string.IsNullOrWhiteSpace(title))
|
|
{
|
|
sb.AppendLine($"# {title}");
|
|
sb.AppendLine();
|
|
}
|
|
|
|
sb.AppendLine("## Expression Structure");
|
|
sb.AppendLine();
|
|
sb.AppendLine("```");
|
|
_indentLevel = 0;
|
|
sb.AppendLine(expression.Accept(this));
|
|
sb.AppendLine("```");
|
|
sb.AppendLine();
|
|
|
|
sb.AppendLine("## Expression Type");
|
|
sb.AppendLine();
|
|
sb.AppendLine($"**Type:** `{expression.GetType().Name}`");
|
|
sb.AppendLine();
|
|
|
|
sb.AppendLine("## Mermaid Diagram");
|
|
sb.AppendLine();
|
|
sb.AppendLine(GenerateMermaidDiagram(expression));
|
|
|
|
sb.AppendLine();
|
|
sb.AppendLine("## Mathematical Expression");
|
|
sb.AppendLine();
|
|
sb.AppendLine(GenerateMathematicalExpression(expression));
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates a mathematical expression using LaTeX notation for GitHub markdown.
|
|
/// </summary>
|
|
/// <param name="expression">The expression to convert to mathematical notation.</param>
|
|
/// <param name="inline">If true, generates inline math ($...$), otherwise block math ($$...$$).</param>
|
|
/// <returns>A string containing the LaTeX mathematical expression.</returns>
|
|
public static string GenerateMathematicalExpression(Expression expression, bool inline = false)
|
|
{
|
|
var latex = ConvertToLatex(expression);
|
|
return inline ? $"${latex}$" : $"$$\n{latex}\n$$";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates a mathematical expression from raw LaTeX in markdown format.
|
|
/// </summary>
|
|
/// <param name="latex">The LaTeX expression.</param>
|
|
/// <param name="format">The format to use: "dollar" for $/$$ delimiters, "math" for ```math code fence.</param>
|
|
/// <param name="inline">If true and format is "dollar", generates inline math ($...$), otherwise block math ($$...$$). Ignored for "math" format.</param>
|
|
/// <returns>A string containing the formatted mathematical expression.</returns>
|
|
public static string GenerateRawMathematicalExpression(string latex, string format = "dollar", bool inline = false)
|
|
{
|
|
return format.ToLower() switch
|
|
{
|
|
"math" => $"```math\n{latex}\n```",
|
|
_ => inline ? $"${latex}$" : $"$$\n{latex}\n$$"
|
|
};
|
|
}
|
|
|
|
private static string ConvertToLatex(Expression expression)
|
|
{
|
|
return expression switch
|
|
{
|
|
// Arithmetic expressions
|
|
ArithmeticExpression arith => ConvertArithmeticToLatex(arith),
|
|
|
|
// Comparison expressions
|
|
ComparisonOperatorExpression comp => ConvertComparisonToLatex(comp),
|
|
|
|
// Logical expressions
|
|
AndExpression and => $"({ConvertToLatex(and.ExpressionA)} \\land {ConvertToLatex(and.ExpressionB)})",
|
|
OrExpression or => $"({ConvertToLatex(or.ExpressionA)} \\lor {ConvertToLatex(or.ExpressionB)})",
|
|
NotExpression not => $"\\neg({ConvertToLatex(not.ExpressionA)})",
|
|
|
|
// Literals
|
|
NumberLiteralExpression num => num.Value.ToString() ?? "0",
|
|
StringLiteralExpression str => $"\\text{{\"{EscapeLatex(str.Value)}\"}}",
|
|
BooleanLiteralExpression b => b.Value ? "\\text{true}" : "\\text{false}",
|
|
NullLiteralExpression => "\\text{NULL}",
|
|
|
|
// Column expressions
|
|
ColumnExpression col => $"\\text{{{EscapeLatex(col.ColumnName)}}}",
|
|
|
|
// Parameter expressions
|
|
ParameterExpression param => $"@{EscapeLatex(param.ParameterName)}",
|
|
|
|
// Case expressions (before FunctionExpression since it's a subclass)
|
|
CaseExpression caseExpr => ConvertCaseToLatex(caseExpr),
|
|
|
|
// Functions
|
|
FunctionExpression func => ConvertFunctionToLatex(func),
|
|
|
|
// Between expressions
|
|
BetweenExpression between => $"{ConvertToLatex(between.Expression)} \\in [{ConvertToLatex(between.LowerBound)}, {ConvertToLatex(between.UpperBound)}]",
|
|
|
|
// IN expressions
|
|
InExpression inExpr => $"{ConvertToLatex(inExpr.SearchExpression)} \\in \\{{{string.Join(", ", inExpr.ValuesToCompare.Select(ConvertToLatex))}\\}}",
|
|
|
|
// LIKE expressions
|
|
LikeExpression like => $"{ConvertToLatex(like.Subject)} \\approx \\text{{\"{EscapeLatex(ConvertExpressionToString(like.Pattern))}\"}}",
|
|
_ => $"\\text{{{EscapeLatex(expression.GetType().Name)}}}"
|
|
};
|
|
}
|
|
|
|
private static string ConvertArithmeticToLatex(ArithmeticExpression arith)
|
|
{
|
|
var left = ConvertToLatex(arith.ExpressionA);
|
|
var right = ConvertToLatex(arith.ExpressionB);
|
|
|
|
var op = arith.ArithmeticOperator switch
|
|
{
|
|
"+" => "+",
|
|
"-" => "-",
|
|
"*" => "\\times",
|
|
"/" => "\\div",
|
|
"%" => "\\bmod",
|
|
_ => "?"
|
|
};
|
|
|
|
return $"({left} {op} {right})";
|
|
}
|
|
|
|
private static string ConvertComparisonToLatex(ComparisonOperatorExpression comp)
|
|
{
|
|
var left = ConvertToLatex(comp.ExpressionA);
|
|
var right = ConvertToLatex(comp.ExpressionB);
|
|
|
|
var op = comp.Operator switch
|
|
{
|
|
"=" => "=",
|
|
"<>" => "\\neq",
|
|
"!=" => "\\neq",
|
|
">" => ">",
|
|
">=" => "\\geq",
|
|
"<" => "<",
|
|
"<=" => "\\leq",
|
|
_ => "?"
|
|
};
|
|
|
|
return $"({left} {op} {right})";
|
|
}
|
|
|
|
private static string ConvertFunctionToLatex(FunctionExpression func)
|
|
{
|
|
var args = string.Join(", ", func.Arguments.Select(ConvertToLatex));
|
|
var funcName = EscapeLatex(func.FunctionName);
|
|
|
|
return func.FunctionName.ToUpper() switch
|
|
{
|
|
// Aggregate functions
|
|
"COUNT" => $"\\text{{COUNT}}({args})",
|
|
"SUM" => $"\\sum({args})",
|
|
"AVG" => $"\\text{{AVG}}({args})",
|
|
"MIN" => $"\\min({args})",
|
|
"MAX" => $"\\max({args})",
|
|
|
|
// Math functions
|
|
"ABS" => $"|{args}|",
|
|
"SQRT" => $"\\sqrt{{{args}}}",
|
|
"POWER" when func.Arguments.Length >= 2 =>
|
|
$"{ConvertToLatex(func.Arguments[0])}^{{{ConvertToLatex(func.Arguments[1])}}}",
|
|
"LOG" => $"\\log({args})",
|
|
"EXP" => $"e^{{{args}}}",
|
|
|
|
// Default
|
|
_ => $"\\text{{{funcName}}}({args})"
|
|
};
|
|
}
|
|
|
|
private static string ConvertCaseToLatex(CaseExpression caseExpr)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.Append("\\begin{cases}\n");
|
|
|
|
foreach (var (condition, result) in caseExpr.ConditionResultPairs)
|
|
{
|
|
sb.Append($" {ConvertToLatex(result)} & \\text{{if }} {ConvertToLatex(condition)} \\\\\n");
|
|
}
|
|
|
|
if (caseExpr.ElseResultExpression is not null)
|
|
{
|
|
sb.Append($" {ConvertToLatex(caseExpr.ElseResultExpression)} & \\text{{otherwise}}\n");
|
|
}
|
|
|
|
sb.Append("\\end{cases}");
|
|
return sb.ToString();
|
|
}
|
|
|
|
private static string ConvertExpressionToString(Expression expression)
|
|
{
|
|
return expression switch
|
|
{
|
|
StringLiteralExpression str => str.Value,
|
|
_ => expression.ToString() ?? ""
|
|
};
|
|
}
|
|
|
|
private static string EscapeLatex(string text)
|
|
{
|
|
return text
|
|
.Replace("\\", "\\\\")
|
|
.Replace("{", "\\{")
|
|
.Replace("}", "\\}")
|
|
.Replace("_", "\\_")
|
|
.Replace("$", "\\$")
|
|
.Replace("%", "\\%")
|
|
.Replace("&", "\\&")
|
|
.Replace("#", "\\#");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generates a Mermaid tree diagram from an Expression tree.
|
|
/// </summary>
|
|
private string GenerateMermaidDiagram(Expression expression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine("```mermaid");
|
|
sb.AppendLine("graph TD");
|
|
sb.AppendLine();
|
|
|
|
int nodeCounter = 0;
|
|
var nodeMap = new Dictionary<object, int>();
|
|
GenerateMermaidNodes(expression, sb, nodeMap, ref nodeCounter);
|
|
|
|
sb.AppendLine("```");
|
|
return sb.ToString();
|
|
}
|
|
|
|
private int GenerateMermaidNodes(Expression expression, StringBuilder sb, Dictionary<object, int> nodeMap, ref int nodeCounter)
|
|
{
|
|
var currentNode = nodeCounter++;
|
|
nodeMap[expression] = currentNode;
|
|
|
|
var nodeLabel = GetNodeLabel(expression);
|
|
var nodeShape = GetNodeShape(expression);
|
|
|
|
sb.AppendLine($" Node{currentNode}{nodeShape[0]}\"{EscapeMarkdown(nodeLabel)}\"{nodeShape[1]}");
|
|
|
|
// Process child expressions
|
|
switch (expression)
|
|
{
|
|
case ComparisonOperatorExpression comp:
|
|
var leftId = GenerateMermaidNodes(comp.ExpressionA, sb, nodeMap, ref nodeCounter);
|
|
var rightId = GenerateMermaidNodes(comp.ExpressionB, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} --> Node{leftId}");
|
|
sb.AppendLine($" Node{currentNode} --> Node{rightId}");
|
|
break;
|
|
|
|
case AndExpression and:
|
|
var andLeftId = GenerateMermaidNodes(and.ExpressionA, sb, nodeMap, ref nodeCounter);
|
|
var andRightId = GenerateMermaidNodes(and.ExpressionB, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} -->|Left| Node{andLeftId}");
|
|
sb.AppendLine($" Node{currentNode} -->|Right| Node{andRightId}");
|
|
break;
|
|
|
|
case OrExpression or:
|
|
var orLeftId = GenerateMermaidNodes(or.ExpressionA, sb, nodeMap, ref nodeCounter);
|
|
var orRightId = GenerateMermaidNodes(or.ExpressionB, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} -->|Left| Node{orLeftId}");
|
|
sb.AppendLine($" Node{currentNode} -->|Right| Node{orRightId}");
|
|
break;
|
|
|
|
case NotExpression not:
|
|
var notId = GenerateMermaidNodes(not.ExpressionA, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} --> Node{notId}");
|
|
break;
|
|
|
|
case ArithmeticExpression arith:
|
|
var arithmLeftId = GenerateMermaidNodes(arith.ExpressionA, sb, nodeMap, ref nodeCounter);
|
|
var arithmRightId = GenerateMermaidNodes(arith.ExpressionB, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} --> Node{arithmLeftId}");
|
|
sb.AppendLine($" Node{currentNode} --> Node{arithmRightId}");
|
|
break;
|
|
|
|
case FunctionExpression func:
|
|
foreach (var arg in func.Arguments)
|
|
{
|
|
var argId = GenerateMermaidNodes(arg, sb, nodeMap, ref nodeCounter);
|
|
sb.AppendLine($" Node{currentNode} --> Node{argId}");
|
|
}
|
|
break;
|
|
}
|
|
|
|
return currentNode;
|
|
}
|
|
|
|
private static string GetNodeLabel(Expression expression)
|
|
{
|
|
return expression switch
|
|
{
|
|
NumberLiteralExpression num => $"Number: {num.Value}",
|
|
StringLiteralExpression str => $"String: {TruncateText(str.Value, 20)}",
|
|
DateTimeLiteralExpression dt => $"DateTime: {dt.Value:yyyy-MM-dd}",
|
|
BooleanLiteralExpression b => $"Boolean: {b.Value}",
|
|
NullLiteralExpression => "NULL",
|
|
ComparisonOperatorExpression comp => $"Comparison: {comp.Operator}",
|
|
AndExpression => "AND",
|
|
OrExpression => "OR",
|
|
NotExpression => "NOT",
|
|
ArithmeticExpression arith => $"Arithmetic: {arith.ArithmeticOperator}",
|
|
FunctionExpression func => $"Function: {func.FunctionName}",
|
|
ParameterExpression param => $"Parameter: @{param.ParameterName}",
|
|
_ => expression.GetType().Name
|
|
};
|
|
}
|
|
|
|
private static string[] GetNodeShape(Expression expression)
|
|
{
|
|
return expression switch
|
|
{
|
|
NumberLiteralExpression or StringLiteralExpression or DateTimeLiteralExpression or BooleanLiteralExpression or NullLiteralExpression => new[] { "[", "]" },
|
|
ComparisonOperatorExpression => new[] { "{", "}" },
|
|
AndExpression or OrExpression or NotExpression => new[] { "{", "}" },
|
|
FunctionExpression => new[] { "[[", "]]" },
|
|
_ => new[] { "(", ")" }
|
|
};
|
|
}
|
|
|
|
private string Indent() => new string(' ', _indentLevel * _indentString.Length);
|
|
|
|
private static string EscapeMarkdown(string text)
|
|
{
|
|
return text
|
|
.Replace("\"", """)
|
|
.Replace("[", "[")
|
|
.Replace("]", "]");
|
|
}
|
|
|
|
private static string TruncateText(string text, int maxLength)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text) || text.Length <= maxLength)
|
|
{
|
|
return text;
|
|
}
|
|
return text.Substring(0, maxLength) + "...";
|
|
}
|
|
|
|
#region IVisitor Implementation
|
|
|
|
public string VisitTableSource(TableSource tableSource)
|
|
{
|
|
return $"{Indent()}TableSource: {tableSource.TableName}";
|
|
}
|
|
|
|
public string VisitColumnExpression<TSource>(ColumnExpression<TSource> column) where TSource : SelectSource
|
|
{
|
|
return $"{Indent()}Column: {column.ColumnName}";
|
|
}
|
|
|
|
public string VisitSelectClauseColumn(SelectClauseColumn selectClauseColumn)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}SelectClauseColumn:");
|
|
_indentLevel++;
|
|
sb.AppendLine(selectClauseColumn.Expression.Accept(this));
|
|
if (!string.IsNullOrWhiteSpace(selectClauseColumn.Alias))
|
|
{
|
|
sb.AppendLine($"{Indent()}Alias: {selectClauseColumn.Alias}");
|
|
}
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitParameterExpression(ParameterExpression parameterExpression)
|
|
{
|
|
return $"{Indent()}Parameter: @{parameterExpression.ParameterName}";
|
|
}
|
|
|
|
public string VisitNumberLiteralExpression(NumberLiteralExpression numberLiteral)
|
|
{
|
|
return $"{Indent()}Number: {numberLiteral.Value}";
|
|
}
|
|
|
|
public string VisitStringLiteralExpression(StringLiteralExpression stringLiteral)
|
|
{
|
|
return $"{Indent()}String: '{stringLiteral.Value}'";
|
|
}
|
|
|
|
public string VisitDateTimeLiteralExpression(DateTimeLiteralExpression dateTimeLiteral)
|
|
{
|
|
return $"{Indent()}DateTime: {dateTimeLiteral.Value:yyyy-MM-dd HH:mm:ss}";
|
|
}
|
|
|
|
public string VisitNullLiteralExpression(NullLiteralExpression nullLiteral)
|
|
{
|
|
return $"{Indent()}NULL";
|
|
}
|
|
|
|
public string VisitBooleanLiteralExpression(BooleanLiteralExpression booleanLiteral)
|
|
{
|
|
return $"{Indent()}Boolean: {booleanLiteral.Value}";
|
|
}
|
|
|
|
public string VisitParameterLiteralExpression(ParameterLiteralExpression parameterLiteral)
|
|
{
|
|
return $"{Indent()}Parameter: {parameterLiteral.Value}";
|
|
}
|
|
|
|
public string VisitSymbolLiteralExpression(SymbolLiteralExpression symbolLiteral)
|
|
{
|
|
return $"{Indent()}Symbol: {symbolLiteral.Value}";
|
|
}
|
|
|
|
public string VisitComparisonExpression(ComparisonOperatorExpression comparison)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}Comparison ({comparison.Operator}):");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Left:");
|
|
_indentLevel++;
|
|
sb.AppendLine(comparison.ExpressionA.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Right:");
|
|
_indentLevel++;
|
|
sb.AppendLine(comparison.ExpressionB.Accept(this));
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitAndExpression(AndExpression logical)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}AND:");
|
|
_indentLevel++;
|
|
sb.AppendLine(logical.ExpressionA.Accept(this));
|
|
sb.AppendLine(logical.ExpressionB.Accept(this));
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitOrExpression(OrExpression logical)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}OR:");
|
|
_indentLevel++;
|
|
sb.AppendLine(logical.ExpressionA.Accept(this));
|
|
sb.AppendLine(logical.ExpressionB.Accept(this));
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitNotExpression(NotExpression logical)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}NOT:");
|
|
_indentLevel++;
|
|
sb.AppendLine(logical.ExpressionA.Accept(this));
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitInExpression(InExpression inExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}IN:");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Search Expression:");
|
|
_indentLevel++;
|
|
sb.AppendLine(inExpression.SearchExpression.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Values:");
|
|
_indentLevel++;
|
|
foreach (var value in inExpression.ValuesToCompare)
|
|
{
|
|
sb.AppendLine(value.Accept(this));
|
|
}
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitNotInExpression(NotInExpression inExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}NOT IN:");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Search Expression:");
|
|
_indentLevel++;
|
|
sb.AppendLine(inExpression.SearchExpression.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Values:");
|
|
_indentLevel++;
|
|
foreach (var value in inExpression.ValuesToCompare)
|
|
{
|
|
sb.AppendLine(value.Accept(this));
|
|
}
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitLikeExpression(LikeExpression likeExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}LIKE (Case {(likeExpression.CaseInsensitive ? "Insensitive" : "Sensitive")}):");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Subject:");
|
|
_indentLevel++;
|
|
sb.AppendLine(likeExpression.Subject.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Pattern:");
|
|
_indentLevel++;
|
|
sb.AppendLine(likeExpression.Pattern.Accept(this));
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitNotLikeExpression(NotLikeExpression notLikeExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}NOT LIKE:");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Subject:");
|
|
_indentLevel++;
|
|
sb.AppendLine(notLikeExpression.Subject.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Pattern:");
|
|
_indentLevel++;
|
|
sb.AppendLine(notLikeExpression.Pattern.Accept(this));
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitBetweenExpression(BetweenExpression betweenExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}BETWEEN:");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Expression:");
|
|
_indentLevel++;
|
|
sb.AppendLine(betweenExpression.Expression.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Lower Bound:");
|
|
_indentLevel++;
|
|
sb.AppendLine(betweenExpression.LowerBound.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Upper Bound:");
|
|
_indentLevel++;
|
|
sb.AppendLine(betweenExpression.UpperBound.Accept(this));
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitFunctionExpression(FunctionExpression function)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}Function: {function.FunctionName}");
|
|
if (function.Arguments.Any())
|
|
{
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Arguments:");
|
|
_indentLevel++;
|
|
foreach (var arg in function.Arguments)
|
|
{
|
|
sb.AppendLine(arg.Accept(this));
|
|
}
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitAggregateFunctionExpression(AggregateFunctionExpression aggregateFunction)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}Aggregate Function: {aggregateFunction.FunctionName}");
|
|
if (aggregateFunction.Arguments.Any())
|
|
{
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Arguments:");
|
|
_indentLevel++;
|
|
foreach (var arg in aggregateFunction.Arguments)
|
|
{
|
|
sb.AppendLine(arg.Accept(this));
|
|
}
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitCaseFunctionExpression(CaseExpression caseFunction)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}CASE:");
|
|
_indentLevel++;
|
|
foreach (var (condition, result) in caseFunction.ConditionResultPairs)
|
|
{
|
|
sb.AppendLine($"{Indent()}WHEN:");
|
|
_indentLevel++;
|
|
sb.AppendLine(condition.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}THEN:");
|
|
_indentLevel++;
|
|
sb.AppendLine(result.Accept(this));
|
|
_indentLevel--;
|
|
}
|
|
if (caseFunction.ElseResultExpression is not null)
|
|
{
|
|
sb.AppendLine($"{Indent()}ELSE:");
|
|
_indentLevel++;
|
|
sb.AppendLine(caseFunction.ElseResultExpression.Accept(this));
|
|
_indentLevel--;
|
|
}
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitArithmeticExpression(ArithmeticExpression arithmeticExpression)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine($"{Indent()}Arithmetic ({arithmeticExpression.ArithmeticOperator}):");
|
|
_indentLevel++;
|
|
sb.AppendLine($"{Indent()}Left:");
|
|
_indentLevel++;
|
|
sb.AppendLine(arithmeticExpression.ExpressionA.Accept(this));
|
|
_indentLevel--;
|
|
sb.AppendLine($"{Indent()}Right:");
|
|
_indentLevel++;
|
|
sb.AppendLine(arithmeticExpression.ExpressionB.Accept(this));
|
|
_indentLevel--;
|
|
_indentLevel--;
|
|
return sb.ToString();
|
|
}
|
|
|
|
public string VisitInputPropertyExpression(InputPropertyExpression inputPropertyExpression)
|
|
{
|
|
return $"{Indent()}InputProperty: {inputPropertyExpression.DataKeyLookup}";
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|