Macro expander integrated in binder
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user