Resolved dependency between AST nodes and scope
This commit is contained in:
@@ -214,11 +214,10 @@ end;
|
||||
|
||||
function TForm1.CompileAst(const ANode: IAstNode; const AParentScope: IExecutionScope; out ADescriptor: IScopeDescriptor): IAstNode;
|
||||
var
|
||||
macroDescriptor: IScopeDescriptor;
|
||||
expandedAst, boundAst, typedAst, loweredAst: IAstNode;
|
||||
begin
|
||||
// Step 1: Expand macros (Phase 1)
|
||||
expandedAst := TMacroExpander.ExpandMacros(AParentScope, ANode, macroDescriptor, CreateEvaluator);
|
||||
expandedAst := TMacroExpander.ExpandMacros(AParentScope, ANode, CreateEvaluator);
|
||||
|
||||
// Step 2: Bind names and addresses (Phase 2)
|
||||
boundAst := TAstBinder.Bind(AParentScope, expandedAst, ADescriptor);
|
||||
|
||||
@@ -6,10 +6,11 @@ uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Data.Value,
|
||||
Myc.Data.Scalar,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast;
|
||||
|
||||
type
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//==================================================================================================
|
||||
//== FULL UNIT START: Myc.Ast.MacroExpander (from Myc.Ast.MacroExpander.pas)
|
||||
//==================================================================================================
|
||||
unit Myc.Ast.MacroExpander;
|
||||
|
||||
interface
|
||||
@@ -19,7 +16,8 @@ uses
|
||||
|
||||
type
|
||||
IAstMacroExpander = interface(IAstVisitor)
|
||||
function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
// Signatur geändert: Descriptor wird nicht mehr zurückgegeben
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
end;
|
||||
|
||||
// Callback type for compile-time evaluation of Unquote expressions
|
||||
@@ -48,10 +46,29 @@ 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 Name: string; const Node: IMacroDefinitionNode);
|
||||
function Find(const Name: string): IMacroDefinitionNode;
|
||||
end;
|
||||
|
||||
private
|
||||
FInitialScope: IExecutionScope;
|
||||
FCurrentDescriptor: IScopeDescriptor;
|
||||
|
||||
// Ersetzt FCurrentDescriptor
|
||||
FCurrentMacroRegistry: TMacroRegistry;
|
||||
|
||||
FEvaluatorFactory: TEvaluatorFactory;
|
||||
|
||||
procedure EnterMacroScope;
|
||||
procedure ExitMacroScope;
|
||||
|
||||
protected
|
||||
// Finds macro definitions
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode; override;
|
||||
@@ -60,14 +77,21 @@ type
|
||||
function VisitQuasiquote(const Node: IQuasiquoteNode): IAstNode; override;
|
||||
function VisitUnquote(const Node: IUnquoteNode): IAstNode; override;
|
||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override;
|
||||
|
||||
// NEU: Überschrieben für lexikalisches Makro-Scoping
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
|
||||
|
||||
public
|
||||
constructor Create(const AInitialScope: IExecutionScope; const AEvaluatorFactory: TEvaluatorFactory);
|
||||
function Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
destructor Destroy; override;
|
||||
|
||||
// Signatur geändert
|
||||
function Execute(const RootNode: IAstNode): IAstNode;
|
||||
|
||||
class function ExpandMacros(
|
||||
const InitialScope: IExecutionScope;
|
||||
const RootNode: IAstNode;
|
||||
out Descriptor: IScopeDescriptor;
|
||||
const EvaluatorFactory: TEvaluatorFactory
|
||||
): IAstNode; static;
|
||||
end;
|
||||
@@ -80,6 +104,40 @@ 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 Name: string; const Node: IMacroDefinitionNode);
|
||||
begin
|
||||
FMacros.AddOrSetValue(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);
|
||||
@@ -232,22 +290,44 @@ begin
|
||||
Assert(Assigned(AEvaluatorFactory));
|
||||
FInitialScope := AInitialScope;
|
||||
FEvaluatorFactory := AEvaluatorFactory;
|
||||
// Create the top-level descriptor for macros
|
||||
FCurrentDescriptor := AInitialScope.CreateDescriptor;
|
||||
|
||||
// Erzeugt die Root-Registry für Makros
|
||||
FCurrentMacroRegistry := TMacroRegistry.Create(nil);
|
||||
end;
|
||||
|
||||
destructor TMacroExpander.Destroy;
|
||||
begin
|
||||
FCurrentMacroRegistry.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TMacroExpander.EnterMacroScope;
|
||||
begin
|
||||
// Erstellt eine neue Registry mit der aktuellen als Parent
|
||||
FCurrentMacroRegistry := TMacroRegistry.Create(FCurrentMacroRegistry);
|
||||
end;
|
||||
|
||||
procedure TMacroExpander.ExitMacroScope;
|
||||
var
|
||||
oldRegistry: TMacroRegistry;
|
||||
begin
|
||||
oldRegistry := FCurrentMacroRegistry;
|
||||
FCurrentMacroRegistry := oldRegistry.FParent;
|
||||
oldRegistry.Free;
|
||||
end;
|
||||
|
||||
class function TMacroExpander.ExpandMacros(
|
||||
const InitialScope: IExecutionScope;
|
||||
const RootNode: IAstNode;
|
||||
out Descriptor: IScopeDescriptor;
|
||||
const EvaluatorFactory: TEvaluatorFactory
|
||||
): IAstNode;
|
||||
begin
|
||||
// IAstMacroExpander.Execute gibt keinen Descriptor mehr zurück
|
||||
var expander := TMacroExpander.Create(InitialScope, EvaluatorFactory) as IAstMacroExpander;
|
||||
Result := expander.Execute(RootNode, Descriptor);
|
||||
Result := expander.Execute(RootNode);
|
||||
end;
|
||||
|
||||
function TMacroExpander.Execute(const RootNode: IAstNode; out Descriptor: IScopeDescriptor): IAstNode;
|
||||
function TMacroExpander.Execute(const RootNode: IAstNode): IAstNode;
|
||||
begin
|
||||
// This executes the transformation (Accept)
|
||||
Result := Accept(RootNode); // Calls the IAstNode-returning helper
|
||||
@@ -255,13 +335,35 @@ begin
|
||||
if not Assigned(Result) then
|
||||
Result := TAst.Block([]); // e.g. if root was (defmacro ...)
|
||||
|
||||
Descriptor := FCurrentDescriptor;
|
||||
// Descriptor := FCurrentDescriptor; // Entfernt
|
||||
end;
|
||||
|
||||
function TMacroExpander.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
|
||||
begin
|
||||
// Ein 'do'-Block eröffnet einen neuen Scope für Makros
|
||||
EnterMacroScope;
|
||||
try
|
||||
Result := inherited VisitBlockExpression(Node);
|
||||
finally
|
||||
ExitMacroScope;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMacroExpander.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
|
||||
begin
|
||||
// Eine 'fn' eröffnet einen neuen Scope für Makros
|
||||
EnterMacroScope;
|
||||
try
|
||||
Result := inherited VisitLambdaExpression(Node);
|
||||
finally
|
||||
ExitMacroScope;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMacroExpander.VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode;
|
||||
begin
|
||||
// Register the macro in the current descriptor
|
||||
FCurrentDescriptor.DefineMacro(Node.Name.Name, Node);
|
||||
// Register the macro in the *current* macro registry
|
||||
FCurrentMacroRegistry.Define(Node.Name.Name, Node);
|
||||
|
||||
// Keep the node in the AST (for the visualizer).
|
||||
Result := Node;
|
||||
@@ -279,8 +381,8 @@ begin
|
||||
|
||||
calleeIdentifier := Node.Callee.AsIdentifier;
|
||||
|
||||
// Check if this identifier is a macro
|
||||
macroDef := FCurrentDescriptor.FindMacro(calleeIdentifier.Name);
|
||||
// Check if this identifier is a macro in the current registry
|
||||
macroDef := FCurrentMacroRegistry.Find(calleeIdentifier.Name);
|
||||
if macroDef = nil then
|
||||
exit(inherited VisitFunctionCall(Node)); // Not a macro, let transformer continue
|
||||
|
||||
@@ -309,7 +411,7 @@ begin
|
||||
boundSubAst: IAstNode;
|
||||
begin
|
||||
// This is the compile-time evaluation (Binder + Evaluator)
|
||||
// [FIX] It must run in the 'expansionScope' which contains the parameters.
|
||||
// Es wird der 'expansionScope' verwendet, der die AST-Argumente enthält
|
||||
boundSubAst := TAstBinder.Bind(expansionScope, ANodeToEvaluate, subDescriptor);
|
||||
|
||||
// Create eval scope from the new descriptor, parented to the expansion scope
|
||||
|
||||
@@ -8,6 +8,7 @@ uses
|
||||
Myc.Data.Scalar,
|
||||
Myc.Data.Value,
|
||||
Myc.Data.Keyword,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Types;
|
||||
|
||||
type
|
||||
@@ -78,19 +79,6 @@ type
|
||||
|
||||
// --- Concrete Type Definitions ---
|
||||
|
||||
// Defines how an identifier's address was resolved.
|
||||
TAddressKind = (akUnresolved, akLocalOrParent, akUpvalue);
|
||||
|
||||
TResolvedAddress = record
|
||||
Kind: TAddressKind;
|
||||
ScopeDepth: Integer;
|
||||
SlotIndex: Integer;
|
||||
constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
|
||||
class operator Initialize(out Dest: TResolvedAddress);
|
||||
public
|
||||
class operator Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
||||
end;
|
||||
|
||||
// A single field in a record literal
|
||||
TRecordFieldLiteral = record
|
||||
Key: IKeywordNode;
|
||||
@@ -397,6 +385,9 @@ type
|
||||
function Execute(const RootNode: IAstNode): TDataValue;
|
||||
end;
|
||||
|
||||
// A factory for creating visitors, primarily used by the debugger subsystem.
|
||||
TEvaluatorFactory = reference to function(const Scope: IExecutionScope): IEvaluatorVisitor;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@@ -413,27 +404,6 @@ begin
|
||||
Result := Result.Substring(2);
|
||||
end;
|
||||
|
||||
{ TResolvedAddress }
|
||||
|
||||
constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
|
||||
begin
|
||||
Kind := AKind;
|
||||
ScopeDepth := AScopeDepth;
|
||||
SlotIndex := ASlotIndex;
|
||||
end;
|
||||
|
||||
class operator TResolvedAddress.Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
||||
begin
|
||||
Result := (A.Kind = B.Kind) and (A.ScopeDepth = B.ScopeDepth) and (A.SlotIndex = B.SlotIndex);
|
||||
end;
|
||||
|
||||
class operator TResolvedAddress.Initialize(out Dest: TResolvedAddress);
|
||||
begin
|
||||
Dest.Kind := akUnresolved;
|
||||
Dest.ScopeDepth := -1;
|
||||
Dest.SlotIndex := -1;
|
||||
end;
|
||||
|
||||
{ TRecordFieldLiteral }
|
||||
|
||||
constructor TRecordFieldLiteral.Create(const AKey: IKeywordNode; const AValue: IAstNode);
|
||||
|
||||
+43
-45
@@ -7,13 +7,25 @@ uses
|
||||
System.Generics.Collections,
|
||||
System.Classes,
|
||||
Myc.Data.Value,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Types;
|
||||
|
||||
type
|
||||
IExecutionScope = interface;
|
||||
IScopeDescriptor = interface;
|
||||
|
||||
// Defines how an identifier's address was resolved.
|
||||
TAddressKind = (akUnresolved, akLocalOrParent, akUpvalue);
|
||||
|
||||
TResolvedAddress = record
|
||||
Kind: TAddressKind;
|
||||
ScopeDepth: Integer;
|
||||
SlotIndex: Integer;
|
||||
constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
|
||||
class operator Initialize(out Dest: TResolvedAddress);
|
||||
public
|
||||
class operator Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
||||
end;
|
||||
|
||||
// A resolved symbol, containing its runtime address and static type.
|
||||
TResolvedSymbol = record
|
||||
Address: TResolvedAddress;
|
||||
@@ -68,18 +80,15 @@ type
|
||||
function Define(const Name: string; const AType: IStaticType = nil): Integer;
|
||||
// Updates the type of an already defined symbol (e.g., for lambda self-reference).
|
||||
procedure UpdateType(SlotIndex: Integer; const AType: IStaticType);
|
||||
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
|
||||
|
||||
// Finds a symbol, returns its address and type.
|
||||
function FindSymbol(const Name: string): TResolvedSymbol;
|
||||
function FindMacro(const Name: string): IMacroDefinitionNode;
|
||||
|
||||
property Parent: IScopeDescriptor read GetParent;
|
||||
property SlotCount: Integer read GetSlotCount;
|
||||
property Symbols: TDictionary<string, Integer> read GetSymbols;
|
||||
end;
|
||||
|
||||
// A factory for creating visitors, primarily used by the debugger subsystem.
|
||||
TEvaluatorFactory = reference to function(const Scope: IExecutionScope): IEvaluatorVisitor;
|
||||
|
||||
TScope = record
|
||||
class function CreateScope(
|
||||
const Parent: IExecutionScope;
|
||||
@@ -93,8 +102,7 @@ implementation
|
||||
|
||||
uses
|
||||
System.Generics.Defaults,
|
||||
System.SyncObjs,
|
||||
Myc.Ast;
|
||||
System.SyncObjs;
|
||||
|
||||
type
|
||||
TExecutionScope = class(TInterfacedObject, IExecutionScope)
|
||||
@@ -151,7 +159,7 @@ type
|
||||
private
|
||||
FParent: IScopeDescriptor;
|
||||
FSymbols: TDictionary<string, Integer>;
|
||||
FMacros: TDictionary<string, IMacroDefinitionNode>;
|
||||
// FMacros: TDictionary<string, IMacroDefinitionNode>; // Entfernt
|
||||
FSlotTypes: TArray<IStaticType>; // Stores types by SlotIndex
|
||||
function GetParent: IScopeDescriptor;
|
||||
function GetSlotCount: Integer;
|
||||
@@ -163,14 +171,35 @@ type
|
||||
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
|
||||
function Define(const Name: string; const AType: IStaticType): Integer;
|
||||
procedure UpdateType(SlotIndex: Integer; const AType: IStaticType = nil);
|
||||
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
|
||||
// procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode); // Entfernt
|
||||
function FindSymbol(const Name: string): TResolvedSymbol;
|
||||
function FindMacro(const Name: string): IMacroDefinitionNode;
|
||||
// function FindMacro(const Name: string): IMacroDefinitionNode; // Entfernt
|
||||
function CreateScope(const Parent: IExecutionScope): IExecutionScope;
|
||||
procedure PopulateFromScope(Scope: TExecutionScope);
|
||||
property Symbols: TDictionary<string, Integer> read FSymbols;
|
||||
end;
|
||||
|
||||
{ TResolvedAddress }
|
||||
|
||||
constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer);
|
||||
begin
|
||||
Kind := AKind;
|
||||
ScopeDepth := AScopeDepth;
|
||||
SlotIndex := ASlotIndex;
|
||||
end;
|
||||
|
||||
class operator TResolvedAddress.Equal(const A: TResolvedAddress; B: TResolvedAddress): Boolean;
|
||||
begin
|
||||
Result := (A.Kind = B.Kind) and (A.ScopeDepth = B.ScopeDepth) and (A.SlotIndex = B.SlotIndex);
|
||||
end;
|
||||
|
||||
class operator TResolvedAddress.Initialize(out Dest: TResolvedAddress);
|
||||
begin
|
||||
Dest.Kind := akUnresolved;
|
||||
Dest.ScopeDepth := -1;
|
||||
Dest.SlotIndex := -1;
|
||||
end;
|
||||
|
||||
{ TResolvedSymbol }
|
||||
|
||||
constructor TResolvedSymbol.Create(const AAddress: TResolvedAddress; const AStaticType: IStaticType);
|
||||
@@ -499,14 +528,14 @@ begin
|
||||
inherited Create;
|
||||
FParent := AParent;
|
||||
FSymbols := TDictionary<string, Integer>.Create;
|
||||
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
|
||||
// FMacros := TDictionary<string, IMacroDefinitionNode>.Create; // Entfernt
|
||||
FSlotTypes := [];
|
||||
end;
|
||||
|
||||
destructor TScopeDescriptor.Destroy;
|
||||
begin
|
||||
FSlotTypes := nil;
|
||||
FMacros.Free;
|
||||
// FMacros.Free; // Entfernt
|
||||
FSymbols.Free;
|
||||
inherited;
|
||||
end;
|
||||
@@ -547,26 +576,6 @@ begin
|
||||
else TTypes.Unknown;
|
||||
end;
|
||||
|
||||
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): TResolvedSymbol;
|
||||
var
|
||||
currentDescriptor: IScopeDescriptor;
|
||||
@@ -633,18 +642,7 @@ begin
|
||||
// We cannot recover the static type from the runtime scope.
|
||||
// FSlotTypes[slotIndex] remains TTypes.Unknown.
|
||||
|
||||
// Check if the symbol is also a macro and add it to the macro table.
|
||||
|
||||
var val := Scope.ValuesArray[slotIndex].GetContent;
|
||||
if val.Kind = vkInterface then
|
||||
begin
|
||||
var node := val.AsIntf<IAstNode>;
|
||||
if (node <> nil) and (node.Kind = akMacroDefinition) then
|
||||
begin
|
||||
if not FMacros.ContainsKey(name) then
|
||||
FMacros.Add(name, node.AsMacroDefinition);
|
||||
end;
|
||||
end;
|
||||
// Makro-Logik hier entfernt
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user