Generic Visitors
This commit is contained in:
+101
-38
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user