1068 lines
32 KiB
ObjectPascal
1068 lines
32 KiB
ObjectPascal
unit Myc.Ast;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
Myc.Data.Scalar,
|
|
Myc.Ast.Nodes;
|
|
|
|
type
|
|
// Record acting as a namespace for the factory functions.
|
|
TAst = record
|
|
// --- Existing factory functions ---
|
|
class function Constant(AValue: TScalar): 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 TernaryExpr(
|
|
const ACondition: IExpressionNode;
|
|
const AThenBranch, AElseBranch: IExpressionNode
|
|
): ITernaryExpressionNode; static;
|
|
class function LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode): ILambdaExpressionNode; static;
|
|
class function FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode; static;
|
|
class function Block(const AExpressions: array of IExpressionNode): IBlockExpressionNode; static;
|
|
class function VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationNode; static;
|
|
class function Assign(const AIdentifier: IIdentifierNode; const AValue: IExpressionNode): IAssignmentNode; static;
|
|
class function AssignResult(const AValue: IExpressionNode): IAssignmentNode; static; deprecated;
|
|
class function Indexer(const ABase: IExpressionNode; const AIndex: IExpressionNode): IIndexerNode; static;
|
|
class function MemberAccess(const ABase: IExpressionNode; const AMember: IIdentifierNode): IMemberAccessNode; static;
|
|
class function CreateSeries(const ADefinition: String): ICreateSeriesNode; static;
|
|
class function AddSeriesItem(
|
|
const ASeries: IIdentifierNode;
|
|
const AValue: IExpressionNode;
|
|
const ALookback: IExpressionNode = nil
|
|
): IAddSeriesItemNode; static;
|
|
class function SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode; static;
|
|
|
|
// --- Static method to run the binder ---
|
|
// Traverses the AST and resolves all identifiers. This must be called before evaluating the AST.
|
|
class procedure Bind(const ARootNode: IExpressionNode); static;
|
|
end;
|
|
|
|
// TAstTraverser provides a default AST traversal implementation.
|
|
TAstTraverser = class abstract(TInterfacedObject, IAstVisitor)
|
|
public
|
|
function VisitConstant(const Node: IConstantNode): TAstValue; virtual;
|
|
function VisitIdentifier(const Node: IIdentifierNode): TAstValue; virtual;
|
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue; virtual;
|
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue; virtual;
|
|
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue; virtual;
|
|
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue; virtual;
|
|
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; virtual;
|
|
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue; virtual;
|
|
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; virtual;
|
|
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue; virtual;
|
|
function VisitAssignment(const Node: IAssignmentNode): TAstValue; virtual;
|
|
function VisitIndexer(const Node: IIndexerNode): TAstValue; virtual;
|
|
function VisitMemberAccess(const Node: IMemberAccessNode): TAstValue; virtual;
|
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TAstValue; virtual;
|
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAstValue; virtual;
|
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TAstValue; virtual;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.Classes,
|
|
System.Generics.Collections;
|
|
|
|
type
|
|
{ TAstNode }
|
|
// Common base class for AST nodes to reduce boilerplate.
|
|
TAstNode = class(TInterfacedObject, IExpressionNode)
|
|
public
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; virtual; abstract;
|
|
end;
|
|
|
|
{ TConstantNode }
|
|
TConstantNode = class(TAstNode, IConstantNode)
|
|
private
|
|
FValue: TScalar;
|
|
function GetValue: TScalar;
|
|
public
|
|
constructor Create(AValue: TScalar);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TIdentifierNode }
|
|
// TIdentifierNode now includes fields for binder annotations.
|
|
TIdentifierNode = class(TAstNode, IIdentifierNode)
|
|
private
|
|
FName: string;
|
|
// --- Annotation fields added for the binder ---
|
|
FIsResolved: Boolean;
|
|
FScopeDepth: Integer;
|
|
FSlotIndex: Integer;
|
|
function GetName: string;
|
|
public
|
|
constructor Create(AName: string);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
|
|
function Resolve(out ScopeDepth: Integer; out SlotIndex: Integer): Boolean;
|
|
|
|
property Name: string read FName;
|
|
end;
|
|
|
|
{ TBinaryExpressionNode }
|
|
TBinaryExpressionNode = class(TAstNode, 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): TAstValue; override;
|
|
end;
|
|
|
|
{ TUnaryExpressionNode }
|
|
TUnaryExpressionNode = class(TAstNode, IUnaryExpressionNode)
|
|
private
|
|
FOperator: TUnaryOperator;
|
|
FRight: IExpressionNode;
|
|
function GetOperator: TUnaryOperator;
|
|
function GetRight: IExpressionNode;
|
|
public
|
|
constructor Create(const AOperator: TUnaryOperator; const ARight: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TIfExpressionNode }
|
|
TIfExpressionNode = class(TAstNode, IIfExpressionNode)
|
|
private
|
|
FCondition: IExpressionNode;
|
|
FThenBranch: IExpressionNode;
|
|
FElseBranch: IExpressionNode;
|
|
function GetCondition: IExpressionNode;
|
|
function GetThenBranch: IExpressionNode;
|
|
function GetElseBranch: IExpressionNode;
|
|
public
|
|
constructor Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TTernaryExpressionNode }
|
|
TTernaryExpressionNode = class(TAstNode, ITernaryExpressionNode)
|
|
private
|
|
FCondition: IExpressionNode;
|
|
FThenBranch: IExpressionNode;
|
|
FElseBranch: IExpressionNode;
|
|
function GetCondition: IExpressionNode;
|
|
function GetThenBranch: IExpressionNode;
|
|
function GetElseBranch: IExpressionNode;
|
|
public
|
|
constructor Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TLambdaExpressionNode }
|
|
TLambdaExpressionNode = class(TAstNode, ILambdaExpressionNode)
|
|
private
|
|
FParameters: TArray<IIdentifierNode>;
|
|
FBody: IExpressionNode;
|
|
function GetParameters: TArray<IIdentifierNode>;
|
|
function GetBody: IExpressionNode;
|
|
public
|
|
constructor Create(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TFunctionCallNode }
|
|
TFunctionCallNode = class(TAstNode, IFunctionCallNode)
|
|
private
|
|
FCallee: IExpressionNode;
|
|
FArguments: TList<IExpressionNode>;
|
|
function GetCallee: IExpressionNode;
|
|
function GetArguments: TList<IExpressionNode>;
|
|
public
|
|
constructor Create(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode);
|
|
destructor Destroy; override;
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TBlockExpressionNode }
|
|
TBlockExpressionNode = class(TAstNode, IBlockExpressionNode)
|
|
private
|
|
FExpressions: TList<IExpressionNode>;
|
|
function GetExpressions: TList<IExpressionNode>;
|
|
public
|
|
constructor Create(const AExpressions: array of IExpressionNode);
|
|
destructor Destroy; override;
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TVariableDeclarationNode }
|
|
TVariableDeclarationNode = class(TAstNode, IVariableDeclarationNode)
|
|
private
|
|
FIdentifier: IIdentifierNode;
|
|
FInitializer: IExpressionNode;
|
|
function GetIdentifier: IIdentifierNode;
|
|
function GetInitializer: IExpressionNode;
|
|
public
|
|
constructor Create(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TAssignmentNode }
|
|
TAssignmentNode = class(TAstNode, IAssignmentNode)
|
|
private
|
|
FIdentifier: IIdentifierNode;
|
|
FValue: IExpressionNode;
|
|
function GetIdentifier: IIdentifierNode;
|
|
function GetValue: IExpressionNode;
|
|
public
|
|
constructor Create(const AIdentifier: IIdentifierNode; const AValue: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TIndexerNode }
|
|
TIndexerNode = class(TAstNode, IIndexerNode)
|
|
private
|
|
FBase: IExpressionNode;
|
|
FIndex: IExpressionNode;
|
|
function GetBase: IExpressionNode;
|
|
function GetIndex: IExpressionNode;
|
|
public
|
|
constructor Create(const ABase: IExpressionNode; const AIndex: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TMemberAccessNode }
|
|
TMemberAccessNode = class(TAstNode, IMemberAccessNode)
|
|
private
|
|
FBase: IExpressionNode;
|
|
FMember: IIdentifierNode;
|
|
function GetBase: IExpressionNode;
|
|
function GetMember: IIdentifierNode;
|
|
public
|
|
constructor Create(const ABase: IExpressionNode; const AMember: IIdentifierNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TCreateSeriesNode }
|
|
TCreateSeriesNode = class(TAstNode, ICreateSeriesNode)
|
|
private
|
|
FDefinition: String;
|
|
function GetDefinition: String;
|
|
public
|
|
constructor Create(const ADefinition: String);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TAddSeriesItemNode }
|
|
TAddSeriesItemNode = class(TAstNode, IAddSeriesItemNode)
|
|
private
|
|
FSeries: IIdentifierNode;
|
|
FValue: IExpressionNode;
|
|
FLookback: IExpressionNode;
|
|
function GetSeries: IIdentifierNode;
|
|
function GetValue: IExpressionNode;
|
|
function GetLookback: IExpressionNode;
|
|
public
|
|
constructor Create(const ASeries: IIdentifierNode; const AValue: IExpressionNode; const ALookback: IExpressionNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
{ TSeriesLengthNode }
|
|
TSeriesLengthNode = class(TAstNode, ISeriesLengthNode)
|
|
private
|
|
FSeries: IIdentifierNode;
|
|
function GetSeries: IIdentifierNode;
|
|
public
|
|
constructor Create(const ASeries: IIdentifierNode);
|
|
function Accept(const Visitor: IAstVisitor): TAstValue; override;
|
|
end;
|
|
|
|
// --- Binder Implementation ---
|
|
|
|
TSymbol = record
|
|
Name: string;
|
|
SlotIndex: Integer;
|
|
end;
|
|
|
|
TSymbolTable = class
|
|
private
|
|
FParent: TSymbolTable;
|
|
FSymbols: TDictionary<string, TSymbol>;
|
|
FNextSlotIndex: Integer;
|
|
public
|
|
constructor Create(AParent: TSymbolTable);
|
|
destructor Destroy; override;
|
|
function Define(const Name: string): TSymbol;
|
|
function Resolve(const Name: string; out Symbol: TSymbol; out Depth: Integer): Boolean;
|
|
end;
|
|
|
|
// TBinder inherits from the base traverser and overrides methods with specific binding logic.
|
|
TBinder = class(TAstTraverser)
|
|
private
|
|
FCurrentScope: TSymbolTable;
|
|
procedure EnterScope;
|
|
procedure ExitScope;
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function VisitIdentifier(const Node: IIdentifierNode): TAstValue; override;
|
|
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue; override;
|
|
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue; override;
|
|
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue; override;
|
|
end;
|
|
|
|
{ TConstantNode }
|
|
|
|
constructor TConstantNode.Create(AValue: TScalar);
|
|
begin
|
|
inherited Create;
|
|
FValue := AValue;
|
|
end;
|
|
|
|
function TConstantNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitConstant(Self);
|
|
end;
|
|
|
|
function TConstantNode.GetValue: TScalar;
|
|
begin
|
|
Result := FValue;
|
|
end;
|
|
|
|
{ TIdentifierNode }
|
|
|
|
constructor TIdentifierNode.Create(AName: string);
|
|
begin
|
|
inherited Create;
|
|
FName := AName;
|
|
FIsResolved := False;
|
|
FScopeDepth := -1;
|
|
FSlotIndex := -1;
|
|
end;
|
|
|
|
function TIdentifierNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitIdentifier(Self);
|
|
end;
|
|
|
|
function TIdentifierNode.GetName: string;
|
|
begin
|
|
Result := FName;
|
|
end;
|
|
|
|
function TIdentifierNode.Resolve(out ScopeDepth: Integer; out SlotIndex: Integer): Boolean;
|
|
begin
|
|
Result := FIsResolved;
|
|
if Result then
|
|
begin
|
|
ScopeDepth := FScopeDepth;
|
|
SlotIndex := FSlotIndex;
|
|
end;
|
|
end;
|
|
|
|
{ TBinaryExpressionNode }
|
|
|
|
constructor TBinaryExpressionNode.Create(ALeft: IExpressionNode; AOperator: TBinaryOperator; ARight: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FLeft := ALeft;
|
|
FOperator := AOperator;
|
|
FRight := ARight;
|
|
end;
|
|
|
|
function TBinaryExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitBinaryExpression(Self);
|
|
end;
|
|
|
|
function TBinaryExpressionNode.GetLeft: IExpressionNode;
|
|
begin
|
|
Result := FLeft;
|
|
end;
|
|
|
|
function TBinaryExpressionNode.GetOperator: TBinaryOperator;
|
|
begin
|
|
Result := FOperator;
|
|
end;
|
|
|
|
function TBinaryExpressionNode.GetRight: IExpressionNode;
|
|
begin
|
|
Result := FRight;
|
|
end;
|
|
|
|
{ TUnaryExpressionNode }
|
|
|
|
constructor TUnaryExpressionNode.Create(const AOperator: TUnaryOperator; const ARight: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FOperator := AOperator;
|
|
FRight := ARight;
|
|
end;
|
|
|
|
function TUnaryExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitUnaryExpression(Self);
|
|
end;
|
|
|
|
function TUnaryExpressionNode.GetOperator: TUnaryOperator;
|
|
begin
|
|
Result := FOperator;
|
|
end;
|
|
|
|
function TUnaryExpressionNode.GetRight: IExpressionNode;
|
|
begin
|
|
Result := FRight;
|
|
end;
|
|
|
|
{ TIfExpressionNode }
|
|
|
|
constructor TIfExpressionNode.Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FCondition := ACondition;
|
|
FThenBranch := AThenBranch;
|
|
FElseBranch := AElseBranch;
|
|
end;
|
|
|
|
function TIfExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitIfExpression(Self);
|
|
end;
|
|
|
|
function TIfExpressionNode.GetCondition: IExpressionNode;
|
|
begin
|
|
Result := FCondition;
|
|
end;
|
|
|
|
function TIfExpressionNode.GetElseBranch: IExpressionNode;
|
|
begin
|
|
Result := FElseBranch;
|
|
end;
|
|
|
|
function TIfExpressionNode.GetThenBranch: IExpressionNode;
|
|
begin
|
|
Result := FThenBranch;
|
|
end;
|
|
|
|
{ TTernaryExpressionNode }
|
|
|
|
constructor TTernaryExpressionNode.Create(const ACondition, AThenBranch, AElseBranch: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FCondition := ACondition;
|
|
FThenBranch := AThenBranch;
|
|
FElseBranch := AElseBranch;
|
|
end;
|
|
|
|
function TTernaryExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitTernaryExpression(Self);
|
|
end;
|
|
|
|
function TTernaryExpressionNode.GetCondition: IExpressionNode;
|
|
begin
|
|
Result := FCondition;
|
|
end;
|
|
|
|
function TTernaryExpressionNode.GetElseBranch: IExpressionNode;
|
|
begin
|
|
Result := FElseBranch;
|
|
end;
|
|
|
|
function TTernaryExpressionNode.GetThenBranch: IExpressionNode;
|
|
begin
|
|
Result := FThenBranch;
|
|
end;
|
|
|
|
{ TLambdaExpressionNode }
|
|
|
|
constructor TLambdaExpressionNode.Create(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FBody := ABody;
|
|
FParameters := AParameters;
|
|
end;
|
|
|
|
function TLambdaExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitLambdaExpression(Self);
|
|
end;
|
|
|
|
function TLambdaExpressionNode.GetBody: IExpressionNode;
|
|
begin
|
|
Result := FBody;
|
|
end;
|
|
|
|
function TLambdaExpressionNode.GetParameters: TArray<IIdentifierNode>;
|
|
begin
|
|
Result := FParameters;
|
|
end;
|
|
|
|
{ TFunctionCallNode }
|
|
|
|
constructor TFunctionCallNode.Create(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode);
|
|
var
|
|
arg: IExpressionNode;
|
|
begin
|
|
inherited Create;
|
|
FCallee := ACallee;
|
|
FArguments := TList<IExpressionNode>.Create;
|
|
for arg in AArguments do
|
|
FArguments.Add(arg);
|
|
end;
|
|
|
|
destructor TFunctionCallNode.Destroy;
|
|
begin
|
|
FArguments.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TFunctionCallNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitFunctionCall(Self);
|
|
end;
|
|
|
|
function TFunctionCallNode.GetArguments: TList<IExpressionNode>;
|
|
begin
|
|
Result := FArguments;
|
|
end;
|
|
|
|
function TFunctionCallNode.GetCallee: IExpressionNode;
|
|
begin
|
|
Result := FCallee;
|
|
end;
|
|
|
|
{ TBlockExpressionNode }
|
|
|
|
constructor TBlockExpressionNode.Create(const AExpressions: array of IExpressionNode);
|
|
var
|
|
expr: IExpressionNode;
|
|
begin
|
|
inherited Create;
|
|
FExpressions := TList<IExpressionNode>.Create;
|
|
for expr in AExpressions do
|
|
FExpressions.Add(expr);
|
|
end;
|
|
|
|
destructor TBlockExpressionNode.Destroy;
|
|
begin
|
|
FExpressions.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TBlockExpressionNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitBlockExpression(Self);
|
|
end;
|
|
|
|
function TBlockExpressionNode.GetExpressions: TList<IExpressionNode>;
|
|
begin
|
|
Result := FExpressions;
|
|
end;
|
|
|
|
{ TVariableDeclarationNode }
|
|
|
|
constructor TVariableDeclarationNode.Create(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FIdentifier := AIdentifier;
|
|
FInitializer := AInitializer;
|
|
end;
|
|
|
|
function TVariableDeclarationNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitVariableDeclaration(Self);
|
|
end;
|
|
|
|
function TVariableDeclarationNode.GetIdentifier: IIdentifierNode;
|
|
begin
|
|
Result := FIdentifier;
|
|
end;
|
|
|
|
function TVariableDeclarationNode.GetInitializer: IExpressionNode;
|
|
begin
|
|
Result := FInitializer;
|
|
end;
|
|
|
|
{ TAssignmentNode }
|
|
|
|
constructor TAssignmentNode.Create(const AIdentifier: IIdentifierNode; const AValue: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FIdentifier := AIdentifier;
|
|
FValue := AValue;
|
|
end;
|
|
|
|
function TAssignmentNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitAssignment(Self);
|
|
end;
|
|
|
|
function TAssignmentNode.GetIdentifier: IIdentifierNode;
|
|
begin
|
|
Result := FIdentifier;
|
|
end;
|
|
|
|
function TAssignmentNode.GetValue: IExpressionNode;
|
|
begin
|
|
Result := FValue;
|
|
end;
|
|
|
|
{ TIndexerNode }
|
|
|
|
constructor TIndexerNode.Create(const ABase, AIndex: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FBase := ABase;
|
|
FIndex := AIndex;
|
|
end;
|
|
|
|
function TIndexerNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitIndexer(Self);
|
|
end;
|
|
|
|
function TIndexerNode.GetBase: IExpressionNode;
|
|
begin
|
|
Result := FBase;
|
|
end;
|
|
|
|
function TIndexerNode.GetIndex: IExpressionNode;
|
|
begin
|
|
Result := FIndex;
|
|
end;
|
|
|
|
{ TMemberAccessNode }
|
|
|
|
constructor TMemberAccessNode.Create(const ABase: IExpressionNode; const AMember: IIdentifierNode);
|
|
begin
|
|
inherited Create;
|
|
FBase := ABase;
|
|
FMember := AMember;
|
|
end;
|
|
|
|
function TMemberAccessNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitMemberAccess(Self);
|
|
end;
|
|
|
|
function TMemberAccessNode.GetBase: IExpressionNode;
|
|
begin
|
|
Result := FBase;
|
|
end;
|
|
|
|
function TMemberAccessNode.GetMember: IIdentifierNode;
|
|
begin
|
|
Result := FMember;
|
|
end;
|
|
|
|
{ TCreateSeriesNode }
|
|
|
|
constructor TCreateSeriesNode.Create(const ADefinition: String);
|
|
begin
|
|
inherited Create;
|
|
FDefinition := ADefinition;
|
|
end;
|
|
|
|
function TCreateSeriesNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitCreateSeries(Self);
|
|
end;
|
|
|
|
function TCreateSeriesNode.GetDefinition: String;
|
|
begin
|
|
Result := FDefinition;
|
|
end;
|
|
|
|
{ TAddSeriesItemNode }
|
|
|
|
constructor TAddSeriesItemNode.Create(const ASeries: IIdentifierNode; const AValue, ALookback: IExpressionNode);
|
|
begin
|
|
inherited Create;
|
|
FSeries := ASeries;
|
|
FValue := AValue;
|
|
FLookback := ALookback;
|
|
end;
|
|
|
|
function TAddSeriesItemNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitAddSeriesItem(Self);
|
|
end;
|
|
|
|
function TAddSeriesItemNode.GetLookback: IExpressionNode;
|
|
begin
|
|
Result := FLookback;
|
|
end;
|
|
|
|
function TAddSeriesItemNode.GetSeries: IIdentifierNode;
|
|
begin
|
|
Result := FSeries;
|
|
end;
|
|
|
|
function TAddSeriesItemNode.GetValue: IExpressionNode;
|
|
begin
|
|
Result := FValue;
|
|
end;
|
|
|
|
{ TSeriesLengthNode }
|
|
|
|
constructor TSeriesLengthNode.Create(const ASeries: IIdentifierNode);
|
|
begin
|
|
inherited Create;
|
|
FSeries := ASeries;
|
|
end;
|
|
|
|
function TSeriesLengthNode.Accept(const Visitor: IAstVisitor): TAstValue;
|
|
begin
|
|
Result := Visitor.VisitSeriesLength(Self);
|
|
end;
|
|
|
|
function TSeriesLengthNode.GetSeries: IIdentifierNode;
|
|
begin
|
|
Result := FSeries;
|
|
end;
|
|
|
|
{ TSymbolTable }
|
|
|
|
constructor TSymbolTable.Create(AParent: TSymbolTable);
|
|
begin
|
|
inherited Create;
|
|
FParent := AParent;
|
|
FSymbols := TDictionary<string, TSymbol>.Create;
|
|
FNextSlotIndex := 0;
|
|
end;
|
|
|
|
destructor TSymbolTable.Destroy;
|
|
begin
|
|
FSymbols.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TSymbolTable.Define(const Name: string): TSymbol;
|
|
begin
|
|
Result.Name := Name;
|
|
Result.SlotIndex := FNextSlotIndex;
|
|
inc(FNextSlotIndex);
|
|
FSymbols.Add(Name, Result);
|
|
end;
|
|
|
|
function TSymbolTable.Resolve(const Name: string; out Symbol: TSymbol; out Depth: Integer): Boolean;
|
|
var
|
|
currentScope: TSymbolTable;
|
|
begin
|
|
Depth := 0;
|
|
currentScope := Self;
|
|
while Assigned(currentScope) do
|
|
begin
|
|
if currentScope.FSymbols.TryGetValue(Name, Symbol) then
|
|
Exit(True);
|
|
|
|
inc(Depth);
|
|
currentScope := currentScope.FParent;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
{ TBinder }
|
|
|
|
constructor TBinder.Create;
|
|
begin
|
|
inherited;
|
|
FCurrentScope := TSymbolTable.Create(nil); // Start with a global scope
|
|
end;
|
|
|
|
destructor TBinder.Destroy;
|
|
begin
|
|
Assert(not Assigned(FCurrentScope.FParent), 'Scope leak in binder.');
|
|
FCurrentScope.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TBinder.EnterScope;
|
|
begin
|
|
FCurrentScope := TSymbolTable.Create(FCurrentScope);
|
|
end;
|
|
|
|
procedure TBinder.ExitScope;
|
|
var
|
|
oldScope: TSymbolTable;
|
|
begin
|
|
oldScope := FCurrentScope;
|
|
FCurrentScope := FCurrentScope.FParent;
|
|
oldScope.Free;
|
|
end;
|
|
|
|
function TBinder.VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
|
|
begin
|
|
EnterScope;
|
|
try
|
|
// Default traversal of all expressions in the block
|
|
inherited VisitBlockExpression(Node);
|
|
finally
|
|
ExitScope;
|
|
end;
|
|
end;
|
|
|
|
function TBinder.VisitIdentifier(const Node: IIdentifierNode): TAstValue;
|
|
var
|
|
symbol: TSymbol;
|
|
depth: Integer;
|
|
identNode: TIdentifierNode;
|
|
begin
|
|
identNode := Node as TIdentifierNode;
|
|
if identNode.FIsResolved then
|
|
Exit;
|
|
|
|
if FCurrentScope.Resolve(identNode.Name, symbol, depth) then
|
|
begin
|
|
identNode.FIsResolved := True;
|
|
identNode.FScopeDepth := depth;
|
|
identNode.FSlotIndex := symbol.SlotIndex;
|
|
end
|
|
else
|
|
raise Exception.CreateFmt('Undefined identifier: "%s"', [identNode.Name]);
|
|
end;
|
|
|
|
function TBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
|
|
var
|
|
param: IIdentifierNode;
|
|
begin
|
|
EnterScope;
|
|
try
|
|
// 1. Define all parameters in the new scope.
|
|
for param in Node.Parameters do
|
|
FCurrentScope.Define(param.Name);
|
|
|
|
// 2. Now visit the parameter identifiers to resolve them to their new definitions,
|
|
// and visit the body to resolve its identifiers.
|
|
inherited VisitLambdaExpression(Node);
|
|
finally
|
|
ExitScope;
|
|
end;
|
|
end;
|
|
|
|
function TBinder.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue;
|
|
begin
|
|
// 1. First, visit the initializer expression to resolve its identifiers.
|
|
if Assigned(Node.Initializer) then
|
|
Node.Initializer.Accept(Self);
|
|
|
|
// 2. Then, define the new variable in the current scope.
|
|
FCurrentScope.Define(Node.Identifier.Name);
|
|
|
|
// 3. Finally, visit the declaration's own identifier to resolve it.
|
|
Node.Identifier.Accept(Self);
|
|
end;
|
|
|
|
{ TAst }
|
|
|
|
class procedure TAst.Bind(const ARootNode: IExpressionNode);
|
|
var
|
|
binder: IAstVisitor;
|
|
begin
|
|
binder := TBinder.Create;
|
|
ARootNode.Accept(binder);
|
|
end;
|
|
|
|
class function TAst.AddSeriesItem(
|
|
const ASeries: IIdentifierNode;
|
|
const AValue: IExpressionNode;
|
|
const ALookback: IExpressionNode
|
|
): IAddSeriesItemNode;
|
|
begin
|
|
Result := TAddSeriesItemNode.Create(ASeries, AValue, ALookback);
|
|
end;
|
|
|
|
class function TAst.Assign(const AIdentifier: IIdentifierNode; const AValue: IExpressionNode): IAssignmentNode;
|
|
begin
|
|
Result := TAssignmentNode.Create(AIdentifier, AValue);
|
|
end;
|
|
|
|
class function TAst.AssignResult(const AValue: IExpressionNode): IAssignmentNode;
|
|
begin
|
|
Result := Assign(TAst.Identifier('Result'), AValue);
|
|
end;
|
|
|
|
class function TAst.Block(const AExpressions: array of IExpressionNode): IBlockExpressionNode;
|
|
begin
|
|
Result := TBlockExpressionNode.Create(AExpressions);
|
|
end;
|
|
|
|
class function TAst.Constant(AValue: TScalar): IConstantNode;
|
|
begin
|
|
Result := TConstantNode.Create(AValue);
|
|
end;
|
|
|
|
class function TAst.CreateSeries(const ADefinition: String): ICreateSeriesNode;
|
|
begin
|
|
Result := TCreateSeriesNode.Create(ADefinition);
|
|
end;
|
|
|
|
class function TAst.BinaryExpr(ALeft: IExpressionNode; AOperator: TBinaryOperator; ARight: IExpressionNode): IBinaryExpressionNode;
|
|
begin
|
|
Result := TBinaryExpressionNode.Create(ALeft, AOperator, ARight);
|
|
end;
|
|
|
|
class function TAst.FunctionCall(const ACallee: IExpressionNode; const AArguments: array of IExpressionNode): IFunctionCallNode;
|
|
begin
|
|
Result := TFunctionCallNode.Create(ACallee, AArguments);
|
|
end;
|
|
|
|
class function TAst.Identifier(AName: string): IIdentifierNode;
|
|
begin
|
|
Result := TIdentifierNode.Create(AName);
|
|
end;
|
|
|
|
class function TAst.IfExpr(const ACondition: IExpressionNode; const AThenBranch, AElseBranch: IExpressionNode): IIfExpressionNode;
|
|
begin
|
|
Result := TIfExpressionNode.Create(ACondition, AThenBranch, AElseBranch);
|
|
end;
|
|
|
|
class function TAst.Indexer(const ABase, AIndex: IExpressionNode): IIndexerNode;
|
|
begin
|
|
Result := TIndexerNode.Create(ABase, AIndex);
|
|
end;
|
|
|
|
class function TAst.MemberAccess(const ABase: IExpressionNode; const AMember: IIdentifierNode): IMemberAccessNode;
|
|
begin
|
|
Result := TMemberAccessNode.Create(ABase, AMember);
|
|
end;
|
|
|
|
class function TAst.SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode;
|
|
begin
|
|
Result := TSeriesLengthNode.Create(ASeries);
|
|
end;
|
|
|
|
class function TAst.TernaryExpr(const ACondition: IExpressionNode; const AThenBranch, AElseBranch: IExpressionNode): ITernaryExpressionNode;
|
|
begin
|
|
Result := TTernaryExpressionNode.Create(ACondition, AThenBranch, AElseBranch);
|
|
end;
|
|
|
|
class function TAst.LambdaExpr(const AParameters: TArray<IIdentifierNode>; const ABody: IExpressionNode): ILambdaExpressionNode;
|
|
begin
|
|
Result := TLambdaExpressionNode.Create(AParameters, ABody);
|
|
end;
|
|
|
|
class function TAst.UnaryExpr(const AOperator: TUnaryOperator; const ARight: IExpressionNode): IUnaryExpressionNode;
|
|
begin
|
|
Result := TUnaryExpressionNode.Create(AOperator, ARight);
|
|
end;
|
|
|
|
class function TAst.VarDecl(const AIdentifier: IIdentifierNode; AInitializer: IExpressionNode): IVariableDeclarationNode;
|
|
begin
|
|
Result := TVariableDeclarationNode.Create(AIdentifier, AInitializer);
|
|
end;
|
|
|
|
{ TAstTraverser }
|
|
|
|
function TAstTraverser.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAstValue;
|
|
begin
|
|
Node.Series.Accept(Self);
|
|
Node.Value.Accept(Self);
|
|
if Assigned(Node.Lookback) then
|
|
Node.Lookback.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitAssignment(const Node: IAssignmentNode): TAstValue;
|
|
begin
|
|
Node.Value.Accept(Self);
|
|
Node.Identifier.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue;
|
|
begin
|
|
Node.Left.Accept(Self);
|
|
Node.Right.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
|
|
var
|
|
expr: IExpressionNode;
|
|
begin
|
|
for expr in Node.Expressions do
|
|
expr.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitConstant(const Node: IConstantNode): TAstValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitCreateSeries(const Node: ICreateSeriesNode): TAstValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
|
|
var
|
|
arg: IExpressionNode;
|
|
begin
|
|
Node.Callee.Accept(Self);
|
|
for arg in Node.Arguments do
|
|
arg.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitIdentifier(const Node: IIdentifierNode): TAstValue;
|
|
begin
|
|
end;
|
|
|
|
function TAstTraverser.VisitIfExpression(const Node: IIfExpressionNode): TAstValue;
|
|
begin
|
|
Node.Condition.Accept(Self);
|
|
Node.ThenBranch.Accept(Self);
|
|
if Assigned(Node.ElseBranch) then
|
|
Node.ElseBranch.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitIndexer(const Node: IIndexerNode): TAstValue;
|
|
begin
|
|
Node.Base.Accept(Self);
|
|
Node.Index.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
|
|
var
|
|
param: IIdentifierNode;
|
|
begin
|
|
for param in Node.Parameters do
|
|
param.Accept(Self);
|
|
Node.Body.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitMemberAccess(const Node: IMemberAccessNode): TAstValue;
|
|
begin
|
|
// Do not visit the member identifier, as it's not a variable in the current scope.
|
|
Node.Base.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitSeriesLength(const Node: ISeriesLengthNode): TAstValue;
|
|
begin
|
|
Node.Series.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
|
|
begin
|
|
Node.Condition.Accept(Self);
|
|
Node.ThenBranch.Accept(Self);
|
|
Node.ElseBranch.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue;
|
|
begin
|
|
Node.Right.Accept(Self);
|
|
end;
|
|
|
|
function TAstTraverser.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue;
|
|
begin
|
|
if Assigned(Node.Initializer) then
|
|
Node.Initializer.Accept(Self);
|
|
Node.Identifier.Accept(Self);
|
|
end;
|
|
|
|
end.
|