Node immutability improved

This commit is contained in:
Michael Schimmel
2025-11-05 18:13:43 +01:00
parent 0915d6d90d
commit 1f0eef7698
11 changed files with 409 additions and 308 deletions
+10 -19
View File
@@ -184,29 +184,23 @@ end;
function TAstTCO.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
var
N: TLambdaExpressionNode;
newParams: TArray<IIdentifierNode>;
newBody: IAstNode;
begin
N := (Node as TLambdaExpressionNode);
// Parameters are not in tail position (handled by AcceptParameters)
FNextIsTail := False;
newParams := AcceptParameters(N.Parameters);
newParams := AcceptParameters(Node.Parameters);
// The body of a lambda is *always* a tail position (relative to the lambda)
FNextIsTail := True;
newBody := Accept(N.Body);
newBody := Accept(Node.Body);
if (newParams = N.Parameters) and (newBody = N.Body) then
if (newParams = Node.Parameters) and (newBody = Node.Body) then
Result := Node
else
begin
Result := TLambdaExpressionNode.Create(newParams, newBody, N.StaticType);
// Copy runtime properties
(Result as TLambdaExpressionNode).ScopeDescriptor := N.ScopeDescriptor;
(Result as TLambdaExpressionNode).Upvalues := N.Upvalues;
(Result as TLambdaExpressionNode).HasNestedLambdas := N.HasNestedLambdas;
// Rebuild using factory and copy properties via interface
Result := TAst.LambdaExpr(newParams, newBody, Node.ScopeDescriptor, Node.Upvalues, Node.HasNestedLambdas, Node.StaticType);
end;
end;
@@ -245,26 +239,23 @@ end;
function TAstTCO.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var
isTailCall: Boolean;
N: TFunctionCallNode;
newCallee: IAstNode;
newArgs: TArray<IAstNode>;
begin
isTailCall := FIsTailStack.Peek;
N := (Node as TFunctionCallNode);
// Arguments are not in tail position
FNextIsTail := False;
newCallee := Accept(N.Callee);
newArgs := AcceptNodes(N.Arguments);
newCallee := Accept(Node.Callee);
newArgs := AcceptNodes(Node.Arguments);
// CoW check: Create a new node only if children changed OR IsTailCall needs update
if (newCallee = N.Callee) and (newArgs = N.Arguments) and (isTailCall = N.IsTailCall) then
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) and (isTailCall = Node.IsTailCall) then
Result := Node
else
begin
Result := TFunctionCallNode.Create(newCallee, newArgs, N.StaticType);
// Mutate the *new* node with the TCO status
(Result as TFunctionCallNode).IsTailCall := isTailCall;
// Use factory to create new node, passing the *new* TCO status
Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, isTailCall);
end;
end;