Resolved circular depependancy between macro expander and binder

This commit is contained in:
Michael Schimmel
2025-11-23 15:40:14 +01:00
parent 30933072a4
commit 738e595f95
2 changed files with 78 additions and 39 deletions
+25 -1
View File
@@ -560,12 +560,36 @@ end;
function TEnvironment.ExpandMacros(const Node: IAstNode): IAstNode;
begin
var cExecutionStrategy := FExecutionStrategy;
// The Glue: This callback performs the full compilation pipeline for a macro argument expression.
// It binds the node to the layout of the temporary macro scope and then executes it.
var macroEvaluator: TMacroEvaluatorProc :=
function(const Scope: IExecutionScope; const ANode: IAstNode): TDataValue
var
tmpLayout: IScopeLayout;
evaluator: IEvaluatorVisitor;
boundSubAst: IAstNode;
scratchScope: IExecutionScope;
begin
// 1. Binding
// Note: Scope is dynamic (from TMacroExpander), so Descriptor.Layout describes current variables.
boundSubAst := TAstBinder.Bind(Scope.Descriptor.Layout, ANode, tmpLayout);
// 2. Scope Matching
// Create a child scope to ensure correct depth resolution (Binder sees Layout at depth 0 relative to itself)
scratchScope := TScope.CreateScope(Scope, nil, nil);
// 3. Execution
evaluator := cExecutionStrategy.CreateVisitor(scratchScope);
Result := evaluator.Execute(boundSubAst);
end;
Result :=
TMacroExpander.ExpandMacros(
FMacroRegistry,
FRootScope,
Node,
function(const Scope: IExecutionScope): IEvaluatorVisitor begin Result := cExecutionStrategy.CreateVisitor(Scope); end
macroEvaluator // Injected single dependency
);
end;