unit Myc.Ast.Printer; interface uses System.SysUtils, System.Classes, System.Generics.Collections, 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 VisitConstant(const Node: IConstantNode): TAstValue; function VisitIdentifier(const Node: IIdentifierNode): TAstValue; function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; function VisitIfExpression(const Node: IIfExpressionNode): TAstValue; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue; function VisitAssignment(const Node: IAssignmentNode): TAstValue; function VisitIndexer(const Node: IIndexerNode): TAstValue; function VisitMemberAccess(const Node: IMemberAccessNode): TAstValue; 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.VisitConstant(const Node: IConstantNode): TAstValue; begin AppendLine(Format('Constant (%s)', [Node.Value.ToString])); Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitIdentifier(const Node: IIdentifierNode): TAstValue; begin AppendLine(Format('Identifier (%s)', [Node.Name])); Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; begin AppendLine(Format('BinaryExpr "%s"', [Node.Operator.ToString])); Indent; Node.Left.Accept(Self); Node.Right.Accept(Self); Unindent; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; begin AppendLine(Format('UnaryExpr "%s"', [Node.Operator.ToString])); Indent; Node.Right.Accept(Self); Unindent; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitIfExpression(const Node: IIfExpressionNode): TAstValue; 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 := TAstValue.Void; end; function TPrettyPrintVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue; 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 := TAstValue.Void; end; function TPrettyPrintVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; 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 := TAstValue.Void; end; function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; 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 := TAstValue.Void; end; function TPrettyPrintVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; var expr: IExpressionNode; begin AppendLine('Block'); Indent; for expr in Node.Expressions do expr.Accept(Self); Unindent; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue; begin AppendLine(Format('VarDecl (%s)', [Node.Identifier.Name])); if Assigned(Node.Initializer) then begin Indent; Node.Initializer.Accept(Self); Unindent; end; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitAssignment(const Node: IAssignmentNode): TAstValue; begin // Print the assignment node. AppendLine(Format('Assignment (%s)', [Node.Identifier.Name])); Indent; Node.Value.Accept(Self); Unindent; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitIndexer(const Node: IIndexerNode): TAstValue; begin AppendLine('Indexer'); Indent; AppendLine('Base:'); Indent; Node.Base.Accept(Self); Unindent; AppendLine('Index:'); Indent; Node.Index.Accept(Self); Unindent; Unindent; Result := TAstValue.Void; end; function TPrettyPrintVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TAstValue; begin AppendLine(Format('MemberAccess (Member: %s)', [Node.Member.Name])); Indent; AppendLine('Base:'); Indent; Node.Base.Accept(Self); Unindent; Unindent; Result := TAstValue.Void; end; end.