Files
MycLib/Src/AST/Myc.Ast.Visitor.pas
T
2025-11-22 14:49:24 +01:00

849 lines
33 KiB
ObjectPascal

unit Myc.Ast.Visitor;
interface
uses
System.SysUtils,
System.Generics.Collections,
Myc.Data.Value,
Myc.Ast,
Myc.Ast.Types,
Myc.Ast.Nodes;
type
TAstVisitor<T> = 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.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 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 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<IAstNode>)
protected
function AcceptParameters(const Nodes: TArray<IIdentifierNode>): TArray<IIdentifierNode>;
function AcceptNodes(const Nodes: TArray<IAstNode>; const AcceptProc: TFunc<Integer, IAstNode, IAstNode> = nil): TArray<IAstNode>;
function VisitConstant(const Node: IConstantNode): IAstNode; override;
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
function VisitKeyword(const Node: IKeywordNode): 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.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 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 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<T>.Accept(const Node: IAstNode): T;
begin
if Assigned(Node) then
Result := Node.Accept(Self).AsGeneric<T>
else
Result := Default(T);
end;
{ TAstVisitor<T> }
function TAstVisitor<T>.DoVisitConstant(const Node: IConstantNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitConstant(Node));
end;
function TAstVisitor<T>.DoVisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitIdentifier(Node));
end;
function TAstVisitor<T>.DoVisitKeyword(const Node: IKeywordNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitKeyword(Node));
end;
function TAstVisitor<T>.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitIfExpression(Node));
end;
function TAstVisitor<T>.DoVisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitTernaryExpression(Node));
end;
function TAstVisitor<T>.DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitLambdaExpression(Node));
end;
function TAstVisitor<T>.DoVisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitFunctionCall(Node));
end;
function TAstVisitor<T>.DoVisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitMacroExpansionNode(Node));
end;
function TAstVisitor<T>.DoVisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitBlockExpression(Node));
end;
function TAstVisitor<T>.DoVisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitVariableDeclaration(Node));
end;
function TAstVisitor<T>.DoVisitAssignment(const Node: IAssignmentNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitAssignment(Node));
end;
function TAstVisitor<T>.DoVisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitMacroDefinition(Node));
end;
function TAstVisitor<T>.DoVisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitQuasiquote(Node));
end;
function TAstVisitor<T>.DoVisitUnquote(const Node: IUnquoteNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitUnquote(Node));
end;
function TAstVisitor<T>.DoVisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitUnquoteSplicing(Node));
end;
function TAstVisitor<T>.DoVisitIndexer(const Node: IIndexerNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitIndexer(Node));
end;
function TAstVisitor<T>.DoVisitMemberAccess(const Node: IMemberAccessNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitMemberAccess(Node));
end;
function TAstVisitor<T>.DoVisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitRecordLiteral(Node));
end;
function TAstVisitor<T>.DoVisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitCreateSeries(Node));
end;
function TAstVisitor<T>.DoVisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitAddSeriesItem(Node));
end;
function TAstVisitor<T>.DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitSeriesLength(Node));
end;
function TAstVisitor<T>.DoVisitRecurNode(const Node: IRecurNode): TDataValue;
begin
Result := TDataValue.FromGeneric<T>(VisitRecurNode(Node));
end;
function TAstVisitor<T>.DoVisitNop(const Node: INopNode): TDataValue;
begin
// Added Nop implementation
Result := TDataValue.FromGeneric<T>(VisitNop(Node));
end;
function TAstTransformer.AcceptParameters(const Nodes: TArray<IIdentifierNode>): TArray<IIdentifierNode>;
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<IAstNode>;
const AcceptProc: TFunc<Integer, IAstNode, IAstNode> = nil
): TArray<IAstNode>;
var
i: Integer;
newNode: IAstNode; // Changed from TDataValue
newList: TList<IAstNode>; // 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<IAstNode>.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<IAstNode>.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.VisitIfExpression(const Node: IIfExpressionNode): IAstNode;
var
newCond, newThen, newElse: IAstNode;
begin
newCond := Accept(Node.Condition);
newThen := Accept(Node.ThenBranch);
newElse := Accept(Node.ElseBranch); // Accept handles nil
if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then
Result := Node
else
// Use TAst factory
Result := TAst.IfExpr(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
// Use TAst factory
Result := TAst.TernaryExpr(newCond, newThen, newElse, Node.StaticType);
end;
function TAstTransformer.VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode;
var
newParams: TArray<IIdentifierNode>;
newBody: IAstNode;
begin
// No longer cast to concrete class, use interface
newParams := AcceptParameters(Node.Parameters);
newBody := Accept(Node.Body);
if (newParams = Node.Parameters) and (newBody = Node.Body) then
Result := Node
else
begin
// Use TAst factory and copy properties via interface getters
Result :=
TAst.LambdaExpr(
newParams,
newBody,
Node.Layout,
Node.Descriptor,
Node.Upvalues,
Node.HasNestedLambdas,
Node.IsPure,
Node.StaticType
);
end;
end;
function TAstTransformer.VisitFunctionCall(const Node: IFunctionCallNode): IAstNode;
var
newCallee: IAstNode;
newArgs: TArray<IAstNode>;
begin
newCallee := Accept(Node.Callee);
newArgs := AcceptNodes(Node.Arguments);
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then
Result := Node
else
begin
// Use TAst factory and copy properties via interface getters
Result := TAst.FunctionCall(newCallee, newArgs, Node.StaticType, Node.IsTailCall, Node.StaticTarget);
end;
end;
function TAstTransformer.VisitMacroExpansionNode(const Node: IMacroExpansionNode): IAstNode;
var
newBody: IAstNode;
begin
// Visit the body and check if it changed
newBody := Accept(Node.ExpandedBody);
if newBody = Node.ExpandedBody then
exit(Node);
// The body changed. Create a NEW wrapper node.
Result := TAst.MacroExpansionNode(Node.CallNode, newBody);
end;
function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
var
newExprs: TArray<IAstNode>;
begin
newExprs := AcceptNodes(Node.Expressions);
if newExprs = Node.Expressions then
Result := Node
else
// Use TAst factory
Result := TAst.Block(newExprs, Node.StaticType);
end;
function TAstTransformer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode;
var
newIdent: IIdentifierNode;
newInit: IAstNode;
begin
// No longer cast to concrete class, use interface
newIdent := Accept(Node.Identifier).AsIdentifier;
newInit := Accept(Node.Initializer); // Accept handles nil
if (newIdent = Node.Identifier) and (newInit = Node.Initializer) then
Result := Node
else
begin
// Use TAst factory and copy properties via interface getters
Result := TAst.VarDecl(newIdent, newInit, Node.StaticType, Node.IsBoxed);
end;
end;
function TAstTransformer.VisitAssignment(const Node: IAssignmentNode): IAstNode;
var
newIdent: IIdentifierNode;
newValue: IAstNode;
begin
newValue := Accept(Node.Value);
newIdent := Accept(Node.Identifier).AsIdentifier;
if (newValue = Node.Value) and (newIdent = Node.Identifier) then
Result := Node
else
// Use TAst factory
Result := TAst.Assign(newIdent, newValue, Node.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;
begin
newBase := Accept(Node.Base);
newIndex := Accept(Node.Index);
if (newBase = Node.Base) and (newIndex = Node.Index) then
Result := Node
else
// Use TAst factory
Result := TAst.Indexer(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; // Keyword ist Blattknoten
if (newBase = Node.Base) and (newMember = Node.Member) then
Result := Node
else
// Use TAst factory
Result := TAst.MemberAccess(newBase, newMember, Node.StaticType);
end;
function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
var
i: Integer;
newFields: TArray<TRecordFieldLiteral>;
hasChanged: Boolean;
begin
SetLength(newFields, Length(Node.Fields));
hasChanged := False;
for i := 0 to High(Node.Fields) do
begin
newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword;
newFields[i].Value := Accept(Node.Fields[i].Value);
if (newFields[i].Key <> Node.Fields[i].Key) or (newFields[i].Value <> Node.Fields[i].Value) then
hasChanged := True;
end;
if not hasChanged then
Result := Node
else
begin
// Rebuild the node, preserving its specific type and definitions
// Use TAst factory
Result := TAst.RecordLiteral(newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType);
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;
begin
newSeries := Accept(Node.Series).AsIdentifier;
newValue := Accept(Node.Value);
newLookback := Accept(Node.Lookback); // Accept handles nil
if (newSeries = Node.Series) and (newValue = Node.Value) and (newLookback = Node.Lookback) then
Result := Node
else
// Use TAst factory
Result := TAst.AddSeriesItem(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
// Use TAst factory
Result := TAst.SeriesLength(newSeries, Node.StaticType);
end;
function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode;
var
newArgs: TArray<IAstNode>;
begin
newArgs := AcceptNodes(Node.Arguments);
if newArgs = Node.Arguments then
Result := Node
else
// Use TAst factory
Result := TAst.Recur(newArgs, Node.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.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.