Generic Visitor Pattern
This commit is contained in:
@@ -10,56 +10,59 @@ uses
|
||||
Myc.Data.Value,
|
||||
Myc.Data.Keyword,
|
||||
Myc.Ast.Nodes,
|
||||
Myc.Ast.Scope;
|
||||
Myc.Ast.Scope,
|
||||
Myc.Ast.Visitor;
|
||||
|
||||
type
|
||||
// Exception for runtime errors during script evaluation
|
||||
EEvaluatorException = class(EAstException);
|
||||
|
||||
// The standard AST evaluator for production use.
|
||||
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor, IEvaluatorVisitor)
|
||||
TEvaluatorVisitor = class(TAstVisitor<TDataValue>, IEvaluatorVisitor)
|
||||
private
|
||||
FScope: IExecutionScope;
|
||||
|
||||
protected
|
||||
// IAstVisitor methods made virtual for TDebugEvaluatorVisitor to override
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; virtual;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; virtual;
|
||||
function VisitKeyword(const Node: IKeywordNode): TDataValue; virtual;
|
||||
// Setup the registry-based handlers
|
||||
procedure SetupHandlers; override;
|
||||
|
||||
// List Visitors
|
||||
function VisitParameterList(const Node: IParameterList): TDataValue; virtual;
|
||||
function VisitArgumentList(const Node: IArgumentList): TDataValue; virtual;
|
||||
function VisitExpressionList(const Node: IExpressionList): TDataValue; virtual;
|
||||
function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; virtual;
|
||||
function VisitRecordField(const Node: IRecordFieldNode): TDataValue; virtual;
|
||||
// --- Core Logic Implementation (Legacy Virtual Overrides) ---
|
||||
// These are kept as virtual methods so TDebugEvaluatorVisitor can still override them.
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue; override;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
|
||||
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
|
||||
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual;
|
||||
function VisitCondExpression(const Node: ICondExpressionNode): TDataValue; virtual;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; virtual;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; virtual;
|
||||
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; virtual;
|
||||
function VisitUnquote(const Node: IUnquoteNode): TDataValue; virtual;
|
||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; virtual;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; virtual;
|
||||
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; virtual;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; virtual;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; virtual;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; virtual;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; virtual;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; virtual;
|
||||
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; virtual;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; virtual;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; virtual;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; virtual;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; virtual;
|
||||
function VisitNop(const Node: INopNode): TDataValue; virtual;
|
||||
function VisitParameterList(const Node: IParameterList): TDataValue; override;
|
||||
function VisitArgumentList(const Node: IArgumentList): TDataValue; override;
|
||||
function VisitExpressionList(const Node: IExpressionList): TDataValue; override;
|
||||
function VisitRecordFieldList(const Node: IRecordFieldList): TDataValue; override;
|
||||
function VisitRecordField(const Node: IRecordFieldNode): TDataValue; override;
|
||||
|
||||
// Pipe Support
|
||||
function VisitPipeInput(const Node: IPipeInputNode): TDataValue; virtual;
|
||||
function VisitPipeSelectorList(const Node: IPipeSelectorList): TDataValue; virtual;
|
||||
function VisitPipeInputList(const Node: IPipeInputList): TDataValue; virtual;
|
||||
function VisitPipe(const Node: IPipeNode): TDataValue; virtual;
|
||||
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
|
||||
function VisitCondExpression(const Node: ICondExpressionNode): TDataValue; override;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; override;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
|
||||
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; override;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
|
||||
function VisitAssignment(const Node: IAssignmentNode): TDataValue; override;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue; override;
|
||||
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue; override;
|
||||
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
|
||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
|
||||
function VisitIndexer(const Node: IIndexerNode): TDataValue; override;
|
||||
function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; override;
|
||||
function VisitRecordLiteral(const Node: IRecordLiteralNode): TDataValue; override;
|
||||
function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; override;
|
||||
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; override;
|
||||
function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; override;
|
||||
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
|
||||
function VisitNop(const Node: INopNode): TDataValue; override;
|
||||
|
||||
function VisitPipeInput(const Node: IPipeInputNode): TDataValue; override;
|
||||
function VisitPipeSelectorList(const Node: IPipeSelectorList): TDataValue; override;
|
||||
function VisitPipeInputList(const Node: IPipeInputList): TDataValue; override;
|
||||
function VisitPipe(const Node: IPipeNode): TDataValue; override;
|
||||
|
||||
function IsTruthy(const AValue: TDataValue): Boolean; inline;
|
||||
|
||||
@@ -108,9 +111,21 @@ end;
|
||||
|
||||
constructor TEvaluatorVisitor.Create(const AScope: IExecutionScope);
|
||||
begin
|
||||
FScope := AScope;
|
||||
// Base constructor calls SetupHandlers automatically
|
||||
inherited Create;
|
||||
Assert(Assigned(AScope));
|
||||
FScope := AScope;
|
||||
end;
|
||||
|
||||
procedure TEvaluatorVisitor.SetupHandlers;
|
||||
begin
|
||||
// The base SetupHandlers registers delegates that call the virtual methods (VisitConstant, etc.).
|
||||
// Since TEvaluatorVisitor still implements its logic by overriding these virtual methods (for now),
|
||||
// we just call inherited.
|
||||
//
|
||||
// In Phase 2/3 of refactoring, we would move the logic from VisitConstant directly into
|
||||
// anonymous methods or separate handler functions registered here, bypassing the virtual table.
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.Execute(const RootNode: IAstNode): TDataValue;
|
||||
@@ -119,7 +134,8 @@ begin
|
||||
exit(TDataValue.Void);
|
||||
|
||||
try
|
||||
Result := RootNode.Accept(Self);
|
||||
// Call the central dispatch method from TAstVisitor<T>
|
||||
Result := Visit(RootNode);
|
||||
HandleTCO(Result);
|
||||
except
|
||||
on E: EAstException do
|
||||
@@ -171,6 +187,23 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// --- Visits Implementation ---
|
||||
|
||||
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
begin
|
||||
Result := Node.Value;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue(TScalar.FromKeyword(Node.Value));
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
begin
|
||||
Result := FScope[Node.Address];
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
var
|
||||
capturedCells: TArray<IValueCell>;
|
||||
@@ -232,8 +265,9 @@ begin
|
||||
end;
|
||||
|
||||
// Create a visitor with the new scope and execute the lambda's body.
|
||||
// Use the generic Visit method for dispatch
|
||||
bodyVisitor := visitorFactory(lambdaScope);
|
||||
Result := cNode.Body.Accept(bodyVisitor);
|
||||
Result := bodyVisitor.Visit(cNode.Body);
|
||||
end;
|
||||
|
||||
Result := TDataValue(closure);
|
||||
@@ -272,7 +306,7 @@ begin
|
||||
argList := Node.Arguments;
|
||||
SetLength(argValues, argList.Count);
|
||||
for i := 0 to argList.Count - 1 do
|
||||
argValues[i] := argList[i].Accept(Self);
|
||||
argValues[i] := Visit(argList[i]); // Use central dispatch
|
||||
|
||||
// Call static target. Exceptions here are caught by Execute/HandleTCO.
|
||||
Result := Node.StaticTarget(argValues);
|
||||
@@ -281,14 +315,14 @@ begin
|
||||
else
|
||||
begin
|
||||
// --- Dynamic Path (Default) ---
|
||||
calleeValue := Node.Callee.Accept(Self);
|
||||
calleeValue := Visit(Node.Callee);
|
||||
if calleeValue.Kind <> vkMethod then
|
||||
raise EEvaluatorException.Create('Expression is not invokable in this context.');
|
||||
|
||||
argList := Node.Arguments;
|
||||
SetLength(argValues, argList.Count);
|
||||
for i := 0 to argList.Count - 1 do
|
||||
argValues[i] := argList[i].Accept(Self);
|
||||
argValues[i] := Visit(argList[i]);
|
||||
|
||||
if Node.IsTailCall then
|
||||
begin
|
||||
@@ -304,7 +338,7 @@ end;
|
||||
|
||||
function TEvaluatorVisitor.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
|
||||
begin
|
||||
Result := Node.ExpandedBody.Accept(Self);
|
||||
Result := Visit(Node.ExpandedBody);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
@@ -316,7 +350,7 @@ var
|
||||
begin
|
||||
SetLength(argValues, Node.Arguments.Count);
|
||||
for i := 0 to Node.Arguments.Count - 1 do
|
||||
argValues[i] := Node.Arguments[i].Accept(Self);
|
||||
argValues[i] := Visit(Node.Arguments[i]);
|
||||
|
||||
calleeAddress.Kind := akLocalOrParent;
|
||||
calleeAddress.ScopeDepth := 0;
|
||||
@@ -332,12 +366,12 @@ var
|
||||
lookback: Int64;
|
||||
begin
|
||||
seriesVar := FScope[Node.Series.Address];
|
||||
itemValue := Node.Value.Accept(Self);
|
||||
itemValue := Visit(Node.Value);
|
||||
lookback := -1;
|
||||
|
||||
if Assigned(Node.Lookback) then
|
||||
begin
|
||||
lookbackValue := Node.Lookback.Accept(Self);
|
||||
lookbackValue := Visit(Node.Lookback);
|
||||
if (lookbackValue.Kind <> vkScalar) or (lookbackValue.AsScalar.Kind <> TScalar.TKind.Ordinal) then
|
||||
raise EEvaluatorException.Create('Lookback parameter must be an integer.');
|
||||
lookback := lookbackValue.AsScalar.Value.AsInt64;
|
||||
@@ -362,20 +396,10 @@ begin
|
||||
if Node.Target.Kind <> akIdentifier then
|
||||
raise EEvaluatorException.Create('Runtime Error: Assignment target must be an identifier.');
|
||||
|
||||
Result := Node.Value.Accept(Self);
|
||||
Result := Visit(Node.Value);
|
||||
FScope[Node.Target.AsIdentifier.Address] := Result;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
begin
|
||||
Result := Node.Value;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue(TScalar.FromKeyword(Node.Value));
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
|
||||
var
|
||||
def: string;
|
||||
@@ -403,11 +427,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
begin
|
||||
Result := FScope[Node.Address];
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIndexer(const Node: IIndexerNode): TDataValue;
|
||||
var
|
||||
baseValue, indexValue: TDataValue;
|
||||
@@ -420,12 +439,12 @@ var
|
||||
memberSeries: ISeries;
|
||||
scalarValue: TScalar;
|
||||
begin
|
||||
baseValue := Node.Base.Accept(Self);
|
||||
baseValue := Visit(Node.Base);
|
||||
|
||||
if baseValue.IsVoid then
|
||||
exit(TDataValue.Void);
|
||||
|
||||
indexValue := Node.Index.Accept(Self);
|
||||
indexValue := Visit(Node.Index);
|
||||
|
||||
if (indexValue.Kind <> vkScalar) or (indexValue.AsScalar.Kind <> TScalar.TKind.Ordinal) then
|
||||
raise EEvaluatorException.Create('Indexer `[]` requires an integer argument.');
|
||||
@@ -471,7 +490,7 @@ function TEvaluatorVisitor.VisitMemberAccess(const Node: IMemberAccessNode): TDa
|
||||
var
|
||||
baseValue: TDataValue;
|
||||
begin
|
||||
baseValue := Node.Base.Accept(Self);
|
||||
baseValue := Visit(Node.Base);
|
||||
|
||||
if baseValue.IsVoid then
|
||||
exit(TDataValue.Void);
|
||||
@@ -498,7 +517,7 @@ begin
|
||||
for i := 0 to Node.Fields.Count - 1 do
|
||||
begin
|
||||
var field := Node.Fields[i];
|
||||
genFields[i] := TPair<IKeyword, TDataValue>.Create(field.Key.Value, field.Value.Accept(Self));
|
||||
genFields[i] := TPair<IKeyword, TDataValue>.Create(field.Key.Value, Visit(field.Value));
|
||||
end;
|
||||
|
||||
Result := TDataValue.FromGenericRecord(TKeywordMapping<TDataValue>.Create(genFields));
|
||||
@@ -511,7 +530,7 @@ begin
|
||||
for i := 0 to Node.Fields.Count - 1 do
|
||||
begin
|
||||
var field := Node.Fields[i];
|
||||
var valData := field.Value.Accept(Self);
|
||||
var valData := Visit(field.Value);
|
||||
values[i] := valData.AsScalar.Value;
|
||||
end;
|
||||
|
||||
@@ -529,7 +548,7 @@ begin
|
||||
raise EEvaluatorException.Create('Runtime Error: Variable declaration target must be an identifier.');
|
||||
|
||||
if Assigned(Node.Initializer) then
|
||||
Result := Node.Initializer.Accept(Self)
|
||||
Result := Visit(Node.Initializer)
|
||||
else
|
||||
Result := TDataValue.Void;
|
||||
|
||||
@@ -548,10 +567,10 @@ end;
|
||||
|
||||
function TEvaluatorVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
begin
|
||||
if IsTruthy(Node.Condition.Accept(Self)) then
|
||||
Result := Node.ThenBranch.Accept(Self)
|
||||
if IsTruthy(Visit(Node.Condition)) then
|
||||
Result := Visit(Node.ThenBranch)
|
||||
else if Assigned(Node.ElseBranch) then
|
||||
Result := Node.ElseBranch.Accept(Self)
|
||||
Result := Visit(Node.ElseBranch)
|
||||
else
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
@@ -562,20 +581,20 @@ var
|
||||
begin
|
||||
for pair in Node.Pairs do
|
||||
begin
|
||||
if IsTruthy(pair.Condition.Accept(Self)) then
|
||||
if IsTruthy(Visit(pair.Condition)) then
|
||||
begin
|
||||
Result := pair.Branch.Accept(Self);
|
||||
Result := Visit(pair.Branch);
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
// Else branch is mandatory in AST (though can be Nop/Void in source if omitted and normalized)
|
||||
Result := Node.ElseBranch.Accept(Self);
|
||||
Result := Visit(Node.ElseBranch);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
begin
|
||||
// Delegate to ExpressionList visitor
|
||||
Result := Node.Expressions.Accept(Self);
|
||||
// Delegate to ExpressionList visitor via central Visit dispatch (default handler maps to VisitExpressionList)
|
||||
Result := Visit(Node.Expressions);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitExpressionList(const Node: IExpressionList): TDataValue;
|
||||
@@ -584,7 +603,7 @@ var
|
||||
begin
|
||||
Result := TDataValue.Void;
|
||||
for i := 0 to Node.Count - 1 do
|
||||
Result := Node[i].Accept(Self);
|
||||
Result := Visit(Node[i]);
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitNop(const Node: INopNode): TDataValue;
|
||||
@@ -610,7 +629,7 @@ begin
|
||||
Result := TDataValue(TScalar.FromInt64(len));
|
||||
end;
|
||||
|
||||
// --- List Visitor Stubs (Mostly Unused directly, but required by Interface) ---
|
||||
// --- List Visitor Stubs (Default to Void if not implemented specifically) ---
|
||||
|
||||
function TEvaluatorVisitor.VisitParameterList(const Node: IParameterList): TDataValue;
|
||||
begin
|
||||
@@ -619,20 +638,16 @@ end;
|
||||
|
||||
function TEvaluatorVisitor.VisitArgumentList(const Node: IArgumentList): TDataValue;
|
||||
begin
|
||||
// Could evaluate arguments here and return an array-wrapped TDataValue,
|
||||
// but VisitFunctionCall handles iteration manually for efficiency.
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitRecordFieldList(const Node: IRecordFieldList): TDataValue;
|
||||
begin
|
||||
// Handled by VisitRecordLiteral
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TEvaluatorVisitor.VisitRecordField(const Node: IRecordFieldNode): TDataValue;
|
||||
begin
|
||||
// Handled by manual iteration in VisitRecordLiteral
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
@@ -711,7 +726,7 @@ begin
|
||||
outputDef := Node.StaticType.Definition;
|
||||
|
||||
// 3. Compile Lambda
|
||||
lambdaFunc := Node.Transformation.Accept(Self).AsMethod();
|
||||
lambdaFunc := Visit(Node.Transformation).AsMethod();
|
||||
|
||||
// 4. Create Adapter
|
||||
pipeAdapter :=
|
||||
|
||||
@@ -64,6 +64,12 @@ type
|
||||
property Errors: TArray<TCompilerError> read FErrors;
|
||||
end;
|
||||
|
||||
// Exception for the new visitor registry dispatch
|
||||
ENoHandlerException = class(EAstException)
|
||||
public
|
||||
constructor Create(const KindName: string);
|
||||
end;
|
||||
|
||||
TCompiledFunction = record
|
||||
public
|
||||
Func: TDataValue.TFunc;
|
||||
@@ -507,6 +513,10 @@ type
|
||||
end;
|
||||
|
||||
IAstVisitor = interface
|
||||
// --- Central Dispatch Method (New) ---
|
||||
function Visit(const Node: IAstNode): TDataValue;
|
||||
|
||||
// --- Specific Methods (Legacy / Hybrid Support) ---
|
||||
function VisitConstant(const Node: IConstantNode): TDataValue;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): TDataValue;
|
||||
function VisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||
@@ -1268,6 +1278,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{ ENoHandlerException }
|
||||
|
||||
constructor ENoHandlerException.Create(const KindName: string);
|
||||
begin
|
||||
inherited CreateFmt('No visitor handler registered for AST node kind: %s', [KindName]);
|
||||
end;
|
||||
|
||||
{ TAstNode }
|
||||
|
||||
constructor TAstNode.Create(const AIdentity: IAstIdentity);
|
||||
|
||||
+206
-103
@@ -12,9 +12,20 @@ uses
|
||||
Myc.Ast.Identities;
|
||||
|
||||
type
|
||||
TAstVisitor<T> = class;
|
||||
|
||||
// Delegate for handling a specific node kind within the visitor context
|
||||
TNodeHandler<T> = reference to function(const Node: IAstNode): T;
|
||||
|
||||
TAstVisitor<T> = class abstract(TInterfacedObject, IAstVisitor)
|
||||
strict private
|
||||
// The registry for O(1) dispatch based on TAstNodeKind
|
||||
FHandlers: array[TAstNodeKind] of TNodeHandler<T>;
|
||||
|
||||
// IAstVisitor explicit implementation (bridge methods)
|
||||
function IAstVisitor.Visit = VisitBridge;
|
||||
|
||||
// Legacy bridge methods for IAstVisitor interface compliance
|
||||
function IAstVisitor.VisitConstant = DoVisitConstant;
|
||||
function IAstVisitor.VisitIdentifier = DoVisitIdentifier;
|
||||
function IAstVisitor.VisitKeyword = DoVisitKeyword;
|
||||
@@ -46,23 +57,21 @@ type
|
||||
function IAstVisitor.VisitRecurNode = DoVisitRecurNode;
|
||||
function IAstVisitor.VisitNop = DoVisitNop;
|
||||
|
||||
// Pipe Support
|
||||
function IAstVisitor.VisitPipeInput = DoVisitPipeInput;
|
||||
function IAstVisitor.VisitPipeSelectorList = DoVisitPipeSelectorList;
|
||||
function IAstVisitor.VisitPipeInputList = DoVisitPipeInputList;
|
||||
function IAstVisitor.VisitPipe = DoVisitPipe;
|
||||
|
||||
// Private bridge method implementations
|
||||
// Private helpers to wrap T into TDataValue for the non-generic interface
|
||||
function VisitBridge(const Node: IAstNode): TDataValue;
|
||||
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 DoVisitCondExpression(const Node: ICondExpressionNode): TDataValue;
|
||||
function DoVisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
@@ -83,17 +92,26 @@ type
|
||||
function DoVisitSeriesLength(const Node: ISeriesLengthNode): TDataValue;
|
||||
function DoVisitRecurNode(const Node: IRecurNode): TDataValue;
|
||||
function DoVisitNop(const Node: INopNode): TDataValue;
|
||||
|
||||
function DoVisitPipeInput(const Node: IPipeInputNode): TDataValue;
|
||||
function DoVisitPipeSelectorList(const Node: IPipeSelectorList): TDataValue;
|
||||
function DoVisitPipeInputList(const Node: IPipeInputList): TDataValue;
|
||||
function DoVisitPipe(const Node: IPipeNode): TDataValue;
|
||||
|
||||
protected
|
||||
// Visit a node.
|
||||
function Accept(const Node: IAstNode): T; virtual;
|
||||
// Registers a handler for a specific node kind.
|
||||
// Subclasses can call this in their constructor/SetupHandlers to override behavior without implementing VisitXYZ.
|
||||
procedure RegisterHandler(Kind: TAstNodeKind; Handler: TNodeHandler<T>);
|
||||
|
||||
// Default visitor functions implemented analogous to TAstVisitor
|
||||
// Initial setup of the dispatch table.
|
||||
// The base implementation maps all kinds to the legacy VisitXYZ virtual methods.
|
||||
procedure SetupHandlers; virtual;
|
||||
|
||||
// The central dispatch method. Looks up the handler in the registry.
|
||||
function Visit(const Node: IAstNode): T; virtual;
|
||||
|
||||
// Legacy Virtual Methods (kept for backward compatibility and default mapping)
|
||||
// Subclasses should eventually move to RegisterHandler, but overriding these still works
|
||||
// because SetupHandlers maps them by default.
|
||||
function VisitConstant(const Node: IConstantNode): T; virtual;
|
||||
function VisitIdentifier(const Node: IIdentifierNode): T; virtual;
|
||||
function VisitKeyword(const Node: IKeywordNode): T; virtual;
|
||||
@@ -129,8 +147,17 @@ type
|
||||
function VisitPipeSelectorList(const Node: IPipeSelectorList): T; virtual;
|
||||
function VisitPipeInputList(const Node: IPipeInputList): T; virtual;
|
||||
function VisitPipe(const Node: IPipeNode): T; virtual;
|
||||
|
||||
// Bridge to support calling Accept on node directly (double dispatch pattern)
|
||||
// In the new architecture, we prefer calling Visit(Node) directly.
|
||||
function Accept(const Node: IAstNode): T; virtual;
|
||||
|
||||
public
|
||||
constructor Create;
|
||||
end;
|
||||
|
||||
// Helper for transformation visitors (returns IAstNode)
|
||||
// Overrides legacy methods to provide default recursive reconstruction behavior.
|
||||
TAstTransformer = class abstract(TAstVisitor<IAstNode>)
|
||||
protected
|
||||
function VisitConstant(const Node: IConstantNode): IAstNode; override;
|
||||
@@ -179,12 +206,91 @@ implementation
|
||||
|
||||
{ TAstVisitor<T> }
|
||||
|
||||
constructor TAstVisitor<T>.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
SetupHandlers;
|
||||
end;
|
||||
|
||||
procedure TAstVisitor<T>.RegisterHandler(Kind: TAstNodeKind; Handler: TNodeHandler<T>);
|
||||
begin
|
||||
FHandlers[Kind] := Handler;
|
||||
end;
|
||||
|
||||
procedure TAstVisitor<T>.SetupHandlers;
|
||||
begin
|
||||
// Map all kinds to the legacy virtual methods.
|
||||
// This provides the compatibility layer for existing subclasses.
|
||||
// In Phase 2, subclasses will register their own handlers directly here.
|
||||
|
||||
// Core
|
||||
FHandlers[akConstant] := function(const Node: IAstNode): T begin Result := VisitConstant(Node.AsConstant); end;
|
||||
FHandlers[akIdentifier] := function(const Node: IAstNode): T begin Result := VisitIdentifier(Node.AsIdentifier); end;
|
||||
FHandlers[akKeyword] := function(const Node: IAstNode): T begin Result := VisitKeyword(Node.AsKeyword); end;
|
||||
|
||||
// Lists
|
||||
FHandlers[akParameterList] := function(const Node: IAstNode): T begin Result := VisitParameterList(Node.AsParameterList); end;
|
||||
FHandlers[akArgumentList] := function(const Node: IAstNode): T begin Result := VisitArgumentList(Node.AsArgumentList); end;
|
||||
FHandlers[akExpressionList] := function(const Node: IAstNode): T begin Result := VisitExpressionList(Node.AsExpressionList); end;
|
||||
FHandlers[akRecordFieldList] := function(const Node: IAstNode): T begin Result := VisitRecordFieldList(Node.AsRecordFieldList); end;
|
||||
FHandlers[akRecordField] := function(const Node: IAstNode): T begin Result := VisitRecordField(Node.AsRecordField); end;
|
||||
|
||||
// Structural
|
||||
FHandlers[akIfExpression] := function(const Node: IAstNode): T begin Result := VisitIfExpression(Node.AsIfExpression); end;
|
||||
FHandlers[akCondExpression] := function(const Node: IAstNode): T begin Result := VisitCondExpression(Node.AsCondExpression); end;
|
||||
FHandlers[akLambdaExpression] := function(const Node: IAstNode): T begin Result := VisitLambdaExpression(Node.AsLambdaExpression); end;
|
||||
FHandlers[akFunctionCall] := function(const Node: IAstNode): T begin Result := VisitFunctionCall(Node.AsFunctionCall); end;
|
||||
FHandlers[akMacroExpansion] := function(const Node: IAstNode): T begin Result := VisitMacroExpansionNode(Node.AsMacroExpansion); end;
|
||||
FHandlers[akBlockExpression] := function(const Node: IAstNode): T begin Result := VisitBlockExpression(Node.AsBlockExpression); end;
|
||||
FHandlers[akVariableDeclaration] :=
|
||||
function(const Node: IAstNode): T begin Result := VisitVariableDeclaration(Node.AsVariableDeclaration); end;
|
||||
FHandlers[akAssignment] := function(const Node: IAstNode): T begin Result := VisitAssignment(Node.AsAssignment); end;
|
||||
FHandlers[akMacroDefinition] := function(const Node: IAstNode): T begin Result := VisitMacroDefinition(Node.AsMacroDefinition); end;
|
||||
FHandlers[akQuasiquote] := function(const Node: IAstNode): T begin Result := VisitQuasiquote(Node.AsQuasiquote); end;
|
||||
FHandlers[akUnquote] := function(const Node: IAstNode): T begin Result := VisitUnquote(Node.AsUnquote); end;
|
||||
FHandlers[akUnquoteSplicing] := function(const Node: IAstNode): T begin Result := VisitUnquoteSplicing(Node.AsUnquoteSplicing); end;
|
||||
FHandlers[akIndexer] := function(const Node: IAstNode): T begin Result := VisitIndexer(Node.AsIndexer); end;
|
||||
FHandlers[akMemberAccess] := function(const Node: IAstNode): T begin Result := VisitMemberAccess(Node.AsMemberAccess); end;
|
||||
FHandlers[akRecordLiteral] := function(const Node: IAstNode): T begin Result := VisitRecordLiteral(Node.AsRecordLiteral); end;
|
||||
FHandlers[akCreateSeries] := function(const Node: IAstNode): T begin Result := VisitCreateSeries(Node.AsCreateSeries); end;
|
||||
FHandlers[akAddSeriesItem] := function(const Node: IAstNode): T begin Result := VisitAddSeriesItem(Node.AsAddSeriesItem); end;
|
||||
FHandlers[akSeriesLength] := function(const Node: IAstNode): T begin Result := VisitSeriesLength(Node.AsSeriesLength); end;
|
||||
FHandlers[akRecur] := function(const Node: IAstNode): T begin Result := VisitRecurNode(Node.AsRecur); end;
|
||||
FHandlers[akNop] := function(const Node: IAstNode): T begin Result := VisitNop(Node.AsNop); end;
|
||||
|
||||
// Pipes
|
||||
FHandlers[akPipeInput] := function(const Node: IAstNode): T begin Result := VisitPipeInput(Node.AsPipeInput); end;
|
||||
FHandlers[akPipeSelectorList] := function(const Node: IAstNode): T begin Result := VisitPipeSelectorList(Node.AsPipeSelectorList); end;
|
||||
FHandlers[akPipeInputList] := function(const Node: IAstNode): T begin Result := VisitPipeInputList(Node.AsPipeInputList); end;
|
||||
FHandlers[akPipe] := function(const Node: IAstNode): T begin Result := VisitPipe(Node.AsPipe); end;
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.Visit(const Node: IAstNode): T;
|
||||
var
|
||||
handler: TNodeHandler<T>;
|
||||
begin
|
||||
if not Assigned(Node) then
|
||||
Exit(Default(T));
|
||||
|
||||
// O(1) Lookup
|
||||
handler := FHandlers[Node.Kind];
|
||||
|
||||
if Assigned(handler) then
|
||||
Result := handler(Node)
|
||||
else
|
||||
raise ENoHandlerException.Create(Node.Kind.ToString);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.Accept(const Node: IAstNode): T;
|
||||
begin
|
||||
if Assigned(Node) then
|
||||
Result := Node.Accept(Self).AsGeneric<T>
|
||||
else
|
||||
Result := Default(T);
|
||||
Result := Visit(Node);
|
||||
end;
|
||||
|
||||
// --- Interface Bridge Methods (IAstVisitor -> TDataValue) ---
|
||||
|
||||
function TAstVisitor<T>.VisitBridge(const Node: IAstNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(Visit(Node));
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.DoVisitConstant(const Node: IConstantNode): TDataValue;
|
||||
@@ -199,7 +305,6 @@ function TAstVisitor<T>.DoVisitKeyword(const Node: IKeywordNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitKeyword(Node));
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.DoVisitParameterList(const Node: IParameterList): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitParameterList(Node));
|
||||
@@ -220,7 +325,6 @@ function TAstVisitor<T>.DoVisitRecordField(const Node: IRecordFieldNode): TDataV
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitRecordField(Node));
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.DoVisitIfExpression(const Node: IIfExpressionNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitIfExpression(Node));
|
||||
@@ -301,7 +405,6 @@ function TAstVisitor<T>.DoVisitNop(const Node: INopNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitNop(Node));
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.DoVisitPipeInput(const Node: IPipeInputNode): TDataValue;
|
||||
begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitPipeInput(Node));
|
||||
@@ -319,7 +422,7 @@ begin
|
||||
Result := TDataValue.FromGeneric<T>(VisitPipe(Node));
|
||||
end;
|
||||
|
||||
// --- Default implementations (analogous to TAstVisitor) ---
|
||||
// --- Default implementations (analogous to original abstract class stubs) ---
|
||||
|
||||
function TAstVisitor<T>.VisitConstant(const Node: IConstantNode): T;
|
||||
begin
|
||||
@@ -340,43 +443,43 @@ function TAstVisitor<T>.VisitParameterList(const Node: IParameterList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitArgumentList(const Node: IArgumentList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitExpressionList(const Node: IExpressionList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitRecordFieldList(const Node: IRecordFieldList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitRecordField(const Node: IRecordFieldNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Key);
|
||||
Accept(Node.Value);
|
||||
Visit(Node.Key);
|
||||
Visit(Node.Value);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitIfExpression(const Node: IIfExpressionNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Condition);
|
||||
Accept(Node.ThenBranch);
|
||||
Accept(Node.ElseBranch);
|
||||
Visit(Node.Condition);
|
||||
Visit(Node.ThenBranch);
|
||||
Visit(Node.ElseBranch);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitCondExpression(const Node: ICondExpressionNode): T;
|
||||
@@ -386,97 +489,97 @@ begin
|
||||
Result := Default(T);
|
||||
for pair in Node.Pairs do
|
||||
begin
|
||||
Accept(pair.Condition);
|
||||
Accept(pair.Branch);
|
||||
Visit(pair.Condition);
|
||||
Visit(pair.Branch);
|
||||
end;
|
||||
Accept(Node.ElseBranch);
|
||||
Visit(Node.ElseBranch);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitLambdaExpression(const Node: ILambdaExpressionNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Parameters);
|
||||
Accept(Node.Body);
|
||||
Visit(Node.Parameters);
|
||||
Visit(Node.Body);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitFunctionCall(const Node: IFunctionCallNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Callee);
|
||||
Accept(Node.Arguments);
|
||||
Visit(Node.Callee);
|
||||
Visit(Node.Arguments);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitMacroExpansionNode(const Node: IMacroExpansionNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.CallNode);
|
||||
Accept(Node.ExpandedBody);
|
||||
Visit(Node.CallNode);
|
||||
Visit(Node.ExpandedBody);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitBlockExpression(const Node: IBlockExpressionNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Expressions);
|
||||
Visit(Node.Expressions);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitVariableDeclaration(const Node: IVariableDeclarationNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Target);
|
||||
Accept(Node.Initializer);
|
||||
Visit(Node.Target);
|
||||
Visit(Node.Initializer);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitAssignment(const Node: IAssignmentNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Target);
|
||||
Accept(Node.Value);
|
||||
Visit(Node.Target);
|
||||
Visit(Node.Value);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitMacroDefinition(const Node: IMacroDefinitionNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Name);
|
||||
Accept(Node.Parameters);
|
||||
Accept(Node.Body);
|
||||
Visit(Node.Name);
|
||||
Visit(Node.Parameters);
|
||||
Visit(Node.Body);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitQuasiquote(const Node: IQuasiquoteNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Expression);
|
||||
Visit(Node.Expression);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitUnquote(const Node: IUnquoteNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Expression);
|
||||
Visit(Node.Expression);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Expression);
|
||||
Visit(Node.Expression);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitIndexer(const Node: IIndexerNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Base);
|
||||
Accept(Node.Index);
|
||||
Visit(Node.Base);
|
||||
Visit(Node.Index);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitMemberAccess(const Node: IMemberAccessNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Base);
|
||||
Accept(Node.Member);
|
||||
Visit(Node.Base);
|
||||
Visit(Node.Member);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitRecordLiteral(const Node: IRecordLiteralNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Fields);
|
||||
Visit(Node.Fields);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitCreateSeries(const Node: ICreateSeriesNode): T;
|
||||
@@ -487,21 +590,21 @@ end;
|
||||
function TAstVisitor<T>.VisitAddSeriesItem(const Node: IAddSeriesItemNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Series);
|
||||
Accept(Node.Value);
|
||||
Accept(Node.Lookback);
|
||||
Visit(Node.Series);
|
||||
Visit(Node.Value);
|
||||
Visit(Node.Lookback);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitSeriesLength(const Node: ISeriesLengthNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Series);
|
||||
Visit(Node.Series);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitRecurNode(const Node: IRecurNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Arguments);
|
||||
Visit(Node.Arguments);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitNop(const Node: INopNode): T;
|
||||
@@ -512,29 +615,29 @@ end;
|
||||
function TAstVisitor<T>.VisitPipeInput(const Node: IPipeInputNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.StreamSource);
|
||||
Accept(Node.Selectors); // Now visits SelectorList
|
||||
Visit(Node.StreamSource);
|
||||
Visit(Node.Selectors);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitPipeSelectorList(const Node: IPipeSelectorList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitPipeInputList(const Node: IPipeInputList): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
for var Item in Node do
|
||||
Accept(Item);
|
||||
Visit(Item);
|
||||
end;
|
||||
|
||||
function TAstVisitor<T>.VisitPipe(const Node: IPipeNode): T;
|
||||
begin
|
||||
Result := Default(T);
|
||||
Accept(Node.Inputs);
|
||||
Accept(Node.Transformation);
|
||||
Visit(Node.Inputs);
|
||||
Visit(Node.Transformation);
|
||||
end;
|
||||
|
||||
{ TAstTransformer }
|
||||
@@ -580,7 +683,7 @@ begin
|
||||
for i := 0 to Node.Count - 1 do
|
||||
begin
|
||||
item := Node[i];
|
||||
newItem := Accept(item).AsIdentifier;
|
||||
newItem := Visit(item).AsIdentifier;
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -605,7 +708,7 @@ begin
|
||||
for i := 0 to Node.Count - 1 do
|
||||
begin
|
||||
item := Node[i];
|
||||
newItem := Accept(item);
|
||||
newItem := Visit(item);
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -629,7 +732,7 @@ begin
|
||||
for i := 0 to Node.Count - 1 do
|
||||
begin
|
||||
item := Node[i];
|
||||
newItem := Accept(item);
|
||||
newItem := Visit(item);
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -653,8 +756,8 @@ begin
|
||||
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;
|
||||
// Ensure we transform the field node itself via Visit to trigger VisitRecordField
|
||||
newItem := Visit(item).AsRecordField;
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -671,8 +774,8 @@ var
|
||||
newKey: IKeywordNode;
|
||||
newValue: IAstNode;
|
||||
begin
|
||||
newKey := Accept(Node.Key).AsKeyword;
|
||||
newValue := Accept(Node.Value);
|
||||
newKey := Visit(Node.Key).AsKeyword;
|
||||
newValue := Visit(Node.Value);
|
||||
|
||||
if (newKey = Node.Key) and (newValue = Node.Value) then
|
||||
Result := Node
|
||||
@@ -686,9 +789,9 @@ function TAstTransformer.VisitIfExpression(const Node: IIfExpressionNode): IAstN
|
||||
var
|
||||
newCond, newThen, newElse: IAstNode;
|
||||
begin
|
||||
newCond := Accept(Node.Condition);
|
||||
newThen := Accept(Node.ThenBranch);
|
||||
newElse := Accept(Node.ElseBranch);
|
||||
newCond := Visit(Node.Condition);
|
||||
newThen := Visit(Node.ThenBranch);
|
||||
newElse := Visit(Node.ElseBranch);
|
||||
|
||||
if (newCond = Node.Condition) and (newThen = Node.ThenBranch) and (newElse = Node.ElseBranch) then
|
||||
Result := Node
|
||||
@@ -709,15 +812,15 @@ begin
|
||||
|
||||
for i := 0 to High(Node.Pairs) do
|
||||
begin
|
||||
newCond := Accept(Node.Pairs[i].Condition);
|
||||
newBranch := Accept(Node.Pairs[i].Branch);
|
||||
newCond := Visit(Node.Pairs[i].Condition);
|
||||
newBranch := Visit(Node.Pairs[i].Branch);
|
||||
newPairs[i] := TCondPair.Create(newCond, newBranch);
|
||||
|
||||
if (newCond <> Node.Pairs[i].Condition) or (newBranch <> Node.Pairs[i].Branch) then
|
||||
hasChanged := True;
|
||||
end;
|
||||
|
||||
newElse := Accept(Node.ElseBranch); // Accept handles nil
|
||||
newElse := Visit(Node.ElseBranch); // Visit handles nil
|
||||
if newElse <> Node.ElseBranch then
|
||||
hasChanged := True;
|
||||
|
||||
@@ -732,8 +835,8 @@ var
|
||||
newParams: IParameterList;
|
||||
newBody: IAstNode;
|
||||
begin
|
||||
newParams := Accept(Node.Parameters).AsParameterList;
|
||||
newBody := Accept(Node.Body);
|
||||
newParams := Visit(Node.Parameters).AsParameterList;
|
||||
newBody := Visit(Node.Body);
|
||||
|
||||
if (newParams = Node.Parameters) and (newBody = Node.Body) then
|
||||
Result := Node
|
||||
@@ -761,8 +864,8 @@ var
|
||||
newCallee: IAstNode;
|
||||
newArgs: IArgumentList;
|
||||
begin
|
||||
newCallee := Accept(Node.Callee);
|
||||
newArgs := Accept(Node.Arguments).AsArgumentList;
|
||||
newCallee := Visit(Node.Callee);
|
||||
newArgs := Visit(Node.Arguments).AsArgumentList;
|
||||
|
||||
if (newCallee = Node.Callee) and (newArgs = Node.Arguments) then
|
||||
Result := Node
|
||||
@@ -778,7 +881,7 @@ function TAstTransformer.VisitMacroExpansionNode(const Node: IMacroExpansionNode
|
||||
var
|
||||
newBody: IAstNode;
|
||||
begin
|
||||
newBody := Accept(Node.ExpandedBody);
|
||||
newBody := Visit(Node.ExpandedBody);
|
||||
if newBody = Node.ExpandedBody then
|
||||
exit(Node);
|
||||
|
||||
@@ -791,7 +894,7 @@ function TAstTransformer.VisitBlockExpression(const Node: IBlockExpressionNode):
|
||||
var
|
||||
newExprs: IExpressionList;
|
||||
begin
|
||||
newExprs := Accept(Node.Expressions).AsExpressionList;
|
||||
newExprs := Visit(Node.Expressions).AsExpressionList;
|
||||
|
||||
if newExprs = Node.Expressions then
|
||||
Result := Node
|
||||
@@ -805,8 +908,8 @@ var
|
||||
newTarget: IAstNode;
|
||||
newInit: IAstNode;
|
||||
begin
|
||||
newTarget := Accept(Node.Target);
|
||||
newInit := Accept(Node.Initializer);
|
||||
newTarget := Visit(Node.Target);
|
||||
newInit := Visit(Node.Initializer);
|
||||
|
||||
if (newTarget = Node.Target) and (newInit = Node.Initializer) then
|
||||
Result := Node
|
||||
@@ -821,8 +924,8 @@ var
|
||||
newTarget: IAstNode;
|
||||
newValue: IAstNode;
|
||||
begin
|
||||
newTarget := Accept(Node.Target);
|
||||
newValue := Accept(Node.Value);
|
||||
newTarget := Visit(Node.Target);
|
||||
newValue := Visit(Node.Value);
|
||||
|
||||
if (newTarget = Node.Target) and (newValue = Node.Value) then
|
||||
Result := Node
|
||||
@@ -841,7 +944,7 @@ function TAstTransformer.VisitQuasiquote(const Node: IQuasiquoteNode): IAstNode;
|
||||
var
|
||||
newExpr: IAstNode;
|
||||
begin
|
||||
newExpr := Accept(Node.Expression);
|
||||
newExpr := Visit(Node.Expression);
|
||||
if newExpr = Node.Expression then
|
||||
Result := Node
|
||||
else
|
||||
@@ -852,7 +955,7 @@ function TAstTransformer.VisitUnquote(const Node: IUnquoteNode): IAstNode;
|
||||
var
|
||||
newExpr: IAstNode;
|
||||
begin
|
||||
newExpr := Accept(Node.Expression);
|
||||
newExpr := Visit(Node.Expression);
|
||||
if newExpr = Node.Expression then
|
||||
Result := Node
|
||||
else
|
||||
@@ -863,7 +966,7 @@ function TAstTransformer.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode):
|
||||
var
|
||||
newExpr: IAstNode;
|
||||
begin
|
||||
newExpr := Accept(Node.Expression);
|
||||
newExpr := Visit(Node.Expression);
|
||||
|
||||
if (newExpr = Node.Expression) then
|
||||
Result := Node
|
||||
@@ -875,8 +978,8 @@ function TAstTransformer.VisitIndexer(const Node: IIndexerNode): IAstNode;
|
||||
var
|
||||
newBase, newIndex: IAstNode;
|
||||
begin
|
||||
newBase := Accept(Node.Base);
|
||||
newIndex := Accept(Node.Index);
|
||||
newBase := Visit(Node.Base);
|
||||
newIndex := Visit(Node.Index);
|
||||
|
||||
if (newBase = Node.Base) and (newIndex = Node.Index) then
|
||||
Result := Node
|
||||
@@ -889,8 +992,8 @@ var
|
||||
newBase: IAstNode;
|
||||
newMember: IKeywordNode;
|
||||
begin
|
||||
newBase := Accept(Node.Base);
|
||||
newMember := Accept(Node.Member).AsKeyword;
|
||||
newBase := Visit(Node.Base);
|
||||
newMember := Visit(Node.Member).AsKeyword;
|
||||
|
||||
if (newBase = Node.Base) and (newMember = Node.Member) then
|
||||
Result := Node
|
||||
@@ -902,7 +1005,7 @@ function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAs
|
||||
var
|
||||
newFields: IRecordFieldList;
|
||||
begin
|
||||
newFields := Accept(Node.Fields).AsRecordFieldList;
|
||||
newFields := Visit(Node.Fields).AsRecordFieldList;
|
||||
|
||||
if newFields = Node.Fields then
|
||||
Result := Node
|
||||
@@ -917,9 +1020,9 @@ var
|
||||
newSeries: IIdentifierNode;
|
||||
newValue, newLookback: IAstNode;
|
||||
begin
|
||||
newSeries := Accept(Node.Series).AsIdentifier;
|
||||
newValue := Accept(Node.Value);
|
||||
newLookback := Accept(Node.Lookback);
|
||||
newSeries := Visit(Node.Series).AsIdentifier;
|
||||
newValue := Visit(Node.Value);
|
||||
newLookback := Visit(Node.Lookback);
|
||||
|
||||
if (newSeries = Node.Series) and (newValue = Node.Value) and (newLookback = Node.Lookback) then
|
||||
Result := Node
|
||||
@@ -931,7 +1034,7 @@ function TAstTransformer.VisitSeriesLength(const Node: ISeriesLengthNode): IAstN
|
||||
var
|
||||
newSeries: IIdentifierNode;
|
||||
begin
|
||||
newSeries := Accept(Node.Series).AsIdentifier;
|
||||
newSeries := Visit(Node.Series).AsIdentifier;
|
||||
|
||||
if newSeries = Node.Series then
|
||||
Result := Node
|
||||
@@ -943,7 +1046,7 @@ function TAstTransformer.VisitRecurNode(const Node: IRecurNode): IAstNode;
|
||||
var
|
||||
newArgs: IArgumentList;
|
||||
begin
|
||||
newArgs := Accept(Node.Arguments).AsArgumentList;
|
||||
newArgs := Visit(Node.Arguments).AsArgumentList;
|
||||
|
||||
if newArgs = Node.Arguments then
|
||||
Result := Node
|
||||
@@ -956,8 +1059,8 @@ var
|
||||
newSource: IIdentifierNode;
|
||||
newSels: IPipeSelectorList;
|
||||
begin
|
||||
newSource := Accept(Node.StreamSource).AsIdentifier;
|
||||
newSels := Accept(Node.Selectors).AsPipeSelectorList;
|
||||
newSource := Visit(Node.StreamSource).AsIdentifier;
|
||||
newSels := Visit(Node.Selectors).AsPipeSelectorList;
|
||||
|
||||
if (newSource = Node.StreamSource) and (newSels = Node.Selectors) then
|
||||
Result := Node
|
||||
@@ -977,7 +1080,7 @@ begin
|
||||
for i := 0 to Node.Count - 1 do
|
||||
begin
|
||||
item := Node[i];
|
||||
newItem := Accept(item).AsKeyword;
|
||||
newItem := Visit(item).AsKeyword;
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -1002,7 +1105,7 @@ begin
|
||||
for i := 0 to Node.Count - 1 do
|
||||
begin
|
||||
item := Node[i];
|
||||
newItem := Accept(item).AsPipeInput; // Explicit cast via new helper
|
||||
newItem := Visit(item).AsPipeInput; // Explicit cast via new helper
|
||||
newItems[i] := newItem;
|
||||
if item <> newItem then
|
||||
hasChanged := True;
|
||||
@@ -1021,8 +1124,8 @@ var
|
||||
newInputs: IPipeInputList;
|
||||
newTrans: ILambdaExpressionNode;
|
||||
begin
|
||||
newInputs := Accept(Node.Inputs).AsPipeInputList;
|
||||
newTrans := Accept(Node.Transformation).AsLambdaExpression;
|
||||
newInputs := Visit(Node.Inputs).AsPipeInputList;
|
||||
newTrans := Visit(Node.Transformation).AsLambdaExpression;
|
||||
|
||||
if (newInputs = Node.Inputs) and (newTrans = Node.Transformation) then
|
||||
Result := Node
|
||||
|
||||
Reference in New Issue
Block a user