Node immutability improved
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user