Generic Visitors

This commit is contained in:
Michael Schimmel
2026-01-02 14:18:46 +01:00
parent 13d8a21de7
commit 2e0db2682f
3 changed files with 49 additions and 61 deletions
-14
View File
@@ -23,9 +23,6 @@ type
FScope: IExecutionScope; FScope: IExecutionScope;
protected protected
// Setup the registry-based handlers
procedure SetupHandlers; override;
// --- Core Logic Implementation (Legacy Virtual Overrides) --- // --- Core Logic Implementation (Legacy Virtual Overrides) ---
// These are kept as virtual methods so TDebugEvaluatorVisitor can still override them. // These are kept as virtual methods so TDebugEvaluatorVisitor can still override them.
function VisitConstant(const Node: IConstantNode): TDataValue; override; function VisitConstant(const Node: IConstantNode): TDataValue; override;
@@ -117,17 +114,6 @@ begin
Assert(Assigned(AScope)); Assert(Assigned(AScope));
end; end;
procedure TEvaluatorVisitor.SetupHandlers;
begin
// The base SetupHandlers registers delegates that call the virtual methods (VisitConstant, etc.).
// Since TEvaluatorVisitor still implements its logic by overriding these virtual methods (for now),
// we just call inherited.
//
// In Phase 2/3 of refactoring, we would move the logic from VisitConstant directly into
// anonymous methods or separate handler functions registered here, bypassing the virtual table.
inherited;
end;
function TEvaluatorVisitor.Execute(const RootNode: IAstNode): TDataValue; function TEvaluatorVisitor.Execute(const RootNode: IAstNode): TDataValue;
begin begin
if not Assigned(RootNode) then if not Assigned(RootNode) then
-1
View File
@@ -513,7 +513,6 @@ type
end; end;
IAstVisitor = interface IAstVisitor = interface
// --- Central Dispatch Method (New) ---
function Visit(const Node: IAstNode): TDataValue; function Visit(const Node: IAstNode): TDataValue;
end; end;
+49 -46
View File
@@ -16,6 +16,7 @@ type
// 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; TNodeHandler<T> = reference to function(const Node: IAstNode): T;
TRegisterHandler<T> = reference to procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>);
TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor) TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor)
strict private strict private
@@ -29,13 +30,9 @@ type
function VisitBridge(const Node: IAstNode): TDataValue; function VisitBridge(const Node: IAstNode): TDataValue;
protected protected
// Registers a handler for a specific node kind.
// Subclasses can call this in their constructor/SetupHandlers to override behavior without implementing VisitXYZ.
procedure RegisterHandler(Kind: TAstNodeKind; Handler: TNodeHandler<T>);
// Initial setup of the dispatch table. // Initial setup of the dispatch table.
// The base implementation maps all kinds to the legacy VisitXYZ virtual methods. // The base implementation maps all kinds to the legacy VisitXYZ virtual methods.
procedure SetupHandlers; virtual; procedure SetupHandlers(const Register: TRegisterHandler<T>); virtual;
// The central dispatch method. Looks up the handler in the registry. // The central dispatch method. Looks up the handler in the registry.
function Visit(const Node: IAstNode): T; virtual; function Visit(const Node: IAstNode): T; virtual;
@@ -84,7 +81,8 @@ type
function Accept(const Node: IAstNode): T; virtual; function Accept(const Node: IAstNode): T; virtual;
public public
constructor Create; procedure AfterConstruction; override;
procedure BeforeDestruction; override;
end; end;
// Helper for transformation visitors (returns IAstNode) // Helper for transformation visitors (returns IAstNode)
@@ -137,74 +135,79 @@ implementation
{ TAstVisitor<T> } { TAstVisitor<T> }
constructor TAstVisitor<T>.Create; procedure TAstVisitor<T>.AfterConstruction;
begin begin
inherited Create; inherited;
SetupHandlers; SetupHandlers(procedure(Kind: TAstNodeKind; const Handler: TNodeHandler<T>) begin FHandlers[Kind] := Handler; end);
end; end;
procedure TAstVisitor<T>.RegisterHandler(Kind: TAstNodeKind; Handler: TNodeHandler<T>); procedure TAstVisitor<T>.BeforeDestruction;
begin begin
FHandlers[Kind] := Handler; for var i := Low(TAstNodeKind) to High(TAstNodeKind) do
FHandlers[i] := nil;
inherited;
end; end;
procedure TAstVisitor<T>.SetupHandlers; 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.
// This provides the compatibility layer for existing subclasses. // This provides the compatibility layer for existing subclasses.
// In Phase 2, subclasses will register their own handlers directly here. // In Phase 2, subclasses will register their own handlers directly here.
// Core // Core
FHandlers[akConstant] := function(const Node: IAstNode): T begin Result := VisitConstant(Node.AsConstant); end; Register(akConstant, function(const Node: IAstNode): T begin Result := VisitConstant(Node.AsConstant); end);
FHandlers[akIdentifier] := function(const Node: IAstNode): T begin Result := VisitIdentifier(Node.AsIdentifier); end; Register(akIdentifier, function(const Node: IAstNode): T begin Result := VisitIdentifier(Node.AsIdentifier); end);
FHandlers[akKeyword] := function(const Node: IAstNode): T begin Result := VisitKeyword(Node.AsKeyword); end; Register(akKeyword, function(const Node: IAstNode): T begin Result := VisitKeyword(Node.AsKeyword); end);
// Lists // Lists
FHandlers[akParameterList] := function(const Node: IAstNode): T begin Result := VisitParameterList(Node.AsParameterList); end; Register(akParameterList, function(const Node: IAstNode): T begin Result := VisitParameterList(Node.AsParameterList); end);
FHandlers[akArgumentList] := function(const Node: IAstNode): T begin Result := VisitArgumentList(Node.AsArgumentList); end; Register(akArgumentList, function(const Node: IAstNode): T begin Result := VisitArgumentList(Node.AsArgumentList); end);
FHandlers[akExpressionList] := function(const Node: IAstNode): T begin Result := VisitExpressionList(Node.AsExpressionList); end; Register(akExpressionList, function(const Node: IAstNode): T begin Result := VisitExpressionList(Node.AsExpressionList); end);
FHandlers[akRecordFieldList] := function(const Node: IAstNode): T begin Result := VisitRecordFieldList(Node.AsRecordFieldList); end; Register(akRecordFieldList, function(const Node: IAstNode): T begin Result := VisitRecordFieldList(Node.AsRecordFieldList); end);
FHandlers[akRecordField] := function(const Node: IAstNode): T begin Result := VisitRecordField(Node.AsRecordField); end; Register(akRecordField, function(const Node: IAstNode): T begin Result := VisitRecordField(Node.AsRecordField); end);
// Structural // Structural
FHandlers[akIfExpression] := function(const Node: IAstNode): T begin Result := VisitIfExpression(Node.AsIfExpression); end; Register(akIfExpression, function(const Node: IAstNode): T begin Result := VisitIfExpression(Node.AsIfExpression); end);
FHandlers[akCondExpression] := function(const Node: IAstNode): T begin Result := VisitCondExpression(Node.AsCondExpression); end; Register(akCondExpression, function(const Node: IAstNode): T begin Result := VisitCondExpression(Node.AsCondExpression); end);
FHandlers[akLambdaExpression] := function(const Node: IAstNode): T begin Result := VisitLambdaExpression(Node.AsLambdaExpression); end; Register(akLambdaExpression, function(const Node: IAstNode): T begin Result := VisitLambdaExpression(Node.AsLambdaExpression); end);
FHandlers[akFunctionCall] := function(const Node: IAstNode): T begin Result := VisitFunctionCall(Node.AsFunctionCall); end; Register(akFunctionCall, function(const Node: IAstNode): T begin Result := VisitFunctionCall(Node.AsFunctionCall); end);
FHandlers[akMacroExpansion] := function(const Node: IAstNode): T begin Result := VisitMacroExpansionNode(Node.AsMacroExpansion); end; Register(akMacroExpansion, function(const Node: IAstNode): T begin Result := VisitMacroExpansionNode(Node.AsMacroExpansion); end);
FHandlers[akBlockExpression] := function(const Node: IAstNode): T begin Result := VisitBlockExpression(Node.AsBlockExpression); end; Register(akBlockExpression, function(const Node: IAstNode): T begin Result := VisitBlockExpression(Node.AsBlockExpression); end);
FHandlers[akVariableDeclaration] := Register(
function(const Node: IAstNode): T begin Result := VisitVariableDeclaration(Node.AsVariableDeclaration); end; akVariableDeclaration,
FHandlers[akAssignment] := function(const Node: IAstNode): T begin Result := VisitAssignment(Node.AsAssignment); end; function(const Node: IAstNode): T begin Result := VisitVariableDeclaration(Node.AsVariableDeclaration); end
FHandlers[akMacroDefinition] := function(const Node: IAstNode): T begin Result := VisitMacroDefinition(Node.AsMacroDefinition); end; );
FHandlers[akQuasiquote] := function(const Node: IAstNode): T begin Result := VisitQuasiquote(Node.AsQuasiquote); end; Register(akAssignment, function(const Node: IAstNode): T begin Result := VisitAssignment(Node.AsAssignment); end);
FHandlers[akUnquote] := function(const Node: IAstNode): T begin Result := VisitUnquote(Node.AsUnquote); end; Register(akMacroDefinition, function(const Node: IAstNode): T begin Result := VisitMacroDefinition(Node.AsMacroDefinition); end);
FHandlers[akUnquoteSplicing] := function(const Node: IAstNode): T begin Result := VisitUnquoteSplicing(Node.AsUnquoteSplicing); end; Register(akQuasiquote, function(const Node: IAstNode): T begin Result := VisitQuasiquote(Node.AsQuasiquote); end);
FHandlers[akIndexer] := function(const Node: IAstNode): T begin Result := VisitIndexer(Node.AsIndexer); end; Register(akUnquote, function(const Node: IAstNode): T begin Result := VisitUnquote(Node.AsUnquote); end);
FHandlers[akMemberAccess] := function(const Node: IAstNode): T begin Result := VisitMemberAccess(Node.AsMemberAccess); end; Register(akUnquoteSplicing, function(const Node: IAstNode): T begin Result := VisitUnquoteSplicing(Node.AsUnquoteSplicing); end);
FHandlers[akRecordLiteral] := function(const Node: IAstNode): T begin Result := VisitRecordLiteral(Node.AsRecordLiteral); end; Register(akIndexer, function(const Node: IAstNode): T begin Result := VisitIndexer(Node.AsIndexer); end);
FHandlers[akCreateSeries] := function(const Node: IAstNode): T begin Result := VisitCreateSeries(Node.AsCreateSeries); end; Register(akMemberAccess, function(const Node: IAstNode): T begin Result := VisitMemberAccess(Node.AsMemberAccess); end);
FHandlers[akAddSeriesItem] := function(const Node: IAstNode): T begin Result := VisitAddSeriesItem(Node.AsAddSeriesItem); end; Register(akRecordLiteral, function(const Node: IAstNode): T begin Result := VisitRecordLiteral(Node.AsRecordLiteral); end);
FHandlers[akSeriesLength] := function(const Node: IAstNode): T begin Result := VisitSeriesLength(Node.AsSeriesLength); end; Register(akCreateSeries, function(const Node: IAstNode): T begin Result := VisitCreateSeries(Node.AsCreateSeries); end);
FHandlers[akRecur] := function(const Node: IAstNode): T begin Result := VisitRecurNode(Node.AsRecur); end; Register(akAddSeriesItem, function(const Node: IAstNode): T begin Result := VisitAddSeriesItem(Node.AsAddSeriesItem); end);
FHandlers[akNop] := function(const Node: IAstNode): T begin Result := VisitNop(Node.AsNop); 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(akNop, function(const Node: IAstNode): T begin Result := VisitNop(Node.AsNop); end);
// Pipes // Pipes
FHandlers[akPipeInput] := function(const Node: IAstNode): T begin Result := VisitPipeInput(Node.AsPipeInput); end; Register(akPipeInput, function(const Node: IAstNode): T begin Result := VisitPipeInput(Node.AsPipeInput); end);
FHandlers[akPipeSelectorList] := function(const Node: IAstNode): T begin Result := VisitPipeSelectorList(Node.AsPipeSelectorList); end; Register(akPipeSelectorList, function(const Node: IAstNode): T begin Result := VisitPipeSelectorList(Node.AsPipeSelectorList); end);
FHandlers[akPipeInputList] := function(const Node: IAstNode): T begin Result := VisitPipeInputList(Node.AsPipeInputList); end; Register(akPipeInputList, function(const Node: IAstNode): T begin Result := VisitPipeInputList(Node.AsPipeInputList); end);
FHandlers[akPipe] := function(const Node: IAstNode): T begin Result := VisitPipe(Node.AsPipe); end; Register(akPipe, function(const Node: IAstNode): T begin Result := VisitPipe(Node.AsPipe); end);
end; end;
function TAstVisitor<T>.Visit(const Node: IAstNode): T; function TAstVisitor<T>.Visit(const Node: IAstNode): T;
var var
[unsafe]
handler: TNodeHandler<T>; handler: TNodeHandler<T>;
begin begin
if not Assigned(Node) then if not Assigned(Node) then
Exit(Default(T)); Exit(Default(T));
// O(1) Lookup // O(1) Lookup
handler := FHandlers[Node.Kind]; handler := TNodeHandler<T>(FHandlers[Node.Kind]);
if Assigned(handler) then if Assigned(handler) then
Result := handler(Node) Result := handler(Node)