Generic Visitors

This commit is contained in:
Michael Schimmel
2026-01-02 14:29:16 +01:00
parent 2e0db2682f
commit db74b83e11
+101 -38
View File
@@ -14,8 +14,11 @@ uses
type type
TAstVisitor<T> = class; TAstVisitor<T> = class;
// Delegate for handling a specific node kind within the visitor context // Delegate for handling a specific node kind within the visitor context.
TNodeHandler<T> = reference to function(const Node: IAstNode): T; // Receives the visitor instance explicitly to allow for stateless handlers or external logic.
TNodeHandler<T> = reference to function(const Visitor: TAstVisitor<T>; const Node: IAstNode): T;
// Callback to register a handler for a specific node kind.
TRegisterHandler<T> = reference to procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>); TRegisterHandler<T> = reference to procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>);
TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor) TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor)
@@ -138,6 +141,8 @@ implementation
procedure TAstVisitor<T>.AfterConstruction; procedure TAstVisitor<T>.AfterConstruction;
begin begin
inherited; inherited;
// We pass explicit anonymous methods that use the 'Visitor' argument.
// This ensures that even if handlers are moved out of context later, they operate on the passed visitor instance.
SetupHandlers(procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>) begin FHandlers[Kind] := Handler; end); SetupHandlers(procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>) begin FHandlers[Kind] := Handler; end);
end; end;
@@ -150,52 +155,110 @@ end;
procedure TAstVisitor<T>.SetupHandlers(const Register: TRegisterHandler<T>); procedure TAstVisitor<T>.SetupHandlers(const Register: TRegisterHandler<T>);
begin begin
// Map all kinds to the legacy virtual methods. // Map all kinds to the legacy virtual methods using the passed Visitor instance (V).
// This provides the compatibility layer for existing subclasses.
// In Phase 2, subclasses will register their own handlers directly here.
// Core // Core
Register(akConstant, function(const Node: IAstNode): T begin Result := VisitConstant(Node.AsConstant); end); Register(akConstant, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitConstant(N.AsConstant); end);
Register(akIdentifier, function(const Node: IAstNode): T begin Result := VisitIdentifier(Node.AsIdentifier); end); Register(akIdentifier, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIdentifier(N.AsIdentifier); end);
Register(akKeyword, function(const Node: IAstNode): T begin Result := VisitKeyword(Node.AsKeyword); end); Register(akKeyword, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitKeyword(N.AsKeyword); end);
// Lists // Lists
Register(akParameterList, function(const Node: IAstNode): T begin Result := VisitParameterList(Node.AsParameterList); end); Register(
Register(akArgumentList, function(const Node: IAstNode): T begin Result := VisitArgumentList(Node.AsArgumentList); end); akParameterList,
Register(akExpressionList, function(const Node: IAstNode): T begin Result := VisitExpressionList(Node.AsExpressionList); end); function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitParameterList(N.AsParameterList); end
Register(akRecordFieldList, function(const Node: IAstNode): T begin Result := VisitRecordFieldList(Node.AsRecordFieldList); end); );
Register(akRecordField, function(const Node: IAstNode): T begin Result := VisitRecordField(Node.AsRecordField); end); Register(
akArgumentList,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitArgumentList(N.AsArgumentList); end
);
Register(
akExpressionList,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitExpressionList(N.AsExpressionList); end
);
Register(
akRecordFieldList,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitRecordFieldList(N.AsRecordFieldList); end
);
Register(
akRecordField,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitRecordField(N.AsRecordField); end
);
// Structural // Structural
Register(akIfExpression, function(const Node: IAstNode): T begin Result := VisitIfExpression(Node.AsIfExpression); end); Register(
Register(akCondExpression, function(const Node: IAstNode): T begin Result := VisitCondExpression(Node.AsCondExpression); end); akIfExpression,
Register(akLambdaExpression, function(const Node: IAstNode): T begin Result := VisitLambdaExpression(Node.AsLambdaExpression); end); function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIfExpression(N.AsIfExpression); end
Register(akFunctionCall, function(const Node: IAstNode): T begin Result := VisitFunctionCall(Node.AsFunctionCall); end); );
Register(akMacroExpansion, function(const Node: IAstNode): T begin Result := VisitMacroExpansionNode(Node.AsMacroExpansion); end); Register(
Register(akBlockExpression, function(const Node: IAstNode): T begin Result := VisitBlockExpression(Node.AsBlockExpression); end); akCondExpression,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitCondExpression(N.AsCondExpression); end
);
Register(
akLambdaExpression,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitLambdaExpression(N.AsLambdaExpression); end
);
Register(
akFunctionCall,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitFunctionCall(N.AsFunctionCall); end
);
Register(
akMacroExpansion,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitMacroExpansionNode(N.AsMacroExpansion); end
);
Register(
akBlockExpression,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitBlockExpression(N.AsBlockExpression); end
);
Register( Register(
akVariableDeclaration, akVariableDeclaration,
function(const Node: IAstNode): T begin Result := VisitVariableDeclaration(Node.AsVariableDeclaration); end function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitVariableDeclaration(N.AsVariableDeclaration); end
); );
Register(akAssignment, function(const Node: IAstNode): T begin Result := VisitAssignment(Node.AsAssignment); end); Register(akAssignment, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitAssignment(N.AsAssignment); end);
Register(akMacroDefinition, function(const Node: IAstNode): T begin Result := VisitMacroDefinition(Node.AsMacroDefinition); end); Register(
Register(akQuasiquote, function(const Node: IAstNode): T begin Result := VisitQuasiquote(Node.AsQuasiquote); end); akMacroDefinition,
Register(akUnquote, function(const Node: IAstNode): T begin Result := VisitUnquote(Node.AsUnquote); end); function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitMacroDefinition(N.AsMacroDefinition); end
Register(akUnquoteSplicing, function(const Node: IAstNode): T begin Result := VisitUnquoteSplicing(Node.AsUnquoteSplicing); end); );
Register(akIndexer, function(const Node: IAstNode): T begin Result := VisitIndexer(Node.AsIndexer); end); Register(akQuasiquote, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitQuasiquote(N.AsQuasiquote); end);
Register(akMemberAccess, function(const Node: IAstNode): T begin Result := VisitMemberAccess(Node.AsMemberAccess); end); Register(akUnquote, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitUnquote(N.AsUnquote); end);
Register(akRecordLiteral, function(const Node: IAstNode): T begin Result := VisitRecordLiteral(Node.AsRecordLiteral); end); Register(
Register(akCreateSeries, function(const Node: IAstNode): T begin Result := VisitCreateSeries(Node.AsCreateSeries); end); akUnquoteSplicing,
Register(akAddSeriesItem, function(const Node: IAstNode): T begin Result := VisitAddSeriesItem(Node.AsAddSeriesItem); end); function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitUnquoteSplicing(N.AsUnquoteSplicing); end
Register(akSeriesLength, function(const Node: IAstNode): T begin Result := VisitSeriesLength(Node.AsSeriesLength); end); );
Register(akRecur, function(const Node: IAstNode): T begin Result := VisitRecurNode(Node.AsRecur); end); Register(akIndexer, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIndexer(N.AsIndexer); end);
Register(akNop, function(const Node: IAstNode): T begin Result := VisitNop(Node.AsNop); end); Register(
akMemberAccess,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitMemberAccess(N.AsMemberAccess); end
);
Register(
akRecordLiteral,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitRecordLiteral(N.AsRecordLiteral); end
);
Register(
akCreateSeries,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitCreateSeries(N.AsCreateSeries); end
);
Register(
akAddSeriesItem,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitAddSeriesItem(N.AsAddSeriesItem); end
);
Register(
akSeriesLength,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitSeriesLength(N.AsSeriesLength); end
);
Register(akRecur, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitRecurNode(N.AsRecur); end);
Register(akNop, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitNop(N.AsNop); end);
// Pipes // Pipes
Register(akPipeInput, function(const Node: IAstNode): T begin Result := VisitPipeInput(Node.AsPipeInput); end); Register(akPipeInput, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitPipeInput(N.AsPipeInput); end);
Register(akPipeSelectorList, function(const Node: IAstNode): T begin Result := VisitPipeSelectorList(Node.AsPipeSelectorList); end); Register(
Register(akPipeInputList, function(const Node: IAstNode): T begin Result := VisitPipeInputList(Node.AsPipeInputList); end); akPipeSelectorList,
Register(akPipe, function(const Node: IAstNode): T begin Result := VisitPipe(Node.AsPipe); end); function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitPipeSelectorList(N.AsPipeSelectorList); end
);
Register(
akPipeInputList,
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitPipeInputList(N.AsPipeInputList); end
);
Register(akPipe, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitPipe(N.AsPipe); end);
end; end;
function TAstVisitor<T>.Visit(const Node: IAstNode): T; function TAstVisitor<T>.Visit(const Node: IAstNode): T;
@@ -210,7 +273,7 @@ begin
handler := TNodeHandler<T>(FHandlers[Node.Kind]); handler := TNodeHandler<T>(FHandlers[Node.Kind]);
if Assigned(handler) then if Assigned(handler) then
Result := handler(Node) Result := handler(Self, Node)
else else
raise ENoHandlerException.Create(Node.Kind.ToString); raise ENoHandlerException.Create(Node.Kind.ToString);
end; end;