470 lines
16 KiB
ObjectPascal
470 lines
16 KiB
ObjectPascal
unit Myc.Ast.Nodes;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Generics.Collections,
|
|
Myc.Data.Scalar;
|
|
|
|
type
|
|
// Operators and helpers
|
|
TBinaryOperator = (boAdd, boSubtract, boMultiply, boDivide, boEqual, boNotEqual, boLess, boGreater, boLessOrEqual, boGreaterOrEqual);
|
|
TUnaryOperator = (uoNegate, uoNot);
|
|
|
|
TBinaryOperatorHelper = record helper for TBinaryOperator
|
|
function ToString: string;
|
|
end;
|
|
|
|
TUnaryOperatorHelper = record helper for TUnaryOperator
|
|
function ToString: string;
|
|
end;
|
|
|
|
// Added avkMemberSeries to represent a TScalarMemberSeries value.
|
|
// Added avkSeries to represent a TScalarSeries value.
|
|
TAstValueKind = (avkUndefined, avkScalar, avkClosure, avkText, avkSeries, avkRecordSeries, avkRecord, avkMemberSeries);
|
|
|
|
// --- Forward Declarations to break cycles ---
|
|
IExecutionScope = interface;
|
|
IAstVisitor = interface;
|
|
IAstNode = interface;
|
|
IExpressionNode = interface;
|
|
IIdentifierNode = interface;
|
|
IConstantNode = interface;
|
|
IBinaryExpressionNode = interface;
|
|
IUnaryExpressionNode = interface;
|
|
IIfExpressionNode = interface;
|
|
ITernaryExpressionNode = interface;
|
|
ILambdaExpressionNode = interface;
|
|
IFunctionCallNode = interface;
|
|
IBlockExpressionNode = interface;
|
|
IVariableDeclarationNode = interface;
|
|
IAssignmentNode = interface;
|
|
IIndexerNode = interface;
|
|
IMemberAccessNode = interface;
|
|
ICreateSeriesNode = interface;
|
|
IAddSeriesItemNode = interface;
|
|
ISeriesLengthNode = interface;
|
|
IEvaluatorClosure = interface;
|
|
|
|
// --- Concrete Type Definitions ---
|
|
|
|
IEvaluatorClosure = interface(IInterface)
|
|
{$region 'private'}
|
|
function GetBody: IExpressionNode;
|
|
function GetParameters: TArray<IIdentifierNode>;
|
|
function GetClosureScope: IExecutionScope;
|
|
{$endregion}
|
|
property Body: IExpressionNode read GetBody;
|
|
property Parameters: TArray<IIdentifierNode> read GetParameters;
|
|
property ClosureScope: IExecutionScope read GetClosureScope;
|
|
end;
|
|
|
|
TAstValue = record
|
|
private
|
|
type
|
|
TVal<T> = class(TInterfacedObject)
|
|
Value: T;
|
|
constructor Create(const AValue: T);
|
|
end;
|
|
|
|
var
|
|
FKind: TAstValueKind;
|
|
FScalar: TScalar;
|
|
FInterface: IInterface;
|
|
function GetKind: TAstValueKind; inline;
|
|
function GetIsVoid: Boolean; inline;
|
|
public
|
|
class operator Initialize(out Dest: TAstValue);
|
|
class function Void: TAstValue; inline; static;
|
|
class function FromScalar(const AValue: TScalar): TAstValue; inline; static;
|
|
class function FromClosure(const AValue: IEvaluatorClosure): TAstValue; inline; static;
|
|
class function FromText(const AValue: String): TAstValue; inline; static;
|
|
class function FromSeries(const [ref] AValue: TScalarSeries): TAstValue; static; inline;
|
|
class function FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TAstValue; static; inline;
|
|
class function FromRecord(const [ref] AValue: TScalarRecord): TAstValue; static; inline;
|
|
class function FromMemberSeries(const [ref] AValue: TScalarMemberSeries): TAstValue; static; inline;
|
|
function AsScalar: TScalar; inline;
|
|
function AsClosure: IEvaluatorClosure; inline;
|
|
function AsText: String; inline;
|
|
function AsRecordSeries: TVal<TScalarRecordSeries>; inline;
|
|
function AsRecord: TScalarRecord; inline;
|
|
function AsMemberSeries: TVal<TScalarMemberSeries>; inline;
|
|
function AsSeries: TVal<TScalarSeries>; inline;
|
|
function ToString: String;
|
|
property IsVoid: Boolean read GetIsVoid;
|
|
property Kind: TAstValueKind read GetKind;
|
|
end;
|
|
|
|
IExecutionScope = interface(IInterface)
|
|
{$region 'private'}
|
|
function GetParent: IExecutionScope;
|
|
{$endregion}
|
|
procedure Clear;
|
|
function FindValue(const Name: string; out Value: TAstValue): Boolean;
|
|
procedure SetValue(const Name: string; const Value: TAstValue);
|
|
procedure AssignValue(const Name: string; const Value: TAstValue);
|
|
function Dump: string;
|
|
property Parent: IExecutionScope read GetParent;
|
|
end;
|
|
|
|
IAstVisitor = interface
|
|
function VisitConstant(const Node: IConstantNode): TAstValue;
|
|
function VisitIdentifier(const Node: IIdentifierNode): TAstValue;
|
|
function VisitBinaryExpression(const Node: IBinaryExpressionNode): TAstValue;
|
|
function VisitUnaryExpression(const Node: IUnaryExpressionNode): TAstValue;
|
|
function VisitIfExpression(const Node: IIfExpressionNode): TAstValue;
|
|
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstValue;
|
|
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstValue;
|
|
function VisitFunctionCall(const Node: IFunctionCallNode): TAstValue;
|
|
function VisitBlockExpression(const Node: IBlockExpressionNode): TAstValue;
|
|
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstValue;
|
|
function VisitAssignment(const Node: IAssignmentNode): TAstValue;
|
|
function VisitIndexer(const Node: IIndexerNode): TAstValue;
|
|
function VisitMemberAccess(const Node: IMemberAccessNode): TAstValue;
|
|
function VisitCreateSeries(const Node: ICreateSeriesNode): TAstValue;
|
|
function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAstValue;
|
|
function VisitSeriesLength(const Node: ISeriesLengthNode): TAstValue;
|
|
end;
|
|
|
|
IAstNode = interface(IInterface)
|
|
function Accept(const Visitor: IAstVisitor): TAstValue;
|
|
end;
|
|
|
|
IExpressionNode = interface(IAstNode)
|
|
end;
|
|
|
|
IConstantNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetValue: TScalar;
|
|
{$endregion}
|
|
property Value: TScalar 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;
|
|
|
|
// Represents an if-statement for control flow.
|
|
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;
|
|
|
|
// Represents a ternary expression (e.g., condition ? true_expr : false_expr) for value selection.
|
|
ITernaryExpressionNode = 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: TArray<IIdentifierNode>;
|
|
function GetBody: IExpressionNode;
|
|
{$endregion}
|
|
property Parameters: TArray<IIdentifierNode> read GetParameters;
|
|
property Body: IExpressionNode 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;
|
|
|
|
IBlockExpressionNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetExpressions: TList<IExpressionNode>;
|
|
{$endregion}
|
|
property Expressions: TList<IExpressionNode> read GetExpressions;
|
|
end;
|
|
|
|
IVariableDeclarationNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetIdentifier: IIdentifierNode;
|
|
function GetInitializer: IExpressionNode;
|
|
{$endregion}
|
|
property Identifier: IIdentifierNode read GetIdentifier;
|
|
property Initializer: IExpressionNode read GetInitializer;
|
|
end;
|
|
|
|
IAssignmentNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetIdentifier: IIdentifierNode;
|
|
function GetValue: IExpressionNode;
|
|
{$endregion}
|
|
property Identifier: IIdentifierNode read GetIdentifier;
|
|
property Value: IExpressionNode read GetValue;
|
|
end;
|
|
|
|
// Represents an index access expression (e.g., series[index]).
|
|
IIndexerNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetBase: IExpressionNode;
|
|
function GetIndex: IExpressionNode;
|
|
{$endregion}
|
|
property Base: IExpressionNode read GetBase;
|
|
property Index: IExpressionNode read GetIndex;
|
|
end;
|
|
|
|
// Represents a member access expression (e.g., series.field or record.field).
|
|
IMemberAccessNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetBase: IExpressionNode;
|
|
function GetMember: IIdentifierNode;
|
|
{$endregion}
|
|
property Base: IExpressionNode read GetBase;
|
|
property Member: IIdentifierNode read GetMember;
|
|
end;
|
|
|
|
// Represents creating a new, empty series (e.g., new series(int)).
|
|
ICreateSeriesNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetDefinition: String;
|
|
{$endregion}
|
|
property Definition: String read GetDefinition;
|
|
end;
|
|
|
|
// Represents adding a value to a series (e.g., my_series.add(value, 100)).
|
|
IAddSeriesItemNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetSeries: IIdentifierNode;
|
|
function GetValue: IExpressionNode;
|
|
function GetLookback: IExpressionNode;
|
|
{$endregion}
|
|
property Series: IIdentifierNode read GetSeries;
|
|
property Value: IExpressionNode read GetValue;
|
|
property Lookback: IExpressionNode read GetLookback;
|
|
end;
|
|
|
|
ISeriesLengthNode = interface(IExpressionNode)
|
|
{$region 'private'}
|
|
function GetSeries: IIdentifierNode;
|
|
{$endregion}
|
|
property Series: IIdentifierNode read GetSeries;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.Classes;
|
|
|
|
{ TAstValue }
|
|
|
|
constructor TAstValue.TVal<T>.Create(const AValue: T);
|
|
begin
|
|
inherited Create;
|
|
Value := AValue;
|
|
end;
|
|
|
|
{ TAstValue }
|
|
|
|
class operator TAstValue.Initialize(out Dest: TAstValue);
|
|
begin
|
|
Dest.FKind := avkUndefined;
|
|
Dest.FInterface := nil;
|
|
end;
|
|
|
|
function TAstValue.AsClosure: IEvaluatorClosure;
|
|
begin
|
|
if (FKind <> avkClosure) then
|
|
raise EInvalidCast.Create('Cannot read value as a Closure.');
|
|
Result := IEvaluatorClosure(FInterface);
|
|
end;
|
|
|
|
function TAstValue.AsMemberSeries: TVal<TScalarMemberSeries>;
|
|
begin
|
|
if (FKind <> avkMemberSeries) then
|
|
raise EInvalidCast.Create('Cannot read value as MemberSeries.');
|
|
Result := TVal<TScalarMemberSeries>(FInterface);
|
|
end;
|
|
|
|
function TAstValue.AsRecord: TScalarRecord;
|
|
begin
|
|
if (FKind <> avkRecord) then
|
|
raise EInvalidCast.Create('Cannot read value as Record.');
|
|
Result := (FInterface as TVal<TScalarRecord>).Value;
|
|
end;
|
|
|
|
function TAstValue.AsRecordSeries: TVal<TScalarRecordSeries>;
|
|
begin
|
|
if (FKind <> avkRecordSeries) then
|
|
raise EInvalidCast.Create('Cannot read value as RecordSeries.');
|
|
Result := TVal<TScalarRecordSeries>(FInterface);
|
|
end;
|
|
|
|
function TAstValue.AsScalar: TScalar;
|
|
begin
|
|
if (FKind <> avkScalar) then
|
|
raise EInvalidCast.Create('Cannot read value as a Scalar.');
|
|
Result := FScalar;
|
|
end;
|
|
|
|
// Added support for TScalarSeries
|
|
function TAstValue.AsSeries: TVal<TScalarSeries>;
|
|
begin
|
|
if (FKind <> avkSeries) then
|
|
raise EInvalidCast.Create('Cannot read value as Series.');
|
|
Result := TVal<TScalarSeries>(FInterface);
|
|
end;
|
|
|
|
function TAstValue.AsText: String;
|
|
begin
|
|
if (FKind <> avkText) then
|
|
raise EInvalidCast.Create('Cannot read value as Text.');
|
|
|
|
Result := (FInterface as TVal<String>).Value;
|
|
end;
|
|
|
|
class function TAstValue.FromClosure(const AValue: IEvaluatorClosure): TAstValue;
|
|
begin
|
|
Result.FKind := avkClosure;
|
|
Result.FInterface := AValue;
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
class function TAstValue.FromMemberSeries(const [ref] AValue: TScalarMemberSeries): TAstValue;
|
|
begin
|
|
Result.FKind := avkMemberSeries;
|
|
Result.FInterface := TVal<TScalarMemberSeries>.Create(AValue);
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
class function TAstValue.FromRecord(const [ref] AValue: TScalarRecord): TAstValue;
|
|
begin
|
|
Result.FKind := avkRecord;
|
|
Result.FInterface := TVal<TScalarRecord>.Create(AValue);
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
class function TAstValue.FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TAstValue;
|
|
begin
|
|
Result.FKind := avkRecordSeries;
|
|
Result.FInterface := TVal<TScalarRecordSeries>.Create(AValue);
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
class function TAstValue.FromScalar(const AValue: TScalar): TAstValue;
|
|
begin
|
|
Result.FKind := avkScalar;
|
|
Result.FScalar := AValue;
|
|
Result.FInterface := nil;
|
|
end;
|
|
|
|
class function TAstValue.FromSeries(const [ref] AValue: TScalarSeries): TAstValue;
|
|
begin
|
|
Result.FKind := avkSeries;
|
|
Result.FInterface := TVal<TScalarSeries>.Create(AValue);
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
class function TAstValue.FromText(const AValue: String): TAstValue;
|
|
begin
|
|
Result.FKind := avkText;
|
|
Result.FInterface := TVal<String>.Create(AValue);
|
|
Result.FScalar := Default(TScalar);
|
|
end;
|
|
|
|
function TAstValue.GetIsVoid: Boolean;
|
|
begin
|
|
Result := FKind = avkUndefined;
|
|
end;
|
|
|
|
function TAstValue.GetKind: TAstValueKind;
|
|
begin
|
|
Result := FKind;
|
|
end;
|
|
|
|
function TAstValue.ToString: String;
|
|
begin
|
|
case FKind of
|
|
avkScalar: Result := FScalar.ToString;
|
|
avkClosure: Result := '<closure>';
|
|
avkText: Result := AsText;
|
|
avkSeries: Result := '<series>';
|
|
avkRecordSeries: Result := '<record_series>';
|
|
avkRecord: Result := '<record>';
|
|
avkMemberSeries: Result := '<member_series>';
|
|
avkUndefined: Result := '<void>';
|
|
else
|
|
Result := '[Unknown AstValue]';
|
|
end;
|
|
end;
|
|
|
|
class function TAstValue.Void: TAstValue;
|
|
begin
|
|
Result := Default(TAstValue);
|
|
end;
|
|
|
|
{ TBinaryOperatorHelper }
|
|
|
|
function TBinaryOperatorHelper.ToString: string;
|
|
begin
|
|
case Self of
|
|
boAdd: Result := '+';
|
|
boSubtract: Result := '-';
|
|
boMultiply: Result := '*';
|
|
boDivide: Result := '/';
|
|
boEqual: Result := '==';
|
|
boNotEqual: Result := '!=';
|
|
boLess: Result := '<';
|
|
boGreater: Result := '>';
|
|
boLessOrEqual: Result := '<=';
|
|
boGreaterOrEqual: Result := '>=';
|
|
else
|
|
Result := '?';
|
|
end;
|
|
end;
|
|
|
|
{ TUnaryOperatorHelper }
|
|
|
|
function TUnaryOperatorHelper.ToString: string;
|
|
begin
|
|
case Self of
|
|
uoNegate: Result := '-';
|
|
uoNot: Result := 'not';
|
|
else
|
|
Result := '?';
|
|
end;
|
|
end;
|
|
|
|
end.
|