unit Myc.Ast.Visitor; interface uses System.SysUtils, System.Generics.Collections, Myc.Data.Value, Myc.Ast, Myc.Ast.Types, Myc.Ast.Nodes, Myc.Ast.Identities; 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.VisitParameterList = DoVisitParameterList; function IAstVisitor.VisitArgumentList = DoVisitArgumentList; function IAstVisitor.VisitExpressionList = DoVisitExpressionList; function IAstVisitor.VisitRecordFieldList = DoVisitRecordFieldList; function IAstVisitor.VisitRecordField = DoVisitRecordField; 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; // Private bridge method implementations function DoVisitConstant(const Node: IConstantNode): TDataValue; function DoVisitIdentifier(const Node: IIdentifierNode): TDataValue; function DoVisitKeyword(const Node: IKeywordNode): TDataValue; function DoVisitParameterList(const Node: IParameterList): TDataValue; function DoVisitArgumentList(const Node: IArgumentList): TDataValue; function DoVisitExpressionList(const Node: IExpressionList): TDataValue; function DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; function DoVisitRecordField(const Node: IRecordFieldNode): 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; protected // Visit a node. function Accept(const Node: IAstNode): T; virtual; // Default visitor functions implemented analogous to TAstVisitor function VisitConstant(const Node: IConstantNode): T; virtual; function VisitIdentifier(const Node: IIdentifierNode): T; virtual; function VisitKeyword(const Node: IKeywordNode): T; virtual; function VisitParameterList(const Node: IParameterList): T; virtual; function VisitArgumentList(const Node: IArgumentList): T; virtual; function VisitExpressionList(const Node: IExpressionList): T; virtual; function VisitRecordFieldList(const Node: IRecordFieldList): T; virtual; function VisitRecordField(const Node: IRecordFieldNode): T; virtual; function VisitIfExpression(const Node: IIfExpressionNode): T; virtual; function VisitTernaryExpression(const Node: ITernaryExpressionNode): T; virtual; function VisitLambdaExpression(const Node: ILambdaExpressionNode): T; virtual; function VisitFunctionCall(const Node: IFunctionCallNode): T; virtual; function VisitMacroExpansionNode(const Node: IMacroExpansionNode): T; virtual; function VisitBlockExpression(const Node: IBlockExpressionNode): T; virtual; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): T; virtual; function VisitAssignment(const Node: IAssignmentNode): T; virtual; function VisitMacroDefinition(const Node: IMacroDefinitionNode): T; virtual; function VisitQuasiquote(const Node: IQuasiquoteNode): T; virtual; function VisitUnquote(const Node: IUnquoteNode): T; virtual; function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): T; virtual; function VisitIndexer(const Node: IIndexerNode): T; virtual; function VisitMemberAccess(const Node: IMemberAccessNode): T; virtual; function VisitRecordLiteral(const Node: IRecordLiteralNode): T; virtual; function VisitCreateSeries(const Node: ICreateSeriesNode): T; virtual; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): T; virtual; function VisitSeriesLength(const Node: ISeriesLengthNode): T; virtual; function VisitRecurNode(const Node: IRecurNode): T; virtual; function VisitNop(const Node: INopNode): T; virtual; end; TAstTransformer = class abstract(TAstVisitor) protected function VisitConstant(const Node: IConstantNode): IAstNode; override; function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override; function VisitKeyword(const Node: IKeywordNode): IAstNode; override; function VisitParameterList(const Node: IParameterList): IAstNode; override; function VisitArgumentList(const Node: IArgumentList): IAstNode; override; function VisitExpressionList(const Node: IExpressionList): IAstNode; override; function VisitRecordFieldList(const Node: IRecordFieldList): IAstNode; override; function VisitRecordField(const Node: IRecordFieldNode): 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; end; TVoid = record end; TAstVisitor = class(TAstVisitor); implementation { TAstVisitor } function TAstVisitor.Accept(const Node: IAstNode): T; begin if Assigned(Node) then Result := Node.Accept(Self).AsGeneric else Result := Default(T); end; 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.DoVisitParameterList(const Node: IParameterList): TDataValue; begin Result := TDataValue.FromGeneric(VisitParameterList(Node)); end; function TAstVisitor.DoVisitArgumentList(const Node: IArgumentList): TDataValue; begin Result := TDataValue.FromGeneric(VisitArgumentList(Node)); end; function TAstVisitor.DoVisitExpressionList(const Node: IExpressionList): TDataValue; begin Result := TDataValue.FromGeneric(VisitExpressionList(Node)); end; function TAstVisitor.DoVisitRecordFieldList(const Node: IRecordFieldList): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecordFieldList(Node)); end; function TAstVisitor.DoVisitRecordField(const Node: IRecordFieldNode): TDataValue; begin Result := TDataValue.FromGeneric(VisitRecordField(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 Result := TDataValue.FromGeneric(VisitNop(Node)); end; // --- Default implementations (analogous to TAstVisitor) --- function TAstVisitor.VisitConstant(const Node: IConstantNode): T; begin Result := Default(T); end; function TAstVisitor.VisitIdentifier(const Node: IIdentifierNode): T; begin Result := Default(T); end; function TAstVisitor.VisitKeyword(const Node: IKeywordNode): T; begin Result := Default(T); end; function TAstVisitor.VisitParameterList(const Node: IParameterList): T; begin Result := Default(T); for var Item in Node do Accept(Item); end; function TAstVisitor.VisitArgumentList(const Node: IArgumentList): T; begin Result := Default(T); for var Item in Node do Accept(Item); end; function TAstVisitor.VisitExpressionList(const Node: IExpressionList): T; begin Result := Default(T); for var Item in Node do Accept(Item); end; function TAstVisitor.VisitRecordFieldList(const Node: IRecordFieldList): T; begin Result := Default(T); for var Item in Node do Accept(Item); end; function TAstVisitor.VisitRecordField(const Node: IRecordFieldNode): T; begin Result := Default(T); Accept(Node.Key); Accept(Node.Value); end; function TAstVisitor.VisitIfExpression(const Node: IIfExpressionNode): T; begin Result := Default(T); Accept(Node.Condition); Accept(Node.ThenBranch); Accept(Node.ElseBranch); end; function TAstVisitor.VisitTernaryExpression(const Node: ITernaryExpressionNode): T; begin Result := Default(T); Accept(Node.Condition); Accept(Node.ThenBranch); Accept(Node.ElseBranch); end; function TAstVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): T; begin Result := Default(T); Accept(Node.Parameters); Accept(Node.Body); end; function TAstVisitor.VisitFunctionCall(const Node: IFunctionCallNode): T; begin Result := Default(T); Accept(Node.Callee); Accept(Node.Arguments); end; function TAstVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode): T; begin Result := Default(T); Accept(Node.CallNode); Accept(Node.ExpandedBody); end; function TAstVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): T; begin Result := Default(T); Accept(Node.Expressions); end; function TAstVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): T; begin Result := Default(T); Accept(Node.Target); Accept(Node.Initializer); end; function TAstVisitor.VisitAssignment(const Node: IAssignmentNode): T; begin Result := Default(T); Accept(Node.Target); Accept(Node.Value); end; function TAstVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): T; begin Result := Default(T); Accept(Node.Name); Accept(Node.Parameters); Accept(Node.Body); end; function TAstVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): T; begin Result := Default(T); Accept(Node.Expression); end; function TAstVisitor.VisitUnquote(const Node: IUnquoteNode): T; begin Result := Default(T); Accept(Node.Expression); end; function TAstVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): T; begin Result := Default(T); Accept(Node.Expression); end; function TAstVisitor.VisitIndexer(const Node: IIndexerNode): T; begin Result := Default(T); Accept(Node.Base); Accept(Node.Index); end; function TAstVisitor.VisitMemberAccess(const Node: IMemberAccessNode): T; begin Result := Default(T); Accept(Node.Base); Accept(Node.Member); end; function TAstVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): T; begin Result := Default(T); Accept(Node.Fields); end; function TAstVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): T; begin Result := Default(T); end; function TAstVisitor.VisitAddSeriesItem(const Node: IAddSeriesItemNode): T; begin Result := Default(T); Accept(Node.Series); Accept(Node.Value); Accept(Node.Lookback); end; function TAstVisitor.VisitSeriesLength(const Node: ISeriesLengthNode): T; begin Result := Default(T); Accept(Node.Series); end; function TAstVisitor.VisitRecurNode(const Node: IRecurNode): T; begin Result := Default(T); Accept(Node.Arguments); end; function TAstVisitor.VisitNop(const Node: INopNode): T; begin Result := Default(T); end; { TAstTransformer } // --- Base Virtual Implementations --- function TAstTransformer.VisitConstant(const Node: IConstantNode): IAstNode; begin Result := Node; end; function TAstTransformer.VisitIdentifier(const Node: IIdentifierNode): IAstNode; begin Result := Node; end; function TAstTransformer.VisitKeyword(const Node: IKeywordNode): IAstNode; begin Result := Node; end; function TAstTransformer.VisitNop(const Node: INopNode): IAstNode; begin Result := Node; end; function TAstTransformer.VisitCreateSeries(const Node: ICreateSeriesNode): IAstNode; begin Result := Node; end; // --- List Transformations --- function TAstTransformer.VisitParameterList(const Node: IParameterList): IAstNode; var hasChanged: Boolean; newItems: TArray; item, newItem: IIdentifierNode; i: Integer; begin hasChanged := False; SetLength(newItems, Node.Count); for i := 0 to Node.Count - 1 do begin item := Node[i]; newItem := Accept(item).AsIdentifier; newItems[i] := newItem; if item <> newItem then hasChanged := True; end; if not hasChanged then Result := Node else // Manually reconstruct using concrete class to verify transformation Result := TParameterList.Create(newItems, Node.Identity); end; function TAstTransformer.VisitArgumentList(const Node: IArgumentList): IAstNode; var hasChanged: Boolean; newItems: TArray; item, newItem: IAstNode; i: Integer; begin hasChanged := False; SetLength(newItems, Node.Count); for i := 0 to Node.Count - 1 do begin item := Node[i]; newItem := Accept(item); newItems[i] := newItem; if item <> newItem then hasChanged := True; end; if not hasChanged then Result := Node else Result := TArgumentList.Create(newItems, Node.Identity); end; function TAstTransformer.VisitExpressionList(const Node: IExpressionList): IAstNode; var hasChanged: Boolean; newItems: TArray; item, newItem: IAstNode; i: Integer; begin hasChanged := False; SetLength(newItems, Node.Count); for i := 0 to Node.Count - 1 do begin item := Node[i]; newItem := Accept(item); newItems[i] := newItem; if item <> newItem then hasChanged := True; end; if not hasChanged then Result := Node else Result := TExpressionList.Create(newItems, Node.Identity); end; function TAstTransformer.VisitRecordFieldList(const Node: IRecordFieldList): IAstNode; var hasChanged: Boolean; newItems: TArray; item, newItem: IRecordFieldNode; i: Integer; begin hasChanged := False; SetLength(newItems, Node.Count); for i := 0 to Node.Count - 1 do begin item := Node[i]; // Ensure we transform the field node itself via Accept to trigger VisitRecordField newItem := Accept(item).AsRecordField; newItems[i] := newItem; if item <> newItem then hasChanged := True; end; if not hasChanged then Result := Node else Result := TRecordFieldList.Create(newItems, Node.Identity); end; function TAstTransformer.VisitRecordField(const Node: IRecordFieldNode): IAstNode; var newKey: IKeywordNode; newValue: IAstNode; begin newKey := Accept(Node.Key).AsKeyword; newValue := Accept(Node.Value); if (newKey = Node.Key) and (newValue = Node.Value) then Result := Node else Result := TAst.RecordField(newKey, newValue, Node.Identity.Location); end; // --- Node Transformations --- function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstNode; var newCond, newThen, newElse: IAstNode; begin newCond := Accept(Node.Condition); newThen := Accept(Node.ThenBranch); newElse := Accept(Node.ElseBranch); if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then Result := Node else Result := TAst.IfExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType); end; function TAstTransformer.VisitTernaryExpression(const Node: ITernaryExpressionNode): IAstNode; var newCond, newThen, newElse: IAstNode; begin newCond := Accept(Node.Condition); newThen := Accept(Node.ThenBranch); newElse := Accept(Node.ElseBranch); if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then Result := Node else Result := TAst.TernaryExpr(Node.Identity, newCond, newThen, newElse, Node.StaticType); end; function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; var newParams: IParameterList; newBody: IAstNode; begin newParams := Accept(Node.Parameters).AsParameterList; newBody := Accept(Node.Body); if (newParams = Node.Parameters) and (newBody = Node.Body) then Result := Node else begin // Rebuild Lambda via concrete constructor to keep Layout/Descriptor info // TAst factory would reset layout info. Result := TLambdaExpressionNode.Create( newParams, newBody, Node.StaticType, Node.Layout, Node.Descriptor, Node.Upvalues, Node.HasNestedLambdas, Node.IsPure, Node.Identity ); end; end; function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; var newCallee: IAstNode; newArgs: IArgumentList; begin newCallee := Accept(Node.Callee); newArgs := Accept(Node.Arguments).AsArgumentList; if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then Result := Node else begin Result := TFunctionCallNode .Create(newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget, Node.IsTargetPure, Node.Identity); end; end; function TAstTransformer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode; var newBody: IAstNode; begin newBody := Accept(Node.ExpandedBody); if newBody = Node.ExpandedBody then exit(Node); // Macro Expansion Nodes are structural, reuse identity. // Note: We don't visit the CallNode as it is the "source" which doesn't change during this transformation typically Result := TAst.MacroExpansionNode(Node.Identity, Node.CallNode, newBody); end; function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; var newExprs: IExpressionList; begin newExprs := Accept(Node.Expressions).AsExpressionList; if newExprs = Node.Expressions then Result := Node else // Rebuild manually to preserve type Result := TBlockExpressionNode.Create(newExprs, Node.StaticType, Node.Identity); end; function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; var newTarget: IAstNode; newInit: IAstNode; begin newTarget := Accept(Node.Target); newInit := Accept(Node.Initializer); if (newTarget = Node.Target) and (newInit = Node.Initializer) then Result := Node else begin Result := TAst.VarDecl(Node.Identity, newTarget, newInit, Node.StaticType, Node.IsBoxed); end; end; function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): IAstNode; var newTarget: IAstNode; newValue: IAstNode; begin newTarget := Accept(Node.Target); newValue := Accept(Node.Value); if (newTarget = Node.Target) and (newValue = Node.Value) then Result := Node else Result := TAst.Assign(Node.Identity, newTarget, newValue, Node.StaticType); end; function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode): IAstNode; begin // Macro definitions are usually stripped/ignored in transformers, // but we return them as-is to support partial pipelines. Result := Node; end; function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): IAstNode; var newExpr: IAstNode; begin newExpr := Accept(Node.Expression); if newExpr = Node.Expression then Result := Node else Result := TAst.Quasiquote(Node.Identity, newExpr); end; function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): IAstNode; var newExpr: IAstNode; begin newExpr := Accept(Node.Expression); if newExpr = Node.Expression then Result := Node else Result := TAst.Unquote(Node.Identity, newExpr); end; function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; var newExpr: IAstNode; begin newExpr := Accept(Node.Expression); if (newExpr = Node.Expression) then Result := Node else Result := TAst.UnquoteSplicing(Node.Identity, newExpr.AsQuasiquote); end; function TAstTransformer.VisitIndexer(const Node: IIndexerNode): IAstNode; var newBase, newIndex: IAstNode; begin newBase := Accept(Node.Base); newIndex := Accept(Node.Index); if (newBase = Node.Base) and (newIndex = Node.Index) then Result := Node else Result := TAst.Indexer(Node.Identity, newBase, newIndex, Node.StaticType); end; function TAstTransformer.VisitMemberAccess(const Node: IMemberAccessNode): IAstNode; var newBase: IAstNode; newMember: IKeywordNode; begin newBase := Accept(Node.Base); newMember := Accept(Node.Member).AsKeyword; if (newBase = Node.Base) and (newMember = Node.Member) then Result := Node else Result := TAst.MemberAccess(Node.Identity, newBase, newMember, Node.StaticType); end; function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; var newFields: IRecordFieldList; begin newFields := Accept(Node.Fields).AsRecordFieldList; if newFields = Node.Fields then Result := Node else begin Result := TRecordLiteralNode.Create(newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType, Node.Identity); end; end; function TAstTransformer.VisitAddSeriesItem(const Node: IAddSeriesItemNode): IAstNode; var newSeries: IIdentifierNode; newValue, newLookback: IAstNode; begin newSeries := Accept(Node.Series).AsIdentifier; newValue := Accept(Node.Value); newLookback := Accept(Node.Lookback); if (newSeries = Node.Series) and (newValue = Node.Value) and (newLookback = Node.Lookback) then Result := Node else Result := TAst.AddSeriesItem(Node.Identity, newSeries, newValue, newLookback, Node.StaticType); end; function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): IAstNode; var newSeries: IIdentifierNode; begin newSeries := Accept(Node.Series).AsIdentifier; if newSeries = Node.Series then Result := Node else Result := TAst.SeriesLength(Node.Identity, newSeries, Node.StaticType); end; function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode; var newArgs: IArgumentList; begin newArgs := Accept(Node.Arguments).AsArgumentList; if newArgs = Node.Arguments then Result := Node else Result := TRecurNode.Create(newArgs, Node.StaticType, Node.Identity); end; end.