208 lines
5.5 KiB
ObjectPascal
208 lines
5.5 KiB
ObjectPascal
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 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;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Myc.Data.POD,
|
|
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, 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): 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.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;
|
|
|
|
end.
|