Ast list nodes
This commit is contained in:
@@ -99,26 +99,42 @@ function TAstTCO.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNod
|
||||
var
|
||||
isContextTail: Boolean;
|
||||
newExprs: TArray<IAstNode>;
|
||||
exprsList: IExpressionList;
|
||||
i: Integer;
|
||||
item, newItem: IAstNode;
|
||||
hasChanged: Boolean;
|
||||
begin
|
||||
isContextTail := FIsTailStack.Peek;
|
||||
exprsList := Node.Expressions;
|
||||
|
||||
var nTail := High(Node.Expressions);
|
||||
newExprs :=
|
||||
AcceptNodes(
|
||||
Node.Expressions,
|
||||
function(idx: Integer; Node: IAstNode): IAstNode
|
||||
begin
|
||||
// Only the last expression in the block inherits the tail position status
|
||||
FNextIsTail := isContextTail and (idx = nTail);
|
||||
Result := Accept(Node);
|
||||
end
|
||||
);
|
||||
SetLength(newExprs, exprsList.Count);
|
||||
hasChanged := False;
|
||||
|
||||
if newExprs = Node.Expressions then
|
||||
var nTail := exprsList.Count - 1;
|
||||
|
||||
for i := 0 to nTail do
|
||||
begin
|
||||
item := exprsList[i];
|
||||
|
||||
// Only the last expression in the block inherits the tail position status
|
||||
FNextIsTail := isContextTail and (i = nTail);
|
||||
|
||||
newItem := Accept(item);
|
||||
newExprs[i] := newItem;
|
||||
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
end;
|
||||
|
||||
if not hasChanged then
|
||||
Result := Node
|
||||
else
|
||||
begin
|
||||
// Wrap array in List container
|
||||
var newList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
|
||||
// CoW: Reuse Identity
|
||||
Result := TAst.Block(Node.Identity, newExprs, Node.StaticType);
|
||||
Result := TAst.Block(Node.Identity, newList, Node.StaticType);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstTCO.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
|
||||
@@ -169,12 +185,13 @@ end;
|
||||
|
||||
function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
|
||||
var
|
||||
newParams: TArray<IIdentifierNode>;
|
||||
newParams: IParameterList;
|
||||
newBody: IAstNode;
|
||||
begin
|
||||
// Parameters are not in tail position
|
||||
FNextIsTail := False;
|
||||
newParams := AcceptParameters(Node.Parameters);
|
||||
// Visit list node to handle potential transformations in children
|
||||
newParams := Accept(Node.Parameters).AsParameterList;
|
||||
|
||||
// The body of a lambda is *always* a tail position (relative to the lambda execution)
|
||||
FNextIsTail := True;
|
||||
@@ -185,8 +202,7 @@ begin
|
||||
else
|
||||
begin
|
||||
// Rebuild using factory.
|
||||
// IMPORTANT: Pass Layout AND Descriptor (TCO runs after TypeChecker).
|
||||
// CoW: Reuse Identity
|
||||
// CoW: Reuse Identity. Factory expects IParameterList now.
|
||||
Result :=
|
||||
TAst.LambdaExpr(
|
||||
Node.Identity,
|
||||
@@ -204,20 +220,21 @@ end;
|
||||
|
||||
function TAstTCO.VisitRecurNode(const Node: IRecurNode): IAstNode;
|
||||
var
|
||||
newArgs: TArray<IAstNode>;
|
||||
newArgsList: IArgumentList;
|
||||
begin
|
||||
if not FIsTailStack.Peek then
|
||||
raise EOptimizerException.Create('''recur'' can only be used in a tail position.');
|
||||
|
||||
// Arguments are not in tail position
|
||||
FNextIsTail := False;
|
||||
newArgs := AcceptNodes(Node.Arguments);
|
||||
// Visit the list node. Accept() ensures children are visited via TAstTransformer.VisitArgumentList
|
||||
newArgsList := Accept(Node.Arguments).AsArgumentList;
|
||||
|
||||
if newArgs = Node.Arguments then
|
||||
if newArgsList = Node.Arguments then
|
||||
Result := Node
|
||||
else
|
||||
// CoW: Reuse Identity
|
||||
Result := TAst.Recur(Node.Identity, newArgs, Node.StaticType);
|
||||
// CoW: Reuse Identity. Factory expects IArgumentList.
|
||||
Result := TAst.Recur(Node.Identity, newArgsList, Node.StaticType);
|
||||
end;
|
||||
|
||||
function TAstTCO.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode;
|
||||
@@ -239,29 +256,32 @@ function TAstTCO.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
|
||||
var
|
||||
isTailCall: Boolean;
|
||||
newCallee: IAstNode;
|
||||
newArgs: TArray<IAstNode>;
|
||||
newArgsList: IArgumentList;
|
||||
begin
|
||||
isTailCall := FIsTailStack.Peek;
|
||||
|
||||
// Callee/Arguments are not in tail position
|
||||
FNextIsTail := False;
|
||||
|
||||
newCallee := Accept(Node.Callee);
|
||||
newArgs := AcceptNodes(Node.Arguments);
|
||||
|
||||
// Visit the arguments list
|
||||
newArgsList := Accept(Node.Arguments).AsArgumentList;
|
||||
|
||||
// CoW check: Create a new node only if children changed OR IsTailCall needs update
|
||||
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) and (isTailCall = Node.IsTailCall) then
|
||||
if (newCallee = Node.Callee) and (newArgsList = Node.Arguments) and (isTailCall = Node.IsTailCall) then
|
||||
begin
|
||||
Result := Node;
|
||||
exit;
|
||||
end;
|
||||
|
||||
// Use factory to create new node, passing the *new* TCO status
|
||||
// CoW: Reuse Identity
|
||||
// CoW: Reuse Identity. Factory expects IArgumentList.
|
||||
Result :=
|
||||
TAst.FunctionCall(
|
||||
Node.Identity,
|
||||
newCallee,
|
||||
newArgs,
|
||||
newArgsList,
|
||||
Node.StaticType,
|
||||
isTailCall,
|
||||
Node.StaticTarget, // Preserve the static target from Specializer
|
||||
|
||||
Reference in New Issue
Block a user