930 lines
37 KiB
ObjectPascal
930 lines
37 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.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<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 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<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>.DoVisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue;
|
|
begin
|
|
Result := TDataValue.FromGeneric<T>(VisitBinaryExpression(Node));
|
|
end;
|
|
|
|
function TAstVisitor<T>.DoVisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
|
|
begin
|
|
Result := TDataValue.FromGeneric<T>(VisitUnaryExpression(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.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<IIdentifierNode>;
|
|
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<IAstNode>;
|
|
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: IAstTypedNode;
|
|
begin
|
|
// Visit the body and check if it changed
|
|
newBody := Accept(Node.ExpandedBody).AsTypedNode;
|
|
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>;
|
|
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<TRecordFieldLiteral>;
|
|
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<IAstNode>;
|
|
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.
|