Binder refactoring, Monster refactoring

This commit is contained in:
Michael Schimmel
2025-11-02 19:38:52 +01:00
parent 8f29212cba
commit ea39a57b77
22 changed files with 3061 additions and 2638 deletions
+56 -54
View File
@@ -9,43 +9,44 @@ uses
Myc.Data.Scalar,
Myc.Data.Value,
Myc.Ast.Nodes,
Myc.Ast.Visitor,
Myc.Ast.Binding,
Myc.Ast.Scope;
type
// The standard AST evaluator for production use.
TEvaluatorVisitor = class(TAstVisitor, IEvaluatorVisitor)
// This class inherits directly from TInterfacedObject as it is an
// Interpreter (AST -> TDataValue), not a Transformer (AST -> IAstNode).
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor, IEvaluatorVisitor)
private
FScope: IExecutionScope;
class var
procedure HandleTCO(var ResultValue: TDataValue);
protected
function VisitConstant(const Node: IConstantNode): TDataValue; override;
function VisitIdentifier(const Node: IIdentifierNode): TDataValue; override;
function VisitKeyword(const Node: IKeywordNode): TDataValue; override;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; override;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; override;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; override;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): 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 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 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;
// 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;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; virtual;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; virtual;
function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; virtual;
function VisitTernaryExpression(const Node: ITernaryExpressionNode): 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 IsTruthy(const AValue: TDataValue): Boolean; inline;
@@ -68,11 +69,12 @@ implementation
uses
System.TypInfo,
System.Generics.Defaults,
Myc.Ast, // Added
Myc.Data.Keyword,
Myc.Data.Decimal,
Myc.Data.Series,
Myc.Data.Scalar.JSON,
Myc.Ast.Binding.Nodes;
Myc.Data.Scalar.JSON;
// Myc.Ast.Binding.Nodes; // Removed
// Helper type for TCO via trampolining.
type
@@ -206,7 +208,7 @@ end;
function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
var
boundNode: TBoundLambdaExpressionNode;
boundNode: TLambdaExpressionNode; // Changed
capturedCells: TArray<IValueCell>;
i: Integer;
sourceAddresses: TArray<TResolvedAddress>;
@@ -214,7 +216,7 @@ var
visitorFactory: TEvaluatorFactory;
begin
// Cast to the bound node to access binder-specific information.
boundNode := Node as TBoundLambdaExpressionNode;
boundNode := Node as TLambdaExpressionNode; // Changed
// Create the closure by capturing the value cells of all upvalues from the current scope.
sourceAddresses := boundNode.Upvalues;
@@ -257,13 +259,13 @@ begin
// Capture the closure itself in slot 0 for 'recur' to find it.
adr.SlotIndex := 0;
lambdaScope[adr] := closure;
lambdaScope[adr] := TDataValue(closure); // Explicit cast
// Populate the scope with the actual parameters passed to the function.
for i := 0 to High(ArgValues) do
begin
// Parameters in a bound lambda must be bound identifiers.
adr.SlotIndex := (params[i] as TBoundIdentifierNode).Address.SlotIndex;
adr.SlotIndex := (params[i] as TIdentifierNode).Address.SlotIndex; // Changed
lambdaScope[adr] := ArgValues[i];
end;
@@ -273,7 +275,7 @@ begin
end;
// The result of visiting a lambda node is the callable closure itself.
Result := closure;
Result := TDataValue(closure); // Explicit cast
end;
function TEvaluatorVisitor.VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
@@ -303,7 +305,7 @@ function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDa
var
calleeValue: TDataValue;
argValues: TArray<TDataValue>;
boundNode: TBoundFunctionCallNode;
boundNode: TFunctionCallNode; // Changed
begin
calleeValue := Node.Callee.Accept(Self);
if calleeValue.Kind <> vkMethod then
@@ -314,7 +316,7 @@ begin
for var i := 0 to High(argNodes) do
argValues[i] := argNodes[i].Accept(Self);
boundNode := Node as TBoundFunctionCallNode;
boundNode := Node as TFunctionCallNode; // Changed
if boundNode.IsTailCall then
begin
// This is a tail call. Return a thunk to be processed by the trampoline.
@@ -363,7 +365,7 @@ var
itemValue, lookbackValue, seriesVar: TDataValue;
lookback: Int64;
begin
seriesVar := FScope[(Node.Series as TBoundIdentifierNode).Address];
seriesVar := FScope[(Node.Series as TIdentifierNode).Address]; // Changed
itemValue := Node.Value.Accept(Self);
lookback := -1;
@@ -397,7 +399,7 @@ begin
// Evaluate the new value.
Result := Node.Value.Accept(Self);
// Assign it. The scope's SetValues implementation now handles boxing correctly.
FScope[(Node.Identifier as TBoundIdentifierNode).Address] := Result;
FScope[(Node.Identifier as TIdentifierNode).Address] := Result; // Changed
end;
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): TDataValue;
@@ -408,7 +410,7 @@ end;
function TEvaluatorVisitor.VisitKeyword(const Node: IKeywordNode): TDataValue;
begin
// Return the keyword as a TScalar value
Result := TDataValue(TScalar.FromKeyword(Node.Value));
Result := TDataValue(TScalar.FromKeyword(Node.Value)); // Explicit cast
end;
function TEvaluatorVisitor.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue;
@@ -434,7 +436,7 @@ end;
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): TDataValue;
begin
// The scope's GetValues implementation now handles unboxing automatically.
Result := FScope[(Node as TBoundIdentifierNode).Address];
Result := FScope[(Node as TIdentifierNode).Address]; // Changed
end;
function TEvaluatorVisitor.VisitIndexer(const Node: IIndexerNode): TDataValue;
@@ -458,7 +460,7 @@ begin
series := baseValue.AsSeries;
if (index < 0) or (index >= series.TotalCount) then
raise EArgumentException.CreateFmt('Index %d is out of bounds for series with %d elements.', [index, series.TotalCount]);
Result := series.Items[Integer(index)];
Result := TDataValue(series.Items[Integer(index)]); // Explicit cast
end;
vkRecordSeries:
begin
@@ -487,7 +489,7 @@ begin
case baseValue.Kind of
vkRecordSeries: Result := TDataValue.FromSeries(baseValue.AsRecordSeries[Node.Member.Value]);
vkRecord: Result := baseValue.AsRecord[Node.Member.Value];
vkRecord: Result := TDataValue(baseValue.AsRecord[Node.Member.Value]); // Explicit cast
// --- NEW GENERIC PATH ---
vkGenericRecord:
@@ -509,10 +511,10 @@ var
i: Integer;
begin
// Check which type the binder created
if Node is TBoundGenericRecordLiteralNode then
if Node is TGenericRecordLiteralNode then // Changed
begin
// --- NEW GENERIC PATH ---
var boundNode := Node as TBoundGenericRecordLiteralNode;
var boundNode := Node as TGenericRecordLiteralNode; // Changed
var genFields: TArray<TPair<IKeyword, TDataValue>>;
SetLength(genFields, Length(boundNode.Fields));
@@ -530,10 +532,10 @@ begin
var dynRec := TDynamicRecord.Create(genFields);
Result := TDataValue.FromGenericRecord(dynRec);
end
else if Node is TBoundRecordLiteralNode then
else if Node is TRecordLiteralNode then // Changed
begin
// --- EXISTING SCALAR PATH ---
var boundNode := Node as TBoundRecordLiteralNode;
var boundNode := Node as TRecordLiteralNode; // Changed
var values: TArray<TScalar.TValue>;
SetLength(values, Length(boundNode.Fields));
@@ -554,7 +556,7 @@ end;
function TEvaluatorVisitor.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
var
address: TResolvedAddress;
boundNode: TBoundVariableDeclarationNode;
boundNode: TVariableDeclarationNode; // Changed
begin
// First, evaluate the initializer to get the variable's initial value.
if Assigned(Node.Initializer) then
@@ -562,9 +564,9 @@ begin
else
Result := TDataValue.Void;
// After binding, all declaration nodes are TBoundVariableDeclarationNode
boundNode := Node as TBoundVariableDeclarationNode;
address := (boundNode.Identifier as TBoundIdentifierNode).Address;
// After binding, all declaration nodes are TVariableDeclarationNode
boundNode := Node as TVariableDeclarationNode; // Changed
address := (boundNode.Identifier as TIdentifierNode).Address; // Changed
// Check the IsBoxed flag set by the binder.
if boundNode.IsBoxed then
@@ -599,7 +601,7 @@ begin
+ ' and '
+ rightValue.AsScalar.Kind.ToString
+ ' .');
Result := resScalar;
Result := TDataValue(resScalar); // Explicit cast
end;
function TEvaluatorVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue;
@@ -614,7 +616,7 @@ begin
var res: TScalar;
if not TScalar.TryUnaryOperation(Node.Operator, rightValue.AsScalar, res) then
raise ENotSupportedException.Create('Unary operation not supported for scalar type' + rightValue.AsScalar.Kind.ToString + '.');
Result := res;
Result := TDataValue(res); // Explicit cast
end;
function TEvaluatorVisitor.VisitIfExpression(const Node: IIfExpressionNode): TDataValue;
@@ -649,7 +651,7 @@ var
seriesValue: TDataValue;
len: Int64;
begin
seriesValue := FScope[(Node.Series as TBoundIdentifierNode).Address];
seriesValue := FScope[(Node.Series as TIdentifierNode).Address]; // Changed
case seriesValue.Kind of
vkSeries: len := seriesValue.AsSeries.Count;
@@ -658,7 +660,7 @@ begin
raise EArgumentException.CreateFmt('Cannot get length of type %s.', [GetEnumName(TypeInfo(TDataValueKind), Ord(seriesValue.Kind))]);
end;
Result := TScalar.FromInt64(len);
Result := TDataValue(TScalar.FromInt64(len)); // Explicit cast
end;
end.