Ast environments

This commit is contained in:
Michael Schimmel
2025-11-07 19:40:35 +01:00
parent 4ccf3bb5fd
commit c0f871ce02
12 changed files with 722 additions and 364 deletions
+36 -87
View File
@@ -12,11 +12,12 @@ uses
Myc.Ast.Visitor,
Myc.Ast.Scope,
Myc.Ast.Types,
Myc.Ast;
Myc.Ast,
Myc.Ast.Environment; // Added for IMacroRegistry
type
IAstMacroExpander = interface(IAstVisitor)
// Signatur geändert: Descriptor wird nicht mehr zurückgegeben
// Signatur geaendert: Descriptor wird nicht mehr zurueckgegeben
function Execute(const RootNode: IAstNode): IAstNode;
end;
@@ -46,28 +47,10 @@ type
// This transformer traverses the entire AST *before* the binder,
// to find and expand macros.
TMacroExpander = class(TAstTransformer, IAstMacroExpander)
type
TMacroRegistry = class
private
FParent: TMacroRegistry;
FMacros: TDictionary<string, IMacroDefinitionNode>;
public
constructor Create(AParent: TMacroRegistry);
destructor Destroy; override;
procedure Define(const Node: IMacroDefinitionNode);
function Find(const Name: string): IMacroDefinitionNode;
end;
strict private
class var
FGlobalMacroRegistry: TMacroRegistry;
class constructor CreateClass;
class destructor DestroyClass;
private
FInitialScope: IExecutionScope;
FCurrentMacroRegistry: TMacroRegistry;
FCurrentMacroRegistry: IMacroRegistry; // Changed from TMacroRegistry
FEvaluatorFactory: TEvaluatorFactory;
@@ -87,18 +70,23 @@ type
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
public
constructor Create(const AInitialScope: IExecutionScope; const AEvaluatorFactory: TEvaluatorFactory);
destructor Destroy; override;
// Updated Constructor
constructor Create(
const ARootRegistry: IMacroRegistry;
const AInitialScope: IExecutionScope;
const AEvaluatorFactory: TEvaluatorFactory
);
destructor Destroy; override; // Modified
function Execute(const RootNode: IAstNode): IAstNode;
// Updated static helper
class function ExpandMacros(
const InitialScope: IExecutionScope;
const ARootRegistry: IMacroRegistry; // Added
const AInitialScope: IExecutionScope;
const RootNode: IAstNode;
const EvaluatorFactory: TEvaluatorFactory
): IAstNode; static;
class property GlobalMacroRegistry: TMacroRegistry read FGlobalMacroRegistry;
end;
implementation
@@ -109,40 +97,6 @@ uses
Myc.Ast.Evaluator, // Required for TEvaluatorVisitor.Execute
Myc.Data.Keyword;
{ TMacroRegistry }
constructor TMacroExpander.TMacroRegistry.Create(AParent: TMacroRegistry);
begin
inherited Create;
FParent := AParent;
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
end;
destructor TMacroExpander.TMacroRegistry.Destroy;
begin
FMacros.Free;
inherited Destroy;
end;
procedure TMacroExpander.TMacroRegistry.Define(const Node: IMacroDefinitionNode);
begin
FMacros.AddOrSetValue(Node.Name.Name, Node);
end;
function TMacroExpander.TMacroRegistry.Find(const Name: string): IMacroDefinitionNode;
var
current: TMacroRegistry;
begin
current := Self;
while Assigned(current) do
begin
if current.FMacros.TryGetValue(Name, Result) then
exit;
current := current.FParent;
end;
Result := nil;
end;
{ TExpansionVisitor }
constructor TExpansionVisitor.Create(const AMacroScope: IExecutionScope; const AEvaluate: TEvaluateProc);
@@ -288,57 +242,52 @@ end;
{ TMacroExpander }
constructor TMacroExpander.Create(const AInitialScope: IExecutionScope; const AEvaluatorFactory: TEvaluatorFactory);
constructor TMacroExpander.Create(
const ARootRegistry: IMacroRegistry;
const AInitialScope: IExecutionScope;
const AEvaluatorFactory: TEvaluatorFactory
);
begin
inherited Create;
Assert(Assigned(ARootRegistry));
Assert(Assigned(AInitialScope));
Assert(Assigned(AEvaluatorFactory));
FInitialScope := AInitialScope;
FEvaluatorFactory := AEvaluatorFactory;
// Erzeugt die Root-Registry für Makros
FCurrentMacroRegistry := TMacroRegistry.Create(FGlobalMacroRegistry);
end;
class constructor TMacroExpander.CreateClass;
begin
FGlobalMacroRegistry := TMacroRegistry.Create(nil);
// Creates the root registry for this specific compilation run,
// parented to the global registry from the environment.
FCurrentMacroRegistry := ARootRegistry.CreateChildRegistry;
end;
destructor TMacroExpander.Destroy;
begin
FCurrentMacroRegistry.Free;
// FCurrentMacroRegistry is an interface, managed by ARC
inherited Destroy;
end;
class destructor TMacroExpander.DestroyClass;
begin
FGlobalMacroRegistry.Free;
end;
procedure TMacroExpander.EnterMacroScope;
begin
// Erstellt eine neue Registry mit der aktuellen als Parent
FCurrentMacroRegistry := TMacroRegistry.Create(FCurrentMacroRegistry);
// Creates a new registry with the current as Parent
FCurrentMacroRegistry := FCurrentMacroRegistry.CreateChildRegistry;
end;
procedure TMacroExpander.ExitMacroScope;
var
oldRegistry: TMacroRegistry;
begin
oldRegistry := FCurrentMacroRegistry;
FCurrentMacroRegistry := oldRegistry.FParent;
oldRegistry.Free;
// Revert to parent registry. ARC will free the old child.
FCurrentMacroRegistry := FCurrentMacroRegistry.Parent;
end;
class function TMacroExpander.ExpandMacros(
const InitialScope: IExecutionScope;
const ARootRegistry: IMacroRegistry;
const AInitialScope: IExecutionScope;
const RootNode: IAstNode;
const EvaluatorFactory: TEvaluatorFactory
): IAstNode;
begin
// IAstMacroExpander.Execute gibt keinen Descriptor mehr zurück
var expander := TMacroExpander.Create(InitialScope, EvaluatorFactory) as IAstMacroExpander;
// IAstMacroExpander.Execute gibt keinen Descriptor mehr zurueck
var expander := TMacroExpander.Create(ARootRegistry, AInitialScope, EvaluatorFactory) as IAstMacroExpander;
Result := expander.Execute(RootNode);
end;
@@ -400,7 +349,7 @@ begin
// --- It is a macro, expand it ---
// 1. Create the temporary scope for the macro parameters
// It must be parented to the *initial* scope to find other macros/globals.
// It must be parented to the *initial* scope to find other globals.
var expansionScope := TAst.CreateScope(FInitialScope);
var params := macroDef.Parameters;
if Length(Node.Arguments) <> Length(params) then
@@ -422,8 +371,8 @@ begin
boundSubAst: IAstNode;
begin
// This is the compile-time evaluation (Binder + Evaluator)
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthält
boundSubAst := TAstBinder.Bind(expansionScope, ANodeToEvaluate, subDescriptor);
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthaelt
boundSubAst := TAstBinder.Bind(expansionScope.CreateDescriptor, ANodeToEvaluate, subDescriptor);
// Create eval scope from the new descriptor, parented to the expansion scope
evalScope := subDescriptor.CreateScope(expansionScope);