Macro expander integrated in binder

This commit is contained in:
Michael Schimmel
2025-10-05 02:45:13 +02:00
parent 54bf350c70
commit 0d73a13051
6 changed files with 373 additions and 218 deletions
+52 -8
View File
@@ -45,7 +45,7 @@ type
property Parent: IExecutionScope read GetParent;
end;
// Describes the layout of a scope: variable names and their slot indices.
// Describes the layout of a scope: variable names, their slot indices and macros.
// This is generated by the binder and used to create TExecutionScope instances at runtime.
IScopeDescriptor = interface
{$region 'private'}
@@ -55,7 +55,9 @@ type
{$endregion}
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
function Define(const Name: string): Integer;
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
function FindSymbol(const Name: string): TResolvedAddress;
function FindMacro(const Name: string): IMacroDefinitionNode;
property Parent: IScopeDescriptor read GetParent;
property SlotCount: Integer read GetSlotCount;
property Symbols: TDictionary<string, Integer> read GetSymbols;
@@ -77,7 +79,8 @@ implementation
uses
System.Generics.Defaults,
System.SyncObjs;
System.SyncObjs,
Myc.Ast;
type
TExecutionScope = class(TInterfacedObject, IExecutionScope)
@@ -132,6 +135,7 @@ type
private
FParent: IScopeDescriptor;
FSymbols: TDictionary<string, Integer>;
FMacros: TDictionary<string, IMacroDefinitionNode>;
function GetParent: IScopeDescriptor;
function GetSlotCount: Integer;
function GetSymbols: TDictionary<string, Integer>;
@@ -140,7 +144,9 @@ type
destructor Destroy; override;
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
function Define(const Name: string): Integer;
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
function FindSymbol(const Name: string): TResolvedAddress;
function FindMacro(const Name: string): IMacroDefinitionNode;
function CreateScope(const Parent: IExecutionScope): IExecutionScope;
procedure PopulateFromScope(Scope: TExecutionScope);
property Symbols: TDictionary<string, Integer> read FSymbols;
@@ -447,16 +453,18 @@ begin
end;
{ TScopeDescriptor }
// ... (Implementation unchanged and correct) ...
constructor TScopeDescriptor.Create(const AParent: IScopeDescriptor);
begin
inherited Create;
FParent := AParent;
FSymbols := TDictionary<string, Integer>.Create;
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
end;
destructor TScopeDescriptor.Destroy;
begin
FMacros.Free;
FSymbols.Free;
inherited;
end;
@@ -484,22 +492,42 @@ begin
FSymbols.Add(Name, Result);
end;
function TScopeDescriptor.FindSymbol(const Name: string): TResolvedAddress;
procedure TScopeDescriptor.DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
begin
FMacros.AddOrSetValue(Name, Node);
end;
function TScopeDescriptor.FindMacro(const Name: string): IMacroDefinitionNode;
var
currentDescriptor: TScopeDescriptor;
begin
// Find a macro by searching up the parent scope chain.
Result := nil;
currentDescriptor := Self;
while Assigned(currentDescriptor) do
begin
if currentDescriptor.FMacros.TryGetValue(Name, Result) then
exit;
currentDescriptor := currentDescriptor.FParent as TScopeDescriptor;
end;
end;
function TScopeDescriptor.FindSymbol(const Name: string): TResolvedAddress;
var
currentDescriptor: IScopeDescriptor;
begin
Result.Kind := akUnresolved;
Result.ScopeDepth := 0;
currentDescriptor := Self;
while currentDescriptor <> nil do
while Assigned(currentDescriptor) do
begin
if currentDescriptor.FSymbols.TryGetValue(Name, Result.SlotIndex) then
if currentDescriptor.Symbols.TryGetValue(Name, Result.SlotIndex) then
begin
Result.Kind := akLocalOrParent;
exit;
end;
inc(Result.ScopeDepth);
currentDescriptor := currentDescriptor.FParent as TScopeDescriptor;
currentDescriptor := currentDescriptor.Parent;
end;
end;
@@ -519,15 +547,31 @@ begin
end;
procedure TScopeDescriptor.PopulateFromScope(Scope: TExecutionScope);
var
val: TDataValue;
begin
// Recreate descriptor by iterating all defined symbols in the runtime scope.
for var pair in Scope.NameToIndex do
begin
var name := Scope.NameStrings[pair.Key];
var slotIndex := pair.Value;
// Add to variable symbol table.
if not FSymbols.ContainsKey(name) then
FSymbols.Add(name, pair.Value);
FSymbols.Add(name, slotIndex);
// Check if the symbol is also a macro and add it to the macro table.
val := Scope.FValues[slotIndex].Value;
if (val.Kind = vkInterface) and (val.AsIntf<IAstNode> is TMacroDefinitionNode) then
begin
if not FMacros.ContainsKey(name) then
FMacros.Add(name, val.AsIntf<IMacroDefinitionNode>);
end;
end;
end;
{ TScope }
class function TScope.CreateDescriptor(const Parent: IScopeDescriptor): IScopeDescriptor;
begin
Result := TScopeDescriptor.Create(Parent);