Binder refactoring, Monster refactoring
This commit is contained in:
@@ -9,7 +9,8 @@ uses
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Visitor,
|
||||
Myc.Ast.Scope,
|
||||
Myc.Data.Value;
|
||||
Myc.Data.Value,
|
||||
Myc.Ast;
|
||||
|
||||
type
|
||||
// This visitor analyzes the AST to find all variables that need to be "lifted" or "boxed"
|
||||
@@ -17,23 +18,28 @@ type
|
||||
TUpvalueAnalyzer = class(TAstTransformer)
|
||||
private
|
||||
FBoxedDeclarations: THashSet<IVariableDeclarationNode>;
|
||||
FCurrentScope: IScopeDescriptor;
|
||||
FCurrentDescriptor: IScopeDescriptor;
|
||||
FDeclarationMap: TDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>;
|
||||
procedure MarkDeclarationForBoxing(const AName: string);
|
||||
protected
|
||||
// Overridden Visit methods to perform analysis during traversal.
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override;
|
||||
public
|
||||
constructor Create(const AParent: IScopeDescriptor);
|
||||
destructor Destroy; override;
|
||||
|
||||
// Added Execute method
|
||||
function Execute(const ARootNode: IAstNode): IAstNode;
|
||||
|
||||
class function Analyze(const ARootNode: IAstNode; const AParent: IScopeDescriptor): THashSet<IVariableDeclarationNode>; static;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.Generics.Defaults,
|
||||
Myc.Ast.Types;
|
||||
|
||||
{ TUpvalueAnalyzer }
|
||||
@@ -42,22 +48,28 @@ constructor TUpvalueAnalyzer.Create(const AParent: IScopeDescriptor);
|
||||
begin
|
||||
inherited Create;
|
||||
FBoxedDeclarations := THashSet<IVariableDeclarationNode>.Create;
|
||||
FDeclarationMap := TDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>.Create;
|
||||
FCurrentScope := TScope.CreateDescriptor(AParent);
|
||||
FDeclarationMap :=
|
||||
TObjectDictionary<IScopeDescriptor, TDictionary<string, IVariableDeclarationNode>>
|
||||
.Create([doOwnsValues], TEqualityComparer<IScopeDescriptor>.Default);
|
||||
FCurrentDescriptor := TScope.CreateDescriptor(AParent);
|
||||
end;
|
||||
|
||||
destructor TUpvalueAnalyzer.Destroy;
|
||||
begin
|
||||
for var dict in FDeclarationMap.Values do
|
||||
dict.Free;
|
||||
FDeclarationMap.Free;
|
||||
FBoxedDeclarations.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.Execute(const ARootNode: IAstNode): IAstNode;
|
||||
begin
|
||||
// Accept will call the Visit... methods and traverse the tree
|
||||
Result := Accept(ARootNode);
|
||||
end;
|
||||
|
||||
class function TUpvalueAnalyzer.Analyze(const ARootNode: IAstNode; const AParent: IScopeDescriptor): THashSet<IVariableDeclarationNode>;
|
||||
var
|
||||
analyzer: TUpvalueAnalyzer;
|
||||
analyzer: TUpvalueAnalyzer; // Changed to concrete type
|
||||
begin
|
||||
if not Assigned(ARootNode) then
|
||||
exit(THashSet<IVariableDeclarationNode>.Create);
|
||||
@@ -78,12 +90,12 @@ var
|
||||
declarationScope: IScopeDescriptor;
|
||||
i: Integer;
|
||||
begin
|
||||
symbol := FCurrentScope.FindSymbol(AName);
|
||||
symbol := FCurrentDescriptor.FindSymbol(AName);
|
||||
if symbol.Address.Kind <> akLocalOrParent then
|
||||
exit;
|
||||
|
||||
// Walk up the scope chain to find the scope where the variable was declared.
|
||||
declarationScope := FCurrentScope;
|
||||
declarationScope := FCurrentDescriptor;
|
||||
for i := 1 to symbol.Address.ScopeDepth do
|
||||
begin
|
||||
if not Assigned(declarationScope.Parent) then
|
||||
@@ -101,13 +113,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
function TUpvalueAnalyzer.VisitIdentifier(const Node: IIdentifierNode): IAstNode;
|
||||
var
|
||||
symbol: TResolvedSymbol;
|
||||
begin
|
||||
if Assigned(FCurrentScope) then
|
||||
if Assigned(FCurrentDescriptor) then
|
||||
begin
|
||||
symbol := FCurrentScope.FindSymbol(Node.Name);
|
||||
symbol := FCurrentDescriptor.FindSymbol(Node.Name);
|
||||
|
||||
if (symbol.Address.Kind = akLocalOrParent) and (symbol.Address.ScopeDepth > 0) then
|
||||
begin
|
||||
@@ -116,54 +128,62 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// As a traverser, return the original node wrapped in a TDataValue.
|
||||
Result := TDataValue.FromIntf<IIdentifierNode>(Node);
|
||||
// This is a leaf node, do not call inherited.
|
||||
Result := Node;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
function TUpvalueAnalyzer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
|
||||
var
|
||||
N: TLambdaExpressionNode;
|
||||
begin
|
||||
N := (Node as TLambdaExpressionNode);
|
||||
|
||||
// A lambda creates a new lexical scope, inheriting from the current one.
|
||||
FCurrentScope := TScope.CreateDescriptor(FCurrentScope);
|
||||
FCurrentDescriptor := TScope.CreateDescriptor(FCurrentDescriptor);
|
||||
try
|
||||
// Define the lambda's parameters within its new scope.
|
||||
// We use TTypes.Unknown as type inference hasn't run yet.
|
||||
for var param in Node.Parameters do
|
||||
FCurrentScope.Define(param.Name, TTypes.Unknown);
|
||||
for var param in N.Parameters do
|
||||
FCurrentDescriptor.Define(Accept(param).AsIdentifier.Name, TTypes.Unknown);
|
||||
|
||||
// Traverse the lambda body within the new scope context.
|
||||
Node.Body.Accept(Self);
|
||||
N.Body := Accept(N.Body); // Manual traversal
|
||||
|
||||
// We do not transform, just analyze. Return the original node wrapped.
|
||||
Result := TDataValue.FromIntf<ILambdaExpressionNode>(Node);
|
||||
Result := N;
|
||||
finally
|
||||
// Restore the parent scope after leaving the lambda.
|
||||
FCurrentScope := FCurrentScope.Parent;
|
||||
FCurrentDescriptor := FCurrentDescriptor.Parent;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TUpvalueAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
function TUpvalueAnalyzer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode;
|
||||
var
|
||||
scopeDeclarations: TDictionary<string, IVariableDeclarationNode>;
|
||||
N: TVariableDeclarationNode;
|
||||
begin
|
||||
N := (Node as TVariableDeclarationNode);
|
||||
|
||||
// Traverse the initializer first. It's evaluated in the current scope
|
||||
// before the new variable is defined.
|
||||
if Assigned(Node.Initializer) then
|
||||
Node.Initializer.Accept(Self);
|
||||
if Assigned(N.Initializer) then
|
||||
N.Initializer := Accept(N.Initializer);
|
||||
|
||||
// Traverse the identifier
|
||||
Accept(N.Identifier);
|
||||
|
||||
// After processing the initializer, define the variable in the current scope.
|
||||
// We use TTypes.Unknown as type inference hasn't run yet.
|
||||
FCurrentScope.Define(Node.Identifier.Name, TTypes.Unknown);
|
||||
FCurrentDescriptor.Define(N.Identifier.Name, TTypes.Unknown);
|
||||
|
||||
// Map this declaration node to its scope and name for later lookup.
|
||||
if not FDeclarationMap.TryGetValue(FCurrentScope, scopeDeclarations) then
|
||||
if not FDeclarationMap.TryGetValue(FCurrentDescriptor, scopeDeclarations) then
|
||||
begin
|
||||
scopeDeclarations := TDictionary<string, IVariableDeclarationNode>.Create;
|
||||
FDeclarationMap.Add(FCurrentScope, scopeDeclarations);
|
||||
FDeclarationMap.Add(FCurrentDescriptor, scopeDeclarations);
|
||||
end;
|
||||
scopeDeclarations.Add(Node.Identifier.Name, Node);
|
||||
scopeDeclarations.Add(N.Identifier.Name, N);
|
||||
|
||||
// As a traverser, return the original node wrapped in a TDataValue.
|
||||
Result := TDataValue.FromIntf<IVariableDeclarationNode>(Node);
|
||||
Result := N;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user