Files
MycLib/Src/AST/Myc.Ast.pas
T
2025-08-27 16:05:13 +02:00

889 lines
29 KiB
ObjectPascal

unit Myc.Ast;
interface
uses
System.SysUtils,
System.Generics.Collections,
Myc.Data.Types;
type
// Operators are now type-safe enums
TBinaryOperator = (boAdd, boSubtract, boMultiply, boDivide);
TUnaryOperator = (uoNegate, uoNot);
// Forward declarations for interfaces
IAstVisitor = interface;
IAstNode = interface;
IExpressionNode = interface;
IStatementNode = interface;
IConstantNode = interface;
IIdentifierNode = interface;
IBinaryExpressionNode = interface;
IUnaryExpressionNode = interface;
IIfExpressionNode = interface;
ILambdaExpressionNode = interface;
IFunctionCallNode = interface;
IBlockStatementNode = interface;
IVariableDeclarationStatementNode = interface;
IExpressionStatementNode = interface;
// --- Abstract Node Interfaces ---
// Base interface for all AST nodes
IAstNode = interface(IInterface)
// Accept is a function that returns the result of the visit.
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
// Abstract interface for all nodes that evaluate to a value.
IExpressionNode = interface(IAstNode)
end;
// Abstract interface for all nodes that perform an action.
IStatementNode = interface(IAstNode)
end;
// --- Concrete Expression Node Interfaces ---
IConstantNode = interface(IExpressionNode)
{$region 'private'}
function GetValue: IDataValue;
{$endregion}
property Value: IDataValue read GetValue;
end;
IIdentifierNode = interface(IExpressionNode)
{$region 'private'}
function GetName: string;
{$endregion}
property Name: string read GetName;
end;
IBinaryExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetLeft: IExpressionNode;
function GetOperator: TBinaryOperator;
function GetRight: IExpressionNode;
{$endregion}
property Left: IExpressionNode read GetLeft;
property Operator: TBinaryOperator read GetOperator;
property Right: IExpressionNode read GetRight;
end;
IUnaryExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetOperator: TUnaryOperator;
function GetRight: IExpressionNode;
{$endregion}
property Operator: TUnaryOperator read GetOperator;
property Right: IExpressionNode read GetRight;
end;
IIfExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetCondition: IExpressionNode;
function GetThenBranch: IExpressionNode;
function GetElseBranch: IExpressionNode;
{$endregion}
property Condition: IExpressionNode read GetCondition;
property ThenBranch: IExpressionNode read GetThenBranch;
property ElseBranch: IExpressionNode read GetElseBranch;
end;
ILambdaExpressionNode = interface(IExpressionNode)
{$region 'private'}
function GetParameters: TList<IIdentifierNode>;
function GetBody: IAstNode; // Can be an expression or a block statement
{$endregion}
property Parameters: TList<IIdentifierNode> read GetParameters;
property Body: IAstNode read GetBody;
end;
IFunctionCallNode = interface(IExpressionNode)
{$region 'private'}
function GetCallee: IExpressionNode;
function GetArguments: TList<IExpressionNode>;
{$endregion}
property Callee: IExpressionNode read GetCallee;
property Arguments: TList<IExpressionNode> read GetArguments;
end;
// --- Concrete Statement Node Interfaces ---
IBlockStatementNode = interface(IStatementNode)
{$region 'private'}
function GetStatements: TList<IStatementNode>;
{$endregion}
property Statements: TList<IStatementNode> read GetStatements;
end;
IVariableDeclarationStatementNode = interface(IStatementNode)
{$region 'private'}
function GetIdentifier: IIdentifierNode;
function GetInitializer: IExpressionNode; // Can be nil
{$endregion}
property Identifier: IIdentifierNode read GetIdentifier;
property Initializer: IExpressionNode read GetInitializer;
end;
IExpressionStatementNode = interface(IStatementNode)
{$region 'private'}
function GetExpression: IExpressionNode;
{$endregion}
property Expression: IExpressionNode read GetExpression;
end;
// All visitor methods are functions returning a value.
IAstVisitor = interface
['{5F4110E9-0158-41E9-A512-E57A843E8A5A}']
// Expression visitors
function VisitConstant(const Node: IConstantNode): IDataValue;
function VisitIdentifier(const Node: IIdentifierNode): IDataValue;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): IDataValue;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): IDataValue;
function VisitIfExpression(const Node: IIfExpressionNode): IDataValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IDataValue;
function VisitFunctionCall(const Node: IFunctionCallNode): IDataValue;
// Statement visitors
function VisitBlockStatement(const Node: IBlockStatementNode): IDataValue;
function VisitVariableDeclarationStatement(const Node: IVariableDeclarationStatementNode): IDataValue;
function VisitExpressionStatement(const Node: IExpressionStatementNode): IDataValue;
end;
// Record acting as a namespace for the factory functions.
TAst = record
// Expressions
class function Constant(AValue: IDataValue): IConstantNode; static;
class function Identifier(AName: string): IIdentifierNode; static;
class function BinaryExpr(
ALeft: IExpressionNode;
AOperator: TBinaryOperator;
ARight: IExpressionNode
): IBinaryExpressionNode; static;
class function UnaryExpr(const AOperator: TUnaryOperator; const ARight: IExpressionNode): IUnaryExpressionNode; static;
class function IfExpr(
const ACondition: IExpressionNode;
const AThenBranch, AElseBranch: IExpressionNode
): IIfExpressionNode; static;
class function LambdaExpr(const AParameters: array of IIdentifierNode; const ABody: IAstNode): ILambdaExpressionNode; static;
class function FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode; static;
// Statements
class function Block(const AStatements: array of IStatementNode): IBlockStatementNode; static;
class function VarDecl(
const AIdentifier: IIdentifierNode;
AInitializer: IExpressionNode
): IVariableDeclarationStatementNode; static;
class function ExprStmt(const AExpression: IExpressionNode): IExpressionStatementNode; static;
end;
// Manages the scope of execution, holding variables and their values.
TExecutionScope = class
private
FParent: TExecutionScope;
FVariables: TDictionary<string, IDataValue>;
public
constructor Create(AParent: TExecutionScope = nil);
destructor Destroy; override;
function FindValue(const Name: string; out Value: IDataValue): Boolean;
procedure SetValue(const Name: string; const Value: IDataValue);
end;
// TEvaluatorVisitor is stateless and thread-safe.
TEvaluatorVisitor = class(TInterfacedObject, IAstVisitor)
private
FScope: TExecutionScope;
function IsTruthy(const AValue: IDataValue): Boolean;
public
constructor Create(AScope: TExecutionScope);
// Expression visitors
function VisitConstant(const Node: IConstantNode): IDataValue;
function VisitIdentifier(const Node: IIdentifierNode): IDataValue;
function VisitBinaryExpression(const Node: IBinaryExpressionNode): IDataValue;
function VisitUnaryExpression(const Node: IUnaryExpressionNode): IDataValue;
function VisitIfExpression(const Node: IIfExpressionNode): IDataValue;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IDataValue;
function VisitFunctionCall(const Node: IFunctionCallNode): IDataValue;
// Statement visitors
function VisitBlockStatement(const Node: IBlockStatementNode): IDataValue;
function VisitVariableDeclarationStatement(const Node: IVariableDeclarationStatementNode): IDataValue;
function VisitExpressionStatement(const Node: IExpressionStatementNode): IDataValue;
end;
implementation
type
TConstantNodeImpl = class(TInterfacedObject, IConstantNode)
private
FValue: IDataValue;
function GetValue: IDataValue;
public
constructor Create(AValue: IDataValue);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TIdentifierNodeImpl = class(TInterfacedObject, IIdentifierNode)
private
FName: string;
function GetName: string;
public
constructor Create(AName: string);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TBinaryExpressionNodeImpl = class(TInterfacedObject, IBinaryExpressionNode)
private
FLeft: IExpressionNode;
FOperator: TBinaryOperator;
FRight: IExpressionNode;
function GetLeft: IExpressionNode;
function GetOperator: TBinaryOperator;
function GetRight: IExpressionNode;
public
constructor Create(ALeft: IExpressionNode; AOperator: TBinaryOperator; ARight: IExpressionNode);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TUnaryExpressionNodeImpl = class(TInterfacedObject, IUnaryExpressionNode)
private
FOperator: TUnaryOperator;
FRight: IExpressionNode;
function GetOperator: TUnaryOperator;
function GetRight: IExpressionNode;
public
constructor Create(AOperator: TUnaryOperator; ARight: IExpressionNode);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TIfExpressionNodeImpl = class(TInterfacedObject, IIfExpressionNode)
private
FCondition: IExpressionNode;
FThenBranch: IExpressionNode;
FElseBranch: IExpressionNode;
function GetCondition: IExpressionNode;
function GetThenBranch: IExpressionNode;
function GetElseBranch: IExpressionNode;
public
constructor Create(ACondition, AThenBranch, AElseBranch: IExpressionNode);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TLambdaExpressionNodeImpl = class(TInterfacedObject, ILambdaExpressionNode)
private
FParameters: TList<IIdentifierNode>;
FBody: IAstNode;
function GetParameters: TList<IIdentifierNode>;
function GetBody: IAstNode;
public
constructor Create(AParameters: TList<IIdentifierNode>; ABody: IAstNode);
destructor Destroy; override;
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TFunctionCallNodeImpl = class(TInterfacedObject, IFunctionCallNode)
private
FCallee: IExpressionNode;
FArguments: TList<IExpressionNode>;
function GetCallee: IExpressionNode;
function GetArguments: TList<IExpressionNode>;
public
constructor Create(ACallee: IExpressionNode; AArguments: TList<IExpressionNode>);
destructor Destroy; override;
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TBlockStatementNodeImpl = class(TInterfacedObject, IBlockStatementNode)
private
FStatements: TList<IStatementNode>;
function GetStatements: TList<IStatementNode>;
public
constructor Create(AStatements: TList<IStatementNode>);
destructor Destroy; override;
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TVariableDeclarationStatementNodeImpl = class(TInterfacedObject, IVariableDeclarationStatementNode)
private
FIdentifier: IIdentifierNode;
FInitializer: IExpressionNode;
function GetIdentifier: IIdentifierNode;
function GetInitializer: IExpressionNode;
public
constructor Create(AIdentifier: IIdentifierNode; AInitializer: IExpressionNode);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
TExpressionStatementNodeImpl = class(TInterfacedObject, IExpressionStatementNode)
private
FExpression: IExpressionNode;
function GetExpression: IExpressionNode;
public
constructor Create(AExpression: IExpressionNode);
function Accept(const Visitor: IAstVisitor): IDataValue;
end;
{ TAst - Factory Function Implementations }
class function TAst.Constant(AValue: IDataValue): IConstantNode;
begin
Result := TConstantNodeImpl.Create(AValue);
end;
class function TAst.Identifier(AName: string): IIdentifierNode;
begin
Result := TIdentifierNodeImpl.Create(AName);
end;
class function TAst.BinaryExpr(ALeft: IExpressionNode; AOperator: TBinaryOperator; ARight: IExpressionNode): IBinaryExpressionNode;
begin
Result := TBinaryExpressionNodeImpl.Create(ALeft, AOperator, ARight);
end;
class function TAst.UnaryExpr(const AOperator: TUnaryOperator; const ARight: IExpressionNode): IUnaryExpressionNode;
begin
Result := TUnaryExpressionNodeImpl.Create(AOperator, ARight);
end;
class function TAst.IfExpr(const ACondition: IExpressionNode; const AThenBranch, AElseBranch: IExpressionNode): IIfExpressionNode;
begin
Result := TIfExpressionNodeImpl.Create(ACondition, AThenBranch, AElseBranch);
end;
class function TAst.LambdaExpr(const AParameters: array of IIdentifierNode; const ABody: IAstNode): ILambdaExpressionNode;
var
paramList: TList<IIdentifierNode>;
param: IIdentifierNode;
begin
paramList := TList<IIdentifierNode>.Create;
for param in AParameters do
paramList.Add(param);
Result := TLambdaExpressionNodeImpl.Create(paramList, ABody);
end;
class function TAst.FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode;
var
argList: TList<IExpressionNode>;
arg: IExpressionNode;
begin
argList := TList<IExpressionNode>.Create;
for arg in AArguments do
argList.Add(arg);
Result := TFunctionCallNodeImpl.Create(ACallee, argList);
end;
class function TAst.Block(const AStatements: array of IStatementNode): IBlockStatementNode;
var
stmtList: TList<IStatementNode>;
stmt: IStatementNode;
begin
stmtList := TList<IStatementNode>.Create;
for stmt in AStatements do
stmtList.Add(stmt);
Result := TBlockStatementNodeImpl.Create(stmtList);
end;
class function TAst.VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationStatementNode;
begin
Result := TVariableDeclarationStatementNodeImpl.Create(AIdentifier, AInitializer);
end;
class function TAst.ExprStmt(const AExpression: IExpressionNode): IExpressionStatementNode;
begin
Result := TExpressionStatementNodeImpl.Create(AExpression);
end;
{ TConstantNodeImpl }
constructor TConstantNodeImpl.Create(AValue: IDataValue);
begin
inherited Create;
FValue := AValue;
end;
function TConstantNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitConstant(Self);
end;
function TConstantNodeImpl.GetValue: IDataValue;
begin
Result := FValue;
end;
{ TIdentifierNodeImpl }
constructor TIdentifierNodeImpl.Create(AName: string);
begin
inherited Create;
FName := AName;
end;
function TIdentifierNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitIdentifier(Self);
end;
function TIdentifierNodeImpl.GetName: string;
begin
Result := FName;
end;
{ TBinaryExpressionNodeImpl }
constructor TBinaryExpressionNodeImpl.Create(ALeft: IExpressionNode; AOperator: TBinaryOperator; ARight: IExpressionNode);
begin
inherited Create;
FLeft := ALeft;
FOperator := AOperator;
FRight := ARight;
end;
function TBinaryExpressionNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitBinaryExpression(Self);
end;
function TBinaryExpressionNodeImpl.GetLeft: IExpressionNode;
begin
Result := FLeft;
end;
function TBinaryExpressionNodeImpl.GetOperator: TBinaryOperator;
begin
Result := FOperator;
end;
function TBinaryExpressionNodeImpl.GetRight: IExpressionNode;
begin
Result := FRight;
end;
{ TUnaryExpressionNodeImpl }
constructor TUnaryExpressionNodeImpl.Create(AOperator: TUnaryOperator; ARight: IExpressionNode);
begin
inherited Create;
FOperator := AOperator;
FRight := ARight;
end;
function TUnaryExpressionNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitUnaryExpression(Self);
end;
function TUnaryExpressionNodeImpl.GetOperator: TUnaryOperator;
begin
Result := FOperator;
end;
function TUnaryExpressionNodeImpl.GetRight: IExpressionNode;
begin
Result := FRight;
end;
{ TIfExpressionNodeImpl }
constructor TIfExpressionNodeImpl.Create(ACondition, AThenBranch, AElseBranch: IExpressionNode);
begin
inherited Create;
FCondition := ACondition;
FThenBranch := AThenBranch;
FElseBranch := AElseBranch;
end;
function TIfExpressionNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitIfExpression(Self);
end;
function TIfExpressionNodeImpl.GetCondition: IExpressionNode;
begin
Result := FCondition;
end;
function TIfExpressionNodeImpl.GetElseBranch: IExpressionNode;
begin
Result := FElseBranch;
end;
function TIfExpressionNodeImpl.GetThenBranch: IExpressionNode;
begin
Result := FThenBranch;
end;
{ TLambdaExpressionNodeImpl }
constructor TLambdaExpressionNodeImpl.Create(AParameters: TList<IIdentifierNode>; ABody: IAstNode);
begin
inherited Create;
FParameters := AParameters;
FBody := ABody;
end;
destructor TLambdaExpressionNodeImpl.Destroy;
begin
FParameters.Free;
inherited Destroy;
end;
function TLambdaExpressionNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitLambdaExpression(Self);
end;
function TLambdaExpressionNodeImpl.GetBody: IAstNode;
begin
Result := FBody;
end;
function TLambdaExpressionNodeImpl.GetParameters: TList<IIdentifierNode>;
begin
Result := FParameters;
end;
{ TFunctionCallNodeImpl }
constructor TFunctionCallNodeImpl.Create(ACallee: IExpressionNode; AArguments: TList<IExpressionNode>);
begin
inherited Create;
FCallee := ACallee;
FArguments := AArguments;
end;
destructor TFunctionCallNodeImpl.Destroy;
begin
FArguments.Free;
inherited Destroy;
end;
function TFunctionCallNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitFunctionCall(Self);
end;
function TFunctionCallNodeImpl.GetArguments: TList<IExpressionNode>;
begin
Result := FArguments;
end;
function TFunctionCallNodeImpl.GetCallee: IExpressionNode;
begin
Result := FCallee;
end;
{ TBlockStatementNodeImpl }
constructor TBlockStatementNodeImpl.Create(AStatements: TList<IStatementNode>);
begin
inherited Create;
FStatements := AStatements;
end;
destructor TBlockStatementNodeImpl.Destroy;
begin
FStatements.Free;
inherited Destroy;
end;
function TBlockStatementNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitBlockStatement(Self);
end;
function TBlockStatementNodeImpl.GetStatements: TList<IStatementNode>;
begin
Result := FStatements;
end;
{ TVariableDeclarationStatementNodeImpl }
constructor TVariableDeclarationStatementNodeImpl.Create(AIdentifier: IIdentifierNode; AInitializer: IExpressionNode);
begin
inherited Create;
FIdentifier := AIdentifier;
FInitializer := AInitializer;
end;
function TVariableDeclarationStatementNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitVariableDeclarationStatement(Self);
end;
function TVariableDeclarationStatementNodeImpl.GetIdentifier: IIdentifierNode;
begin
Result := FIdentifier;
end;
function TVariableDeclarationStatementNodeImpl.GetInitializer: IExpressionNode;
begin
Result := FInitializer;
end;
{ TExpressionStatementNodeImpl }
constructor TExpressionStatementNodeImpl.Create(AExpression: IExpressionNode);
begin
inherited Create;
FExpression := AExpression;
end;
function TExpressionStatementNodeImpl.Accept(const Visitor: IAstVisitor): IDataValue;
begin
Result := Visitor.VisitExpressionStatement(Self);
end;
function TExpressionStatementNodeImpl.GetExpression: IExpressionNode;
begin
Result := FExpression;
end;
{ TExecutionScope }
constructor TExecutionScope.Create(AParent: TExecutionScope = nil);
begin
inherited Create;
FParent := AParent;
FVariables := TDictionary<string, IDataValue>.Create;
end;
destructor TExecutionScope.Destroy;
begin
FVariables.Free;
inherited Destroy;
end;
function TExecutionScope.FindValue(const Name: string; out Value: IDataValue): Boolean;
begin
Result := FVariables.TryGetValue(Name, Value);
if not Result and Assigned(FParent) then
begin
Result := FParent.FindValue(Name, Value);
end;
end;
procedure TExecutionScope.SetValue(const Name: string; const Value: IDataValue);
begin
// This defines a variable in the current scope. It can shadow a parent variable.
FVariables.AddOrSetValue(Name, Value);
end;
{ TEvaluatorVisitor }
constructor TEvaluatorVisitor.Create(AScope: TExecutionScope);
begin
inherited Create;
Assert(Assigned(AScope));
FScope := AScope;
end;
function TEvaluatorVisitor.IsTruthy(const AValue: IDataValue): Boolean;
begin
// Defines the language's concept of "truthiness".
// For now, only ordinals can be conditions. 0 is false, everything else is true.
if not Assigned(AValue) then
Exit(False);
case AValue.DataType.Kind of
dkOrdinal: Result := (TDataType.TValue(AValue).AsOrdinal.Value <> 0);
else
Result := False;
end;
end;
function TEvaluatorVisitor.VisitConstant(const Node: IConstantNode): IDataValue;
begin
Result := Node.Value;
end;
function TEvaluatorVisitor.VisitIdentifier(const Node: IIdentifierNode): IDataValue;
var
val: IDataValue;
begin
if FScope.FindValue(Node.Name, val) then
Result := val
else
raise EArgumentException.CreateFmt('Identifier not found: "%s"', [Node.Name]);
end;
function TEvaluatorVisitor.VisitBinaryExpression(const Node: IBinaryExpressionNode): IDataValue;
var
leftValue, rightValue: IDataValue;
begin
leftValue := Node.Left.Accept(Self);
rightValue := Node.Right.Accept(Self);
if (leftValue.DataType.Kind <> rightValue.DataType.Kind) then
raise ENotSupportedException.CreateFmt(
'Binary operations on different types (%s and %s) are not supported',
[leftValue.DataType.Name, rightValue.DataType.Name]);
case leftValue.DataType.Kind of
dkOrdinal:
begin
var leftOrdinal := TDataType.TValue(leftValue).AsOrdinal;
var rightOrdinal := TDataType.TValue(rightValue).AsOrdinal;
var resultVal: Int64;
case Node.Operator of
boAdd: resultVal := leftOrdinal.Value + rightOrdinal.Value;
boSubtract: resultVal := leftOrdinal.Value - rightOrdinal.Value;
boMultiply: resultVal := leftOrdinal.Value * rightOrdinal.Value;
boDivide: resultVal := leftOrdinal.Value div rightOrdinal.Value;
else
raise ENotSupportedException.Create('Operator not supported for Ordinal type');
end;
Result := TDataType.Ordinal.CreateValue(resultVal);
end;
dkText:
begin
if (Node.Operator = boAdd) then
begin
var leftText := TDataType.TValue(leftValue).AsText;
var rightText := TDataType.TValue(rightValue).AsText;
Result := TDataType.Text.CreateValue(leftText.Value + rightText.Value);
end
else
raise ENotSupportedException.Create('Operator not supported for Text type');
end;
else
raise ENotSupportedException.CreateFmt('Binary operation not supported for type %s', [leftValue.DataType.Name]);
end;
end;
function TEvaluatorVisitor.VisitUnaryExpression(const Node: IUnaryExpressionNode): IDataValue;
var
rightValue: IDataValue;
ordinalVal: IDataOrdinalValue;
begin
rightValue := Node.Right.Accept(Self);
case Node.Operator of
uoNegate:
begin
if (rightValue.DataType.Kind = dkOrdinal) then
begin
ordinalVal := TDataType.TValue(rightValue).AsOrdinal;
Result := TDataType.Ordinal.CreateValue(-ordinalVal.Value);
end
else
raise ENotSupportedException.CreateFmt('Unary "-" not supported for type %s', [rightValue.DataType.Name]);
end;
uoNot: raise ENotImplemented.Create('Unary "not" operator is not yet implemented');
else
raise ENotSupportedException.Create('Unary operator not supported');
end;
end;
function TEvaluatorVisitor.VisitIfExpression(const Node: IIfExpressionNode): IDataValue;
var
conditionValue: IDataValue;
begin
conditionValue := Node.Condition.Accept(Self);
if IsTruthy(conditionValue) then
Result := Node.ThenBranch.Accept(Self)
else
Result := Node.ElseBranch.Accept(Self);
end;
function TEvaluatorVisitor.VisitLambdaExpression(const Node: ILambdaExpressionNode): IDataValue;
var
lambdaBody: IAstNode;
lambdaParams: TList<IIdentifierNode>;
closureScope: TExecutionScope;
methodType: IDataMethodType;
begin
closureScope := FScope;
lambdaBody := Node.Body;
lambdaParams := Node.Parameters;
methodType := TDataType.MethodOf(TDataType.Ordinal, TDataType.Ordinal);
Result :=
methodType.CreateValue(
function(const AValue: IDataValue): IDataValue
var
callScope: TExecutionScope;
innerVisitor: IAstVisitor;
begin
callScope := TExecutionScope.Create(closureScope);
try
if (lambdaParams.Count <> 1) then
raise EArgumentException.Create('This simple implementation only supports single-parameter lambdas.');
callScope.SetValue(lambdaParams[0].Name, AValue);
innerVisitor := TEvaluatorVisitor.Create(callScope);
Result := lambdaBody.Accept(innerVisitor);
finally
callScope.Free;
end;
end
);
end;
function TEvaluatorVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IDataValue;
var
calleeValue, argValue: IDataValue;
methodProc: TDataMethodProc;
arguments: TList<IExpressionNode>;
begin
calleeValue := Node.Callee.Accept(Self);
if (calleeValue.DataType.Kind <> dkMethod) then
raise EArgumentException.Create('Expression is not callable.');
arguments := Node.Arguments;
if (arguments.Count <> 1) then
raise EArgumentException.Create('This simple implementation only supports single-argument calls.');
argValue := arguments[0].Accept(Self);
methodProc := TDataType.TValue(calleeValue).AsMethod.Value;
Result := methodProc(argValue);
end;
// --- Statement Visitor Implementations ---
function TEvaluatorVisitor.VisitBlockStatement(const Node: IBlockStatementNode): IDataValue;
var
statement: IStatementNode;
begin
// Execute all statements in the block sequentially.
for statement in Node.Statements do
begin
statement.Accept(Self); // The result is ignored.
end;
Result := TDataType.Void.Value;
end;
function TEvaluatorVisitor.VisitVariableDeclarationStatement(const Node: IVariableDeclarationStatementNode): IDataValue;
var
varName: string;
initValue: IDataValue;
begin
varName := Node.Identifier.Name;
// Evaluate the initializer expression, if it exists.
if Assigned(Node.Initializer) then
initValue := Node.Initializer.Accept(Self)
else
initValue := TDataType.Void.Value; // Default value if no initializer is provided.
// Define the variable in the current scope.
FScope.SetValue(varName, initValue);
Result := TDataType.Void.Value;
end;
function TEvaluatorVisitor.VisitExpressionStatement(const Node: IExpressionStatementNode): IDataValue;
begin
// Evaluate the expression for its side-effects and discard the result.
Node.Expression.Accept(Self);
Result := TDataType.Void.Value;
end;
end.