unit Myc.Ast.Visitor; interface uses System.SysUtils, System.Generics.Collections, Myc.Data.Value, Myc.Ast, Myc.Ast.Types, Myc.Ast.Nodes; type TAstVisitor = class abstract(TInterfacedObject, IAstVisitor) strict private // IAstVisitor explicit implementation (bridge methods) function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitKeyword = DoVisitKeyword; function IAstVisitor.VisitBinaryExpression = DoVisitBinaryExpression; function IAstVisitor.VisitUnaryExpression = DoVisitUnaryExpression; function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; function IAstVisitor.VisitFunctionCall = DoVisitFunctionCall; function IAstVisitor.VisitMacroExpansionNode = DoVisitMacroExpansionNode; function IAstVisitor.VisitBlockExpression = DoVisitBlockExpression; function IAstVisitor.VisitVariableDeclaration = DoVisitVariableDeclaration; function IAstVisitor.VisitAssignment = DoVisitAssignment; function IAstVisitor.VisitMacroDefinition = DoVisitMacroDefinition; function IAstVisitor.VisitQuasiquote = DoVisitQuasiquote; function IAstVisitor.VisitUnquote = DoVisitUnquote; function IAstVisitor.VisitUnquoteSplicing = DoVisitUnquoteSplicing; function IAstVisitor.VisitIndexer = DoVisitIndexer; function IAstVisitor.VisitMemberAccess = DoVisitMemberAccess; function IAstVisitor.VisitRecordLiteral = DoVisitRecordLiteral; function IAstVisitor.VisitCreateSeries = DoVisitCreateSeries; function IAstVisitor.VisitAddSeriesItem = DoVisitAddSeriesItem; function IAstVisitor.VisitSeriesLength = DoVisitSeriesLength; function IAstVisitor.VisitRecurNode = DoVisitRecurNode; function IAstVisitor.VisitNop = DoVisitNop; // Added Nop // Private bridge method implementations function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue; function DoVisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; function DoVisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; function DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function DoVisitAssignment(const Node: IAssignmentNode): TDataValue; function DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; function DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; function DoVisitUnquote(const Node: IUnquoteNode): TDataValue; function DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; function DoVisitIndexer(const Node: IIndexerNode): TDataValue; function DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; function DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; function DoVisitRecurNode(const Node: IRecurNode): TDataValue; function DoVisitNop(const Node: INopNode): TDataValue; // Added Nop protected // Visit a node. function Accept(const Node: IAstNode): T; virtual; function VisitConstant(const Node: IConstantNode): T; virtual; abstract; function VisitIdentifier(const Node: IIdentifierNode): T; virtual; abstract; function VisitKeyword(const Node: IKeywordNode): T; virtual; abstract; function VisitBinaryExpression(const Node: IBinaryExpressionNode): T; virtual; abstract; function VisitUnaryExpression(const Node: IUnaryExpressionNode): T; virtual; abstract; function VisitIfExpression(const Node: IIfExpressionNode): T; virtual; abstract; function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual; abstract; function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual; abstract; function VisitFunctionCall(const Node: IFunctionCallNode): T; virtual; abstract; function VisitMacroExpansionNode(const Node: IMacroExpansionNode): T; virtual; abstract; function VisitBlockExpression(const Node: IBlockExpressionNode): T; virtual; abstract; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): T; virtual; abstract; function VisitAssignment(const Node: IAssignmentNode): T; virtual; abstract; function VisitMacroDefinition(const Node: IMacroDefinitionNode): T; virtual; abstract; function VisitQuasiquote(const Node: IQuasiquoteNode): T; virtual; abstract; function VisitUnquote(const Node: IUnquoteNode): T; virtual; abstract; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): T; virtual; abstract; function VisitIndexer(const Node: IIndexerNode): T; virtual; abstract; function VisitMemberAccess(const Node: IMemberAccessNode): T; virtual; abstract; function VisitRecordLiteral(const Node: IRecordLiteralNode): T; virtual; abstract; function VisitCreateSeries(const Node: ICreateSeriesNode): T; virtual; abstract; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): T; virtual; abstract; function VisitSeriesLength(const Node: ISeriesLengthNode): T; virtual; abstract; function VisitRecurNode(const Node: IRecurNode): T; virtual; abstract; function VisitNop(const Node: INopNode): T; virtual; abstract; // Added Nop end; TAstTransformer = class abstract(TAstVisitor) protected function AcceptParameters(const Nodes: TArray): TArray; function AcceptNodes(const Nodes: TArray; const AcceptProc: TFunc = nil): TArray; function VisitConstant(const Node: IConstantNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; function VisitKeyword(const Node: IKeywordNode): IAstNode; override; function VisitBinaryExpression(const Node: IBinaryExpressionNode): IAstNode; override; function VisitUnaryExpression(const Node: IUnaryExpressionNode): IAstNode; override; function VisitIfExpression(const Node: IIfExpressionNode): IAstNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; override; function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override; function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override; function VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; override; function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override; function VisitAssignment(const Node: IAssignmentNode): IAstNode; override; function VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode; override; function VisitQuasiquote(const Node: IQuasiquoteNode): IAstNode; override; function VisitUnquote(const Node: IUnquoteNode): IAstNode; override; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override; function VisitIndexer(const Node: IIndexerNode): IAstNode; override; function VisitMemberAccess(const Node: IMemberAccessNode): IAstNode; override; function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override; function VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode; override; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode; override; function VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode; override; function VisitRecurNode(const Node: IRecurNode): IAstNode; override; function VisitNop(const Node: INopNode): IAstNode; override; // Added Nop end; TAstVisitor = class abstract(TInterfacedObject, IAstVisitor) strict private // IAstVisitor explicit implementation (bridge methods) function IAstVisitor.VisitConstant = DoVisitConstant; function IAstVisitor.VisitIdentifier = DoVisitIdentifier; function IAstVisitor.VisitKeyword = DoVisitKeyword; function IAstVisitor.VisitBinaryExpression = DoVisitBinaryExpression; function IAstVisitor.VisitUnaryExpression = DoVisitUnaryExpression; function IAstVisitor.VisitIfExpression = DoVisitIfExpression; function IAstVisitor.VisitTernaryExpression = DoVisitTernaryExpression; function IAstVisitor.VisitLambdaExpression = DoVisitLambdaExpression; function IAstVisitor.VisitFunctionCall = DoVisitFunctionCall; function IAstVisitor.VisitMacroExpansionNode = DoVisitMacroExpansionNode; function IAstVisitor.VisitBlockExpression = DoVisitBlockExpression; function IAstVisitor.VisitVariableDeclaration = DoVisitVariableDeclaration; function IAstVisitor.VisitAssignment = DoVisitAssignment; function IAstVisitor.VisitMacroDefinition = DoVisitMacroDefinition; function IAstVisitor.VisitQuasiquote = DoVisitQuasiquote; function IAstVisitor.VisitUnquote = DoVisitUnquote; function IAstVisitor.VisitUnquoteSplicing = DoVisitUnquoteSplicing; function IAstVisitor.VisitIndexer = DoVisitIndexer; function IAstVisitor.VisitMemberAccess = DoVisitMemberAccess; function IAstVisitor.VisitRecordLiteral = DoVisitRecordLiteral; function IAstVisitor.VisitCreateSeries = DoVisitCreateSeries; function IAstVisitor.VisitAddSeriesItem = DoVisitAddSeriesItem; function IAstVisitor.VisitSeriesLength = DoVisitSeriesLength; function IAstVisitor.VisitRecurNode = DoVisitRecurNode; function IAstVisitor.VisitNop = DoVisitNop; // Added Nop // Private bridge method implementations function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue; function DoVisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; function DoVisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; function DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; function DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; function DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function DoVisitAssignment(const Node: IAssignmentNode): TDataValue; function DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; function DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; function DoVisitUnquote(const Node: IUnquoteNode): TDataValue; function DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; function DoVisitIndexer(const Node: IIndexerNode): TDataValue; function DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; function DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; function DoVisitRecurNode(const Node: IRecurNode): TDataValue; function DoVisitNop(const Node: INopNode): TDataValue; // Added Nop protected // Virtual procedures for descendants (Interpreters/Side-effects) to override procedure VisitConstant(const Node: IConstantNode); virtual; abstract; procedure VisitIdentifier(const Node: IIdentifierNode); virtual; abstract; procedure VisitKeyword(const Node: IKeywordNode); virtual; abstract; procedure VisitBinaryExpression(const Node: IBinaryExpressionNode); virtual; abstract; procedure VisitUnaryExpression(const Node: IUnaryExpressionNode); virtual; abstract; procedure VisitIfExpression(const Node: IIfExpressionNode); virtual; abstract; procedure VisitTernaryExpression(const Node: ITernaryExpressionNode); virtual; abstract; procedure VisitLambdaExpression(const Node: ILambdaExpressionNode); virtual; abstract; procedure VisitFunctionCall(const Node: IFunctionCallNode); virtual; abstract; procedure VisitMacroExpansionNode(const Node: IMacroExpansionNode); virtual; abstract; procedure VisitBlockExpression(const Node: IBlockExpressionNode); virtual; abstract; procedure VisitVariableDeclaration(const Node: IVariableDeclarationNode); virtual; abstract; procedure VisitAssignment(const Node: IAssignmentNode); virtual; abstract; procedure VisitMacroDefinition(const Node: IMacroDefinitionNode); virtual; abstract; procedure VisitQuasiquote(const Node: IQuasiquoteNode); virtual; abstract; procedure VisitUnquote(const Node: IUnquoteNode); virtual; abstract; procedure VisitUnquoteSplicing(const Node: IUnquoteSplicingNode); virtual; abstract; procedure VisitIndexer(const Node: IIndexerNode); virtual; abstract; procedure VisitMemberAccess(const Node: IMemberAccessNode); virtual; abstract; procedure VisitRecordLiteral(const Node: IRecordLiteralNode); virtual; abstract; procedure VisitCreateSeries(const Node: ICreateSeriesNode); virtual; abstract; procedure VisitAddSeriesItem(const Node: IAddSeriesItemNode); virtual; abstract; procedure VisitSeriesLength(const Node: ISeriesLengthNode); virtual; abstract; procedure VisitRecurNode(const Node: IRecurNode); virtual; abstract; procedure VisitNop(const Node: INopNode); virtual; abstract; // Added Nop end; implementation { TAstVisitor } function TAstVisitor.Accept(const Node: IAstNode): T; begin if Assigned(Node) then Result := Node.Accept(Self).AsGeneric else Result := Default(T); end; { TAstVisitor } function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitConstant(Node)); end; function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIdentifier(Node)); end; function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitKeyword(Node)); end; function TAstVisitor.DoVisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitBinaryExpression(Node)); end; function TAstVisitor.DoVisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitUnaryExpression(Node)); end; function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIfExpression(Node)); end; function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitTernaryExpression(Node)); end; function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitLambdaExpression(Node)); end; function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitFunctionCall(Node)); end; function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMacroExpansionNode(Node)); end; function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitBlockExpression(Node)); end; function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitVariableDeclaration(Node)); end; function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitAssignment(Node)); end; function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMacroDefinition(Node)); end; function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitQuasiquote(Node)); end; function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitUnquote(Node)); end; function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitUnquoteSplicing(Node)); end; function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitIndexer(Node)); end; function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitMemberAccess(Node)); end; function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecordLiteral(Node)); end; function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitCreateSeries(Node)); end; function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitAddSeriesItem(Node)); end; function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitSeriesLength(Node)); end; function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecurNode(Node)); end; function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue; begin // Added Nop implementation Result := TDataValue.FromGeneric(VisitNop(Node)); end; function TAstTransformer.AcceptParameters(const Nodes: TArray): TArray; var i: Integer; hasChanged: Boolean; newNode: IIdentifierNode; begin // Implement Copy-on-Write for parameter arrays hasChanged := False; SetLength(Result, Length(Nodes)); for i := 0 to High(Nodes) do begin newNode := Accept(Nodes[i]).AsIdentifier; Result[i] := newNode; if newNode <> Nodes[i] then hasChanged := True; end; if not hasChanged then Result := Nodes; // Return original array if no changes end; function TAstTransformer.AcceptNodes( const Nodes: TArray; const AcceptProc: TFunc = nil ): TArray; var i: Integer; newNode: IAstNode; // Changed from TDataValue newList: TList; // Used if nodes are removed (e.g. defmacro) hasChanged: Boolean; begin // This implementation already supports CoW and node removal (nil) // We just need to track if the array reference itself needs to change. hasChanged := False; newList := nil; for i := 0 to High(Nodes) do begin if Assigned(AcceptProc) then newNode := AcceptProc(i, Nodes[i]) else newNode := Accept(Nodes[i]); // Calls new Accept, returns IAstNode (or nil) if not Assigned(newNode) then // Node was removed begin hasChanged := True; if newList = nil then // First change begin newList := TList.Create; for var j := 0 to i - 1 do newList.Add(Nodes[j]); end; // else: just skip adding it end else begin if newNode <> Nodes[i] then // Node was replaced begin hasChanged := True; if newList = nil then // First change begin newList := TList.Create; for var j := 0 to i - 1 do newList.Add(Nodes[j]); end; newList.Add(newNode); end else begin if newList <> nil then // No change, but we are already copying newList.Add(Nodes[i]); end; end; end; if not hasChanged then Result := Nodes // Return original array else if newList <> nil then begin Result := newList.ToArray; newList.Free; end else Result := []; // All nodes were removed end; // --- Base Virtual Implementations (IAstNode-based) --- // --- Now fully implementing Copy-on-Write (CoW) --- function TAstTransformer.VisitConstant(const Node: IConstantNode): IAstNode; begin Result := Node; // Leaf node, immutable end; function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): IAstNode; begin Result := Node; // Leaf node, immutable (will be replaced by Binder) end; function TAstTransformer.VisitKeyword(const Node: IKeywordNode): IAstNode; begin Result := Node; // Leaf node, immutable end; function TAstTransformer.VisitNop(const Node: INopNode): IAstNode; begin // Added Nop implementation Result := Node; // Leaf node, immutable end; function TAstTransformer.VisitBinaryExpression(const Node: IBinaryExpressionNode): IAstNode; var newLeft, newRight: IAstNode; N: TBinaryExpressionNode; begin N := (Node as TBinaryExpressionNode); newLeft := Accept(N.Left); newRight := Accept(N.Right); if (newLeft = N.Left) and (newRight = N.Right) then Result := Node else Result := TBinaryExpressionNode.Create(newLeft, N.Operator, newRight, N.StaticType); end; function TAstTransformer.VisitUnaryExpression(const Node: IUnaryExpressionNode): IAstNode; var newRight: IAstNode; N: TUnaryExpressionNode; begin N := (Node as TUnaryExpressionNode); newRight := Accept(N.Right); if newRight = N.Right then Result := Node else Result := TUnaryExpressionNode.Create(N.Operator, newRight, N.StaticType); end; function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; var newCond, newThen, newElse: IAstNode; N: TIfExpressionNode; begin N := (Node as TIfExpressionNode); newCond := Accept(N.Condition); newThen := Accept(N.ThenBranch); newElse := Accept(N.ElseBranch); // Accept handles nil if (newCond = N.Condition) and (newThen = N.ThenBranch) and (newElse = N.ElseBranch) then Result := Node else Result := TIfExpressionNode.Create(newCond, newThen, newElse, N.StaticType); end; function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; var newCond, newThen, newElse: IAstNode; N: TTernaryExpressionNode; begin N := (Node as TTernaryExpressionNode); newCond := Accept(N.Condition); newThen := Accept(N.ThenBranch); newElse := Accept(N.ElseBranch); if (newCond = N.Condition) and (newThen = N.ThenBranch) and (newElse = N.ElseBranch) then Result := Node else Result := TTernaryExpressionNode.Create(newCond, newThen, newElse, N.StaticType); end; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; var newParams: TArray; newBody: IAstNode; N: TLambdaExpressionNode; begin N := (Node as TLambdaExpressionNode); newParams := AcceptParameters(N.Parameters); newBody := Accept(N.Body); if (newParams = N.Parameters) and (newBody = N.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; end; end; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var newCallee: IAstNode; newArgs: TArray; N: TFunctionCallNode; begin N := (Node as TFunctionCallNode); newCallee := Accept(N.Callee); newArgs := AcceptNodes(N.Arguments); if (newCallee = N.Callee) and (newArgs = N.Arguments) then Result := Node else begin Result := TFunctionCallNode.Create(newCallee, newArgs, N.StaticType); // Copy runtime properties (Result as TFunctionCallNode).IsTailCall := N.IsTailCall; end; end; function TAstTransformer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; var newBody: IAstNode; N: TMacroExpansionNode; newType: IStaticType; begin N := (Node as TMacroExpansionNode); // 1. Visit the body newBody := Accept(N.ExpandedBody); // 2. Check if the body changed (Copy-on-Write) if newBody = N.ExpandedBody then begin // No change, return the original immutable node Result := Node; end else begin // The body changed. Create a NEW wrapper node. // The type of the wrapper is the type of its body. newType := newBody.AsTypedNode.StaticType; Result := TMacroExpansionNode.Create(N.CallNode, newBody, newType); end; end; function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; var newExprs: TArray; N: TBlockExpressionNode; begin N := (Node as TBlockExpressionNode); newExprs := AcceptNodes(N.Expressions); if newExprs = N.Expressions then Result := Node else Result := TBlockExpressionNode.Create(newExprs, N.StaticType); end; function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; var newIdent: IIdentifierNode; newInit: IAstNode; N: TVariableDeclarationNode; begin N := (Node as TVariableDeclarationNode); newIdent := Accept(N.Identifier).AsIdentifier; newInit := Accept(N.Initializer); // Accept handles nil if (newIdent = N.Identifier) and (newInit = N.Initializer) then Result := Node else begin Result := TVariableDeclarationNode.Create(newIdent, newInit, N.StaticType); // Copy runtime properties (Result as TVariableDeclarationNode).IsBoxed := N.IsBoxed; end; end; function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): IAstNode; var newIdent: IIdentifierNode; newValue: IAstNode; N: TAssignmentNode; begin N := (Node as TAssignmentNode); newValue := Accept(N.Value); newIdent := Accept(N.Identifier).AsIdentifier; if (newValue = N.Value) and (newIdent = N.Identifier) then Result := Node else Result := TAssignmentNode.Create(newIdent, newValue, N.StaticType); end; function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode; begin // A macro definition is a compile-time construct. // Transformers (Binder, TypeChecker, Lowerer) should not traverse its // children (Name, Parameters, Body) as they are not part of the // standard execution AST. // Serializers (TAstDumper/TJsonAstConverter), which need to traverse, // provide their own override. Result := Node; end; function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): IAstNode; var newExpr: IAstNode; begin // Rebuild instead of mutate (Copy-on-Write) newExpr := Accept(Node.Expression); if newExpr = Node.Expression then Result := Node else Result := TAst.Quasiquote(newExpr); end; function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): IAstNode; var newExpr: IAstNode; begin // Rebuild instead of mutate (Copy-on-Write) newExpr := Accept(Node.Expression); if newExpr = Node.Expression then Result := Node else Result := TAst.Unquote(newExpr); end; function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; var newExpr: IAstNode; begin // Rebuild instead of mutate (Copy-on-Write) newExpr := Accept(Node.Expression); if (newExpr = Node.Expression) then Result := Node else Result := TAst.UnquoteSplicing(newExpr.AsQuasiquote); end; function TAstTransformer.VisitIndexer(const Node: IIndexerNode): IAstNode; var newBase, newIndex: IAstNode; N: TIndexerNode; begin N := (Node as TIndexerNode); newBase := Accept(N.Base); newIndex := Accept(N.Index); if (newBase = N.Base) and (newIndex = N.Index) then Result := Node else Result := TIndexerNode.Create(newBase, newIndex, N.StaticType); end; function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): IAstNode; var newBase: IAstNode; newMember: IKeywordNode; N: TMemberAccessNode; begin N := (Node as TMemberAccessNode); newBase := Accept(N.Base); newMember := Accept(N.Member).AsKeyword; // Keyword ist Blattknoten if (newBase = N.Base) and (newMember = N.Member) then Result := Node else Result := TMemberAccessNode.Create(newBase, newMember, N.StaticType); end; function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; var N: TRecordLiteralNode; i: Integer; newFields: TArray; hasChanged: Boolean; begin N := (Node as TRecordLiteralNode); SetLength(newFields, Length(N.Fields)); hasChanged := False; for i := 0 to High(N.Fields) do begin newFields[i].Key := Accept(N.Fields[i].Key).AsKeyword; newFields[i].Value := Accept(N.Fields[i].Value); if (newFields[i].Key <> N.Fields[i].Key) or (newFields[i].Value <> N.Fields[i].Value) then hasChanged := True; end; if not hasChanged then Result := Node else begin // Rebuild the node, preserving its specific type and definitions if N is TGenericRecordLiteralNode then begin Result := TGenericRecordLiteralNode.Create(newFields, N.StaticType); (Result as TGenericRecordLiteralNode).GenericDefinition := (N as TGenericRecordLiteralNode).GenericDefinition; end else begin Result := TRecordLiteralNode.Create(newFields, N.StaticType); (Result as TRecordLiteralNode).Definition := N.Definition; end; end; end; function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode; begin Result := Node; // Leaf node, immutable end; function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode; var newSeries: IIdentifierNode; newValue, newLookback: IAstNode; N: TAddSeriesItemNode; begin N := (Node as TAddSeriesItemNode); newSeries := Accept(N.Series).AsIdentifier; newValue := Accept(N.Value); newLookback := Accept(N.Lookback); // Accept handles nil if (newSeries = N.Series) and (newValue = N.Value) and (newLookback = N.Lookback) then Result := Node else Result := TAddSeriesItemNode.Create(newSeries, newValue, newLookback, N.StaticType); end; function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode; var newSeries: IIdentifierNode; N: TSeriesLengthNode; begin N := (Node as TSeriesLengthNode); newSeries := Accept(N.Series).AsIdentifier; if newSeries = N.Series then Result := Node else Result := TSeriesLengthNode.Create(newSeries, N.StaticType); end; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode; var newArgs: TArray; N: TRecurNode; begin N := (Node as TRecurNode); newArgs := AcceptNodes(N.Arguments); if newArgs = N.Arguments then Result := Node else Result := TRecurNode.Create(newArgs, N.StaticType); end; { TAstVisitor } function TAstVisitor.DoVisitConstant(const Node: IConstantNode): TDataValue; begin VisitConstant(Node); end; function TAstVisitor.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; begin VisitIdentifier(Node); end; function TAstVisitor.DoVisitKeyword(const Node: IKeywordNode): TDataValue; begin VisitKeyword(Node); end; function TAstVisitor.DoVisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; begin VisitBinaryExpression(Node); end; function TAstVisitor.DoVisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; begin VisitUnaryExpression(Node); end; function TAstVisitor.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue; begin VisitIfExpression(Node); end; function TAstVisitor.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; begin VisitTernaryExpression(Node); end; function TAstVisitor.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; begin VisitLambdaExpression(Node); end; function TAstVisitor.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue; begin VisitFunctionCall(Node); end; function TAstVisitor.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; begin VisitMacroExpansionNode(Node); end; function TAstVisitor.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; begin VisitBlockExpression(Node); end; function TAstVisitor.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; begin VisitVariableDeclaration(Node); end; function TAstVisitor.DoVisitAssignment(const Node: IAssignmentNode): TDataValue; begin VisitAssignment(Node); end; function TAstVisitor.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; begin VisitMacroDefinition(Node); end; function TAstVisitor.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; begin VisitQuasiquote(Node); end; function TAstVisitor.DoVisitUnquote(const Node: IUnquoteNode): TDataValue; begin VisitUnquote(Node); end; function TAstVisitor.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; begin VisitUnquoteSplicing(Node); end; function TAstVisitor.DoVisitIndexer(const Node: IIndexerNode): TDataValue; begin VisitIndexer(Node); end; function TAstVisitor.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue; begin VisitMemberAccess(Node); end; function TAstVisitor.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; begin VisitRecordLiteral(Node); end; function TAstVisitor.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; begin VisitCreateSeries(Node); end; function TAstVisitor.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; begin VisitAddSeriesItem(Node); end; function TAstVisitor.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; begin VisitSeriesLength(Node); end; function TAstVisitor.DoVisitRecurNode(const Node: IRecurNode): TDataValue; begin VisitRecurNode(Node); end; function TAstVisitor.DoVisitNop(const Node: INopNode): TDataValue; begin // Added Nop implementation VisitNop(Node); end; end.