unit Myc.Ast.Printer; interface uses System.SysUtils, System.Classes, System.Generics.Collections, Myc.Data.Types, Myc.Ast; type TPrettyPrintVisitor = class(TInterfacedObject, IAstVisitor) private FBuilder: TStringBuilder; FIndentLevel: Integer; procedure Indent; procedure Unindent; procedure AppendLine(const S: string); public constructor Create; destructor Destroy; override; function GetResult: string; // IAstVisitor function VisitConstant(const Node: IConstantNode): IDataValue; function VisitIdentifier(const Node: IIdentifierNode): IDataValue; function VisitBinaryExpression(const Node: IBinaryExpressionNode): IDataValue; function VisitUnaryExpression(const Node: IUnaryExpressionNode): IDataValue; function VisitIfExpression(const Node: IIfExpressionNode): IDataValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IDataValue; function VisitFunctionCall(const Node: IFunctionCallNode): IDataValue; function VisitBlockExpression(const Node: IBlockExpressionNode): IDataValue; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IDataValue; end; implementation { TPrettyPrintVisitor } constructor TPrettyPrintVisitor.Create; begin inherited Create; FBuilder := TStringBuilder.Create; FIndentLevel := 0; 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, 2); end; procedure TPrettyPrintVisitor.Unindent; begin dec(FIndentLevel, 2); end; procedure TPrettyPrintVisitor.AppendLine(const S: string); begin FBuilder.Append(''.PadLeft(FIndentLevel)); FBuilder.AppendLine(S); end; function TPrettyPrintVisitor.VisitConstant(const Node: IConstantNode): IDataValue; begin AppendLine(Format('Constant (%s)', [Node.Value.AsString])); Result := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitIdentifier(const Node: IIdentifierNode): IDataValue; begin AppendLine(Format('Identifier (%s)', [Node.Name])); Result := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): IDataValue; begin AppendLine(Format('BinaryExpr (%s)', [Node.Operator.ToString])); Indent; Node.Left.Accept(Self); Node.Right.Accept(Self); Unindent; Result := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): IDataValue; begin AppendLine(Format('UnaryExpr (%s)', [Node.Operator.ToString])); Indent; Node.Right.Accept(Self); Unindent; Result := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode): IDataValue; begin AppendLine('IfExpr'); 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 := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): IDataValue; 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 := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IDataValue; var arg: IExpressionNode; 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 := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): IDataValue; var expr: IExpressionNode; begin AppendLine('Block'); Indent; for expr in Node.Expressions do expr.Accept(Self); Unindent; Result := TDataType.Void.Value; end; function TPrettyPrintVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IDataValue; begin AppendLine(Format('VarDecl (%s)', [Node.Identifier.Name])); if Assigned(Node.Initializer) then begin Indent; Node.Initializer.Accept(Self); Unindent; end; Result := TDataType.Void.Value; end; end.