diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj
index b620b06..91a3108 100644
--- a/ASTPlayground/ASTPlayground.dproj
+++ b/ASTPlayground/ASTPlayground.dproj
@@ -4,7 +4,7 @@
20.3
FMX
True
- Release
+ Debug
Win64
ASTPlayground
2
diff --git a/Src/AST/Myc.Ast.Binding.pas b/Src/AST/Myc.Ast.Binding.pas
index a26ebcd..12da01a 100644
--- a/Src/AST/Myc.Ast.Binding.pas
+++ b/Src/AST/Myc.Ast.Binding.pas
@@ -12,7 +12,7 @@ uses
Myc.Ast.Scope;
type
- TAstBinder = class(TAstTraverser)
+ TAstBinder = class(TAstTraverser)
type
TUpvalueMapping = class
Map: TDictionary;
@@ -25,12 +25,13 @@ type
FCurrentDescriptor: IScopeDescriptor;
FUpvalueStack: TStack;
FNestedLambdaCount: Integer;
+ FIsTailStack: TStack;
FNextIsTail: Boolean;
procedure EnterScope;
procedure ExitScope;
protected
- function EnterNode(const Node: IAstNode): Boolean; override;
+ function Accept(const Node: IAstNode): TDataValue; override;
public
constructor Create(const AInitialScope: IExecutionScope);
@@ -51,7 +52,6 @@ type
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
property CurrentDescriptor: IScopeDescriptor read FCurrentDescriptor;
- property NextIsTail: Boolean write FNextIsTail;
end;
implementation
@@ -61,12 +61,6 @@ uses
Myc.Ast;
type
- TResolvedAddressComparer = class(TEqualityComparer)
- public
- function Equals(const Left, Right: TResolvedAddress): Boolean; override;
- function GetHashCode(const Value: TResolvedAddress): Integer; override;
- end;
-
TScopeDescriptor = class(TInterfacedObject, IScopeDescriptor)
private
FParent: IScopeDescriptor;
@@ -84,22 +78,6 @@ type
property Symbols: TDictionary read FSymbols;
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 }
constructor TAstBinder.Create(const AInitialScope: IExecutionScope);
@@ -108,15 +86,31 @@ begin
FCurrentDescriptor := CreateDescriptor(AInitialScope);
FUpvalueStack := TObjectStack.Create(true);
FNestedLambdaCount := 0;
- FNextIsTail := False;
+ FIsTailStack := TStack.Create;
+ // The content of the root node is in a tail position.
+ FNextIsTail := true;
end;
destructor TAstBinder.Destroy;
begin
+ FIsTailStack.Free;
FUpvalueStack.Free;
inherited;
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;
var
binder: TAstBinder;
@@ -125,7 +119,7 @@ begin
try
binder.EnterScope;
try
- // Start the traversal. The content of the root node is in a tail position.
+ // Start the traversal
binder.Accept(RootNode);
Result := binder.CurrentDescriptor;
finally
@@ -158,12 +152,6 @@ begin
FCurrentDescriptor := FCurrentDescriptor.Parent;
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;
begin
FNextIsTail := False;
@@ -177,27 +165,24 @@ begin
end;
function TAstBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
-var
- i: Integer;
begin
- for i := 0 to Node.Expressions.Count - 2 do
- begin
- FNextIsTail := False;
- Accept(Node.Expressions[i]);
- end;
+ FNextIsTail := False;
- if Node.Expressions.Count > 0 then
+ var n := Node.Expressions.Count - 1;
+ for var i := 0 to n do
begin
// The last expression is in a tail position IF the block itself is.
- FNextIsTail := Data.Peek;
- Accept(Node.Expressions.Last);
+ if i = n then
+ FNextIsTail := FIsTailStack.Peek;
+
+ Accept(Node.Expressions[i]);
end;
end;
function TAstBinder.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin
// 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
// their context is non-tail.
@@ -250,7 +235,7 @@ begin
Accept(Node.Condition);
// The branches are in a tail position if the if-expression itself is.
- FNextIsTail := Data.Peek;
+ FNextIsTail := FIsTailStack.Peek;
Accept(Node.ThenBranch);
if Assigned(Node.ElseBranch) then
Accept(Node.ElseBranch);
@@ -266,14 +251,13 @@ begin
try
EnterScope;
try
- (FCurrentDescriptor as TScopeDescriptor).Define('Self');
+ FCurrentDescriptor.Define('Self');
for param in Node.Parameters do
- (FCurrentDescriptor as TScopeDescriptor).Define(param.Name);
+ FCurrentDescriptor.Define(param.Name);
var lastNestedLambdaCount := FNestedLambdaCount;
- // Manually traverse children since we can't call 'inherited' from the simple traverser.
// Parameters are never in a tail position.
FNextIsTail := False;
for param in Node.Parameters do
@@ -290,22 +274,23 @@ begin
end;
finally
var upvalue := FUpvalueStack.Peek;
+ try
+ sortedPairs := upvalue.Map.ToArray;
+ TArray.Sort>(
+ sortedPairs,
+ TComparer>.Construct(
+ function(const Left, Right: TPair): Integer begin Result := Left.Value - Right.Value; end
+ )
+ );
- sortedPairs := upvalue.Map.ToArray;
- TArray.Sort>(
- sortedPairs,
- TComparer>.Construct(
- function(const Left, Right: TPair): Integer begin Result := Left.Value - Right.Value; end
- )
- );
+ SetLength(sourceAddresses, Length(sortedPairs));
+ for var i := 0 to High(sortedPairs) do
+ sourceAddresses[i] := sortedPairs[i].Key;
- SetLength(sourceAddresses, Length(sortedPairs));
- for var i := 0 to High(sortedPairs) do
- sourceAddresses[i] := sortedPairs[i].Key;
-
- (Node as TLambdaExpressionNode).Upvalues := sourceAddresses;
-
- FUpvalueStack.Pop;
+ (Node as TLambdaExpressionNode).Upvalues := sourceAddresses;
+ finally
+ FUpvalueStack.Pop;
+ end;
inc(FNestedLambdaCount);
end;
@@ -318,7 +303,7 @@ begin
Accept(Node.Condition);
// The branches are in a tail position if the ternary expression itself is.
- FNextIsTail := Data.Peek;
+ FNextIsTail := FIsTailStack.Peek;
Accept(Node.ThenBranch);
Accept(Node.ElseBranch);
end;
@@ -338,7 +323,7 @@ begin
if Assigned(Node.Initializer) then
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);
FNextIsTail := False;
@@ -412,7 +397,7 @@ end;
constructor TAstBinder.TUpvalueMapping.Create;
begin
inherited Create;
- Map := TDictionary.Create(TResolvedAddressComparer.Default);
+ Map := TDictionary.Create;
Nodes := TList.Create();
end;