Refactoring Binder
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<ProjectVersion>20.3</ProjectVersion>
|
<ProjectVersion>20.3</ProjectVersion>
|
||||||
<FrameworkType>FMX</FrameworkType>
|
<FrameworkType>FMX</FrameworkType>
|
||||||
<Base>True</Base>
|
<Base>True</Base>
|
||||||
<Config Condition="'$(Config)'==''">Release</Config>
|
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||||
<Platform Condition="'$(Platform)'==''">Win64</Platform>
|
<Platform Condition="'$(Platform)'==''">Win64</Platform>
|
||||||
<ProjectName Condition="'$(ProjectName)'==''">ASTPlayground</ProjectName>
|
<ProjectName Condition="'$(ProjectName)'==''">ASTPlayground</ProjectName>
|
||||||
<TargetedPlatforms>2</TargetedPlatforms>
|
<TargetedPlatforms>2</TargetedPlatforms>
|
||||||
|
|||||||
+50
-65
@@ -12,7 +12,7 @@ uses
|
|||||||
Myc.Ast.Scope;
|
Myc.Ast.Scope;
|
||||||
|
|
||||||
type
|
type
|
||||||
TAstBinder = class(TAstTraverser<Boolean>)
|
TAstBinder = class(TAstTraverser)
|
||||||
type
|
type
|
||||||
TUpvalueMapping = class
|
TUpvalueMapping = class
|
||||||
Map: TDictionary<TResolvedAddress, Integer>;
|
Map: TDictionary<TResolvedAddress, Integer>;
|
||||||
@@ -25,12 +25,13 @@ type
|
|||||||
FCurrentDescriptor: IScopeDescriptor;
|
FCurrentDescriptor: IScopeDescriptor;
|
||||||
FUpvalueStack: TStack<TUpvalueMapping>;
|
FUpvalueStack: TStack<TUpvalueMapping>;
|
||||||
FNestedLambdaCount: Integer;
|
FNestedLambdaCount: Integer;
|
||||||
|
FIsTailStack: TStack<Boolean>;
|
||||||
FNextIsTail: Boolean;
|
FNextIsTail: Boolean;
|
||||||
procedure EnterScope;
|
procedure EnterScope;
|
||||||
procedure ExitScope;
|
procedure ExitScope;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
function EnterNode(const Node: IAstNode): Boolean; override;
|
function Accept(const Node: IAstNode): TDataValue; override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(const AInitialScope: IExecutionScope);
|
constructor Create(const AInitialScope: IExecutionScope);
|
||||||
@@ -51,7 +52,6 @@ type
|
|||||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||||
|
|
||||||
property CurrentDescriptor: IScopeDescriptor read FCurrentDescriptor;
|
property CurrentDescriptor: IScopeDescriptor read FCurrentDescriptor;
|
||||||
property NextIsTail: Boolean write FNextIsTail;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -61,12 +61,6 @@ uses
|
|||||||
Myc.Ast;
|
Myc.Ast;
|
||||||
|
|
||||||
type
|
type
|
||||||
TResolvedAddressComparer = class(TEqualityComparer<TResolvedAddress>)
|
|
||||||
public
|
|
||||||
function Equals(const Left, Right: TResolvedAddress): Boolean; override;
|
|
||||||
function GetHashCode(const Value: TResolvedAddress): Integer; override;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TScopeDescriptor = class(TInterfacedObject, IScopeDescriptor)
|
TScopeDescriptor = class(TInterfacedObject, IScopeDescriptor)
|
||||||
private
|
private
|
||||||
FParent: IScopeDescriptor;
|
FParent: IScopeDescriptor;
|
||||||
@@ -84,22 +78,6 @@ type
|
|||||||
property Symbols: TDictionary<string, Integer> read FSymbols;
|
property Symbols: TDictionary<string, Integer> read FSymbols;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TResolvedAddressComparer }
|
|
||||||
|
|
||||||
function TResolvedAddressComparer.Equals(const Left, Right: TResolvedAddress): Boolean;
|
|
||||||
begin
|
|
||||||
Result := (Left.Kind = Right.Kind) and (Left.ScopeDepth = Right.ScopeDepth) and (Left.SlotIndex = Right.SlotIndex);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TResolvedAddressComparer.GetHashCode(const Value: TResolvedAddress): Integer;
|
|
||||||
begin
|
|
||||||
// Simple combining hash function
|
|
||||||
Result := 17;
|
|
||||||
Result := Result * 23 + Ord(Value.Kind);
|
|
||||||
Result := Result * 23 + Value.ScopeDepth;
|
|
||||||
Result := Result * 23 + Value.SlotIndex;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TAstBinder }
|
{ TAstBinder }
|
||||||
|
|
||||||
constructor TAstBinder.Create(const AInitialScope: IExecutionScope);
|
constructor TAstBinder.Create(const AInitialScope: IExecutionScope);
|
||||||
@@ -108,15 +86,31 @@ begin
|
|||||||
FCurrentDescriptor := CreateDescriptor(AInitialScope);
|
FCurrentDescriptor := CreateDescriptor(AInitialScope);
|
||||||
FUpvalueStack := TObjectStack<TUpvalueMapping>.Create(true);
|
FUpvalueStack := TObjectStack<TUpvalueMapping>.Create(true);
|
||||||
FNestedLambdaCount := 0;
|
FNestedLambdaCount := 0;
|
||||||
FNextIsTail := False;
|
FIsTailStack := TStack<Boolean>.Create;
|
||||||
|
// The content of the root node is in a tail position.
|
||||||
|
FNextIsTail := true;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TAstBinder.Destroy;
|
destructor TAstBinder.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FIsTailStack.Free;
|
||||||
FUpvalueStack.Free;
|
FUpvalueStack.Free;
|
||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TAstBinder.Accept(const Node: IAstNode): TDataValue;
|
||||||
|
begin
|
||||||
|
if not Assigned(Node) or Done then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
FIsTailStack.Push(FNextIsTail);
|
||||||
|
try
|
||||||
|
Result := inherited Accept(Node);
|
||||||
|
finally
|
||||||
|
FNextIsTail := FIsTailStack.Pop;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
class function TAstBinder.Bind(const RootNode: IAstNode; const ParentScope: IExecutionScope): IScopeDescriptor;
|
class function TAstBinder.Bind(const RootNode: IAstNode; const ParentScope: IExecutionScope): IScopeDescriptor;
|
||||||
var
|
var
|
||||||
binder: TAstBinder;
|
binder: TAstBinder;
|
||||||
@@ -125,7 +119,7 @@ begin
|
|||||||
try
|
try
|
||||||
binder.EnterScope;
|
binder.EnterScope;
|
||||||
try
|
try
|
||||||
// Start the traversal. The content of the root node is in a tail position.
|
// Start the traversal
|
||||||
binder.Accept(RootNode);
|
binder.Accept(RootNode);
|
||||||
Result := binder.CurrentDescriptor;
|
Result := binder.CurrentDescriptor;
|
||||||
finally
|
finally
|
||||||
@@ -158,12 +152,6 @@ begin
|
|||||||
FCurrentDescriptor := FCurrentDescriptor.Parent;
|
FCurrentDescriptor := FCurrentDescriptor.Parent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstBinder.EnterNode(const Node: IAstNode): Boolean;
|
|
||||||
begin
|
|
||||||
// The context for the current node is whatever the parent Visit... method prepared.
|
|
||||||
Result := FNextIsTail;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TAstBinder.VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
function TAstBinder.VisitAssignment(const Node: IAssignmentNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
FNextIsTail := False;
|
FNextIsTail := False;
|
||||||
@@ -177,27 +165,24 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||||
var
|
|
||||||
i: Integer;
|
|
||||||
begin
|
begin
|
||||||
for i := 0 to Node.Expressions.Count - 2 do
|
FNextIsTail := False;
|
||||||
begin
|
|
||||||
FNextIsTail := False;
|
|
||||||
Accept(Node.Expressions[i]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if Node.Expressions.Count > 0 then
|
var n := Node.Expressions.Count - 1;
|
||||||
|
for var i := 0 to n do
|
||||||
begin
|
begin
|
||||||
// The last expression is in a tail position IF the block itself is.
|
// The last expression is in a tail position IF the block itself is.
|
||||||
FNextIsTail := Data.Peek;
|
if i = n then
|
||||||
Accept(Node.Expressions.Last);
|
FNextIsTail := FIsTailStack.Peek;
|
||||||
|
|
||||||
|
Accept(Node.Expressions[i]);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||||
begin
|
begin
|
||||||
// Annotate this node based on its context, which is on top of the stack.
|
// Annotate this node based on its context, which is on top of the stack.
|
||||||
(Node as TFunctionCallNode).IsTailCall := Data.Peek;
|
(Node as TFunctionCallNode).IsTailCall := FIsTailStack.Peek;
|
||||||
|
|
||||||
// Let the default traverser visit children (callee, args), but ensure
|
// Let the default traverser visit children (callee, args), but ensure
|
||||||
// their context is non-tail.
|
// their context is non-tail.
|
||||||
@@ -250,7 +235,7 @@ begin
|
|||||||
Accept(Node.Condition);
|
Accept(Node.Condition);
|
||||||
|
|
||||||
// The branches are in a tail position if the if-expression itself is.
|
// The branches are in a tail position if the if-expression itself is.
|
||||||
FNextIsTail := Data.Peek;
|
FNextIsTail := FIsTailStack.Peek;
|
||||||
Accept(Node.ThenBranch);
|
Accept(Node.ThenBranch);
|
||||||
if Assigned(Node.ElseBranch) then
|
if Assigned(Node.ElseBranch) then
|
||||||
Accept(Node.ElseBranch);
|
Accept(Node.ElseBranch);
|
||||||
@@ -266,14 +251,13 @@ begin
|
|||||||
try
|
try
|
||||||
EnterScope;
|
EnterScope;
|
||||||
try
|
try
|
||||||
(FCurrentDescriptor as TScopeDescriptor).Define('Self');
|
FCurrentDescriptor.Define('Self');
|
||||||
|
|
||||||
for param in Node.Parameters do
|
for param in Node.Parameters do
|
||||||
(FCurrentDescriptor as TScopeDescriptor).Define(param.Name);
|
FCurrentDescriptor.Define(param.Name);
|
||||||
|
|
||||||
var lastNestedLambdaCount := FNestedLambdaCount;
|
var lastNestedLambdaCount := FNestedLambdaCount;
|
||||||
|
|
||||||
// Manually traverse children since we can't call 'inherited' from the simple traverser.
|
|
||||||
// Parameters are never in a tail position.
|
// Parameters are never in a tail position.
|
||||||
FNextIsTail := False;
|
FNextIsTail := False;
|
||||||
for param in Node.Parameters do
|
for param in Node.Parameters do
|
||||||
@@ -290,22 +274,23 @@ begin
|
|||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
var upvalue := FUpvalueStack.Peek;
|
var upvalue := FUpvalueStack.Peek;
|
||||||
|
try
|
||||||
|
sortedPairs := upvalue.Map.ToArray;
|
||||||
|
TArray.Sort<TPair<TResolvedAddress, Integer>>(
|
||||||
|
sortedPairs,
|
||||||
|
TComparer<TPair<TResolvedAddress, Integer>>.Construct(
|
||||||
|
function(const Left, Right: TPair<TResolvedAddress, Integer>): Integer begin Result := Left.Value - Right.Value; end
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
sortedPairs := upvalue.Map.ToArray;
|
SetLength(sourceAddresses, Length(sortedPairs));
|
||||||
TArray.Sort<TPair<TResolvedAddress, Integer>>(
|
for var i := 0 to High(sortedPairs) do
|
||||||
sortedPairs,
|
sourceAddresses[i] := sortedPairs[i].Key;
|
||||||
TComparer<TPair<TResolvedAddress, Integer>>.Construct(
|
|
||||||
function(const Left, Right: TPair<TResolvedAddress, Integer>): Integer begin Result := Left.Value - Right.Value; end
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
SetLength(sourceAddresses, Length(sortedPairs));
|
(Node as TLambdaExpressionNode).Upvalues := sourceAddresses;
|
||||||
for var i := 0 to High(sortedPairs) do
|
finally
|
||||||
sourceAddresses[i] := sortedPairs[i].Key;
|
FUpvalueStack.Pop;
|
||||||
|
end;
|
||||||
(Node as TLambdaExpressionNode).Upvalues := sourceAddresses;
|
|
||||||
|
|
||||||
FUpvalueStack.Pop;
|
|
||||||
|
|
||||||
inc(FNestedLambdaCount);
|
inc(FNestedLambdaCount);
|
||||||
end;
|
end;
|
||||||
@@ -318,7 +303,7 @@ begin
|
|||||||
Accept(Node.Condition);
|
Accept(Node.Condition);
|
||||||
|
|
||||||
// The branches are in a tail position if the ternary expression itself is.
|
// The branches are in a tail position if the ternary expression itself is.
|
||||||
FNextIsTail := Data.Peek;
|
FNextIsTail := FIsTailStack.Peek;
|
||||||
Accept(Node.ThenBranch);
|
Accept(Node.ThenBranch);
|
||||||
Accept(Node.ElseBranch);
|
Accept(Node.ElseBranch);
|
||||||
end;
|
end;
|
||||||
@@ -338,7 +323,7 @@ begin
|
|||||||
if Assigned(Node.Initializer) then
|
if Assigned(Node.Initializer) then
|
||||||
Accept(Node.Initializer);
|
Accept(Node.Initializer);
|
||||||
|
|
||||||
slotIndex := (FCurrentDescriptor as TScopeDescriptor).Define(Node.Identifier.Name);
|
slotIndex := FCurrentDescriptor.Define(Node.Identifier.Name);
|
||||||
(Node.Identifier as TIdentifierNode).Address := TResolvedAddress.Create(akLocalOrParent, 0, slotIndex);
|
(Node.Identifier as TIdentifierNode).Address := TResolvedAddress.Create(akLocalOrParent, 0, slotIndex);
|
||||||
|
|
||||||
FNextIsTail := False;
|
FNextIsTail := False;
|
||||||
@@ -412,7 +397,7 @@ end;
|
|||||||
constructor TAstBinder.TUpvalueMapping.Create;
|
constructor TAstBinder.TUpvalueMapping.Create;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
Map := TDictionary<TResolvedAddress, Integer>.Create(TResolvedAddressComparer.Default);
|
Map := TDictionary<TResolvedAddress, Integer>.Create;
|
||||||
Nodes := TList<IIdentifierNode>.Create();
|
Nodes := TList<IIdentifierNode>.Create();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user