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.