Files
MycLib/Src/AST/Myc.Ast.Printer.pas
T
2025-09-19 11:53:16 +02:00

313 lines
8.4 KiB
ObjectPascal

unit Myc.Ast.Printer;
interface
uses
System.SysUtils,
System.Classes,
System.Generics.Collections,
Myc.Data.Value,
Myc.Ast.Nodes,
Myc.Ast;
type
TPrettyPrintVisitor = class(TInterfacedObject, IAstVisitor)
private
FBuilder: TStringBuilder;
FIndentLevel: Integer;
procedure Indent;
procedure Unindent;
procedure AppendLine(const S: string);
public
constructor Create(AIndentLevel: Integer = 0);
destructor Destroy; override;
function GetResult: string;
// IAstVisitor
function Execute(const RootNode: IAstNode): TDataValue;
function VisitConstant(const Node: IConstantNode): TDataValue;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
function VisitAssignment(const Node: IAssignmentNode): TDataValue;
function VisitIndexer(const Node: IIndexerNode): TDataValue;
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
end;
implementation
uses
Myc.Data.Scalar,
Myc.Data.Decimal;
{ TPrettyPrintVisitor }
constructor TPrettyPrintVisitor.Create(AIndentLevel: Integer);
begin
inherited Create;
FBuilder := TStringBuilder.Create;
FIndentLevel := 0;
FIndentLevel := AIndentLevel;
end;
destructor TPrettyPrintVisitor.Destroy;
begin
FBuilder.Free;
inherited Destroy;
end;
function TPrettyPrintVisitor.GetResult: string;
begin
Result := FBuilder.ToString;
end;
procedure TPrettyPrintVisitor.Indent;
begin
inc(FIndentLevel, 4);
end;
procedure TPrettyPrintVisitor.Unindent;
begin
dec(FIndentLevel, 4);
end;
procedure TPrettyPrintVisitor.AppendLine(const S: string);
begin
FBuilder.Append(''.PadLeft(FIndentLevel));
FBuilder.AppendLine(S);
end;
function TPrettyPrintVisitor.Execute(const RootNode: IAstNode): TDataValue;
begin
Result := RootNode.Accept(Self);
end;
function TPrettyPrintVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
begin
AppendLine(Format('Constant (%s)', [Node.Value.ToString]));
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin
AppendLine(Format('Identifier (%s)', [Node.Name]));
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
begin
AppendLine(Format('BinaryExpr "%s"', [Node.Operator.ToString]));
Indent;
Node.Left.Accept(Self);
Node.Right.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
begin
AppendLine(Format('UnaryExpr "%s"', [Node.Operator.ToString]));
Indent;
Node.Right.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin
AppendLine('IfExpr');
Indent;
AppendLine('Condition:');
Indent;
Node.Condition.Accept(Self);
Unindent;
AppendLine('Then:');
Indent;
Node.ThenBranch.Accept(Self);
Unindent;
if Node.ElseBranch <> nil then
begin
AppendLine('Else:');
Indent;
Node.ElseBranch.Accept(Self);
Unindent;
end;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin
AppendLine('TernaryExpr');
Indent;
AppendLine('Condition:');
Indent;
Node.Condition.Accept(Self);
Unindent;
AppendLine('Then:');
Indent;
Node.ThenBranch.Accept(Self);
Unindent;
AppendLine('Else:');
Indent;
Node.ElseBranch.Accept(Self);
Unindent;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
var
param: IIdentifierNode;
paramNames: TStringList;
begin
paramNames := TStringList.Create;
try
for param in Node.Parameters do
paramNames.Add(param.Name);
AppendLine(Format('Lambda (params: %s)', [paramNames.CommaText]));
finally
paramNames.Free;
end;
Indent;
AppendLine('Body:');
Indent;
Node.Body.Accept(Self);
Unindent;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
var
arg: IAstNode;
begin
AppendLine('FunctionCall');
Indent;
AppendLine('Callee:');
Indent;
Node.Callee.Accept(Self);
Unindent;
AppendLine('Arguments:');
Indent;
for arg in Node.Arguments do
arg.Accept(Self);
Unindent;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
var
expr: IAstNode;
begin
AppendLine('Block');
Indent;
for expr in Node.Expressions do
expr.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin
AppendLine(Format('VarDecl (%s)', [Node.Identifier.Name]));
if Assigned(Node.Initializer) then
begin
Indent;
Node.Initializer.Accept(Self);
Unindent;
end;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitAssignment(const Node: IAssignmentNode): TDataValue;
begin
// Print the assignment node.
AppendLine(Format('Assignment (%s)', [Node.Identifier.Name]));
Indent;
Node.Value.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitIndexer(const Node: IIndexerNode): TDataValue;
begin
AppendLine('Indexer');
Indent;
AppendLine('Base:');
Indent;
Node.Base.Accept(Self);
Unindent;
AppendLine('Index:');
Indent;
Node.Index.Accept(Self);
Unindent;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin
AppendLine(Format('MemberAccess (Member: %s)', [Node.Member.Name]));
Indent;
AppendLine('Base:');
Indent;
Node.Base.Accept(Self);
Unindent;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin
AppendLine('CreateSeries');
Indent;
AppendLine('Definition: ' + Node.Definition);
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin
AppendLine('AddSeriesItem');
Indent;
AppendLine('Series:');
Indent;
Node.Series.Accept(Self);
Unindent;
AppendLine('Value:');
Indent;
Node.Value.Accept(Self);
Unindent;
if Assigned(Node.Lookback) then
begin
AppendLine('Lookback:');
Indent;
Node.Lookback.Accept(Self);
Unindent;
end;
Unindent;
Result := TDataValue.Void;
end;
function TPrettyPrintVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin
AppendLine('SeriesLength');
Indent;
Node.Series.Accept(Self);
Unindent;
Result := TDataValue.Void;
end;
end.