Generic Visitors
This commit is contained in:
+101
-38
@@ -14,8 +14,11 @@ uses
|
||||
type
|
||||
TAstVisitor<T> = class;
|
||||
|
||||
// Delegate for handling a specific node kind within the visitor context
|
||||
TNodeHandler<T> = reference to function(const Node: IAstNode): T;
|
||||
// Delegate for handling a specific node kind within the visitor context.
|
||||
// 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>);
|
||||
|
||||
TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor)
|
||||
@@ -138,6 +141,8 @@ implementation
|
||||
procedure TAstVisitor<T>.AfterConstruction;
|
||||
begin
|
||||
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);
|
||||
end;
|
||||
|
||||
@@ -150,52 +155,110 @@ end;
|
||||
|
||||
procedure TAstVisitor<T>.SetupHandlers(const Register: TRegisterHandler<T>);
|
||||
begin
|
||||
// Map all kinds to the legacy virtual methods.
|
||||
// This provides the compatibility layer for existing subclasses.
|
||||
// In Phase 2, subclasses will register their own handlers directly here.
|
||||
// Map all kinds to the legacy virtual methods using the passed Visitor instance (V).
|
||||
|
||||
// Core
|
||||
Register(akConstant, function(const Node: IAstNode): T begin Result := VisitConstant(Node.AsConstant); end);
|
||||
Register(akIdentifier, function(const Node: IAstNode): T begin Result := VisitIdentifier(Node.AsIdentifier); end);
|
||||
Register(akKeyword, function(const Node: IAstNode): T begin Result := VisitKeyword(Node.AsKeyword); end);
|
||||
Register(akConstant, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitConstant(N.AsConstant); end);
|
||||
Register(akIdentifier, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIdentifier(N.AsIdentifier); end);
|
||||
Register(akKeyword, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitKeyword(N.AsKeyword); end);
|
||||
|
||||
// Lists
|
||||
Register(akParameterList, function(const Node: IAstNode): T begin Result := VisitParameterList(Node.AsParameterList); end);
|
||||
Register(akArgumentList, function(const Node: IAstNode): T begin Result := VisitArgumentList(Node.AsArgumentList); end);
|
||||
Register(akExpressionList, function(const Node: IAstNode): T begin Result := VisitExpressionList(Node.AsExpressionList); 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(
|
||||
akParameterList,
|
||||
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitParameterList(N.AsParameterList); 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
|
||||
Register(akIfExpression, function(const Node: IAstNode): T begin Result := VisitIfExpression(Node.AsIfExpression); end);
|
||||
Register(akCondExpression, function(const Node: IAstNode): T begin Result := VisitCondExpression(Node.AsCondExpression); end);
|
||||
Register(akLambdaExpression, function(const Node: IAstNode): T begin Result := VisitLambdaExpression(Node.AsLambdaExpression); 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(akBlockExpression, function(const Node: IAstNode): T begin Result := VisitBlockExpression(Node.AsBlockExpression); end);
|
||||
Register(
|
||||
akIfExpression,
|
||||
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIfExpression(N.AsIfExpression); end
|
||||
);
|
||||
Register(
|
||||
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(
|
||||
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(akMacroDefinition, function(const Node: IAstNode): T begin Result := VisitMacroDefinition(Node.AsMacroDefinition); end);
|
||||
Register(akQuasiquote, function(const Node: IAstNode): T begin Result := VisitQuasiquote(Node.AsQuasiquote); end);
|
||||
Register(akUnquote, function(const Node: IAstNode): T begin Result := VisitUnquote(Node.AsUnquote); 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(akMemberAccess, function(const Node: IAstNode): T begin Result := VisitMemberAccess(Node.AsMemberAccess); end);
|
||||
Register(akRecordLiteral, function(const Node: IAstNode): T begin Result := VisitRecordLiteral(Node.AsRecordLiteral); end);
|
||||
Register(akCreateSeries, function(const Node: IAstNode): T begin Result := VisitCreateSeries(Node.AsCreateSeries); end);
|
||||
Register(akAddSeriesItem, function(const Node: IAstNode): T begin Result := VisitAddSeriesItem(Node.AsAddSeriesItem); 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);
|
||||
Register(akAssignment, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitAssignment(N.AsAssignment); end);
|
||||
Register(
|
||||
akMacroDefinition,
|
||||
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitMacroDefinition(N.AsMacroDefinition); end
|
||||
);
|
||||
Register(akQuasiquote, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitQuasiquote(N.AsQuasiquote); end);
|
||||
Register(akUnquote, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitUnquote(N.AsUnquote); end);
|
||||
Register(
|
||||
akUnquoteSplicing,
|
||||
function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitUnquoteSplicing(N.AsUnquoteSplicing); end
|
||||
);
|
||||
Register(akIndexer, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitIndexer(N.AsIndexer); 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
|
||||
Register(akPipeInput, function(const Node: IAstNode): T begin Result := VisitPipeInput(Node.AsPipeInput); end);
|
||||
Register(akPipeSelectorList, function(const Node: IAstNode): T begin Result := VisitPipeSelectorList(Node.AsPipeSelectorList); end);
|
||||
Register(akPipeInputList, function(const Node: IAstNode): T begin Result := VisitPipeInputList(Node.AsPipeInputList); end);
|
||||
Register(akPipe, function(const Node: IAstNode): T begin Result := VisitPipe(Node.AsPipe); end);
|
||||
Register(akPipeInput, function(const V: TAstVisitor<T>; const N: IAstNode): T begin Result := V.VisitPipeInput(N.AsPipeInput); end);
|
||||
Register(
|
||||
akPipeSelectorList,
|
||||
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;
|
||||
|
||||
function TAstVisitor<T>.Visit(const Node: IAstNode): T;
|
||||
@@ -210,7 +273,7 @@ begin
|
||||
handler := TNodeHandler<T>(FHandlers[Node.Kind]);
|
||||
|
||||
if Assigned(handler) then
|
||||
Result := handler(Node)
|
||||
Result := handler(Self, Node)
|
||||
else
|
||||
raise ENoHandlerException.Create(Node.Kind.ToString);
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user