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 --- IAstVisitor = interface; IAstNode = 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; IExecutionScope = interface; IScopeDescriptor = interface; IValueCell = interface; // --- Concrete Type Definitions --- TAstValue = record type IClosure = interface {$region 'private'} function GetBody: IAstNode; function GetClosureScope: IExecutionScope; function GetParameters: TArray; function GetUpvalues: TArray; {$endregion} property Body: IAstNode read GetBody; property ClosureScope: IExecutionScope read GetClosureScope; property Parameters: TArray read GetParameters; property Upvalues: TArray read GetUpvalues; end; TVal = class(TInterfacedObject) Value: T; constructor Create(const AValue: T); end; private 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 operator Implicit(const AValue: TScalar): TAstValue; overload; inline; class operator Implicit(const AValue: TAstValue.IClosure): TAstValue; overload; inline; class operator Implicit(const AValue: String): TAstValue; overload; inline; 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: TAstValue.IClosure; inline; function AsText: String; inline; function AsRecordSeries: TVal; inline; function AsRecord: TScalarRecord; inline; function AsMemberSeries: TVal; inline; function AsSeries: TVal; inline; function ToString: String; property IsVoid: Boolean read GetIsVoid; property Kind: TAstValueKind read GetKind; end; // A managed, reference-counted cell that holds a TAstValue, // allowing it to be shared by reference between scopes (for closures). IValueCell = interface {$region 'private'} function GetValue: TAstValue; procedure SetValue(const AValue: TAstValue); {$endregion} property Value: TAstValue read GetValue write SetValue; end; // Defines how an identifier's address was resolved. TAddressKind = (akUnresolved, akLocalOrParent, akUpvalue); TResolvedAddress = record Kind: TAddressKind; ScopeDepth: Integer; SlotIndex: Integer; constructor Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer); class operator Initialize(out Dest: TResolvedAddress); end; IExecutionScope = interface {$region 'private'} function GetParent: IExecutionScope; function GetCell(const Address: TResolvedAddress): IValueCell; {$endregion} procedure Define(const Name: string; const Value: TAstValue); function Dump: string; procedure Clear; property Cell[const Address: TResolvedAddress]: IValueCell read GetCell; default; property Parent: IExecutionScope read GetParent; end; IScopeDescriptor = interface {$region 'private'} function GetParent: IScopeDescriptor; function GetSlotCount: Integer; function GetSymbols: TDictionary; {$endregion} function CreateScope(const AParent: IExecutionScope): IExecutionScope; property Parent: IScopeDescriptor read GetParent; property SlotCount: Integer read GetSlotCount; property Symbols: TDictionary read GetSymbols; 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; IConstantNode = interface(IAstNode) {$region 'private'} function GetValue: TScalar; {$endregion} property Value: TScalar read GetValue; end; IIdentifierNode = interface(IAstNode) {$region 'private'} function GetIsResolved: Boolean; function GetAddress: TResolvedAddress; function GetName: string; {$endregion} property Name: string read GetName; property IsResolved: Boolean read GetIsResolved; property Address: TResolvedAddress read GetAddress; end; IBinaryExpressionNode = interface(IAstNode) {$region 'private'} function GetLeft: IAstNode; function GetOperator: TBinaryOperator; function GetRight: IAstNode; {$endregion} property Left: IAstNode read GetLeft; property Operator: TBinaryOperator read GetOperator; property Right: IAstNode read GetRight; end; IUnaryExpressionNode = interface(IAstNode) {$region 'private'} function GetOperator: TUnaryOperator; function GetRight: IAstNode; {$endregion} property Operator: TUnaryOperator read GetOperator; property Right: IAstNode read GetRight; end; // Represents an if-statement for control flow. IIfExpressionNode = interface(IAstNode) {$region 'private'} function GetCondition: IAstNode; function GetThenBranch: IAstNode; function GetElseBranch: IAstNode; {$endregion} property Condition: IAstNode read GetCondition; property ThenBranch: IAstNode read GetThenBranch; property ElseBranch: IAstNode read GetElseBranch; end; // Represents a ternary expression (e.g., condition ? true_expr : false_expr) for value selection. ITernaryExpressionNode = interface(IAstNode) {$region 'private'} function GetCondition: IAstNode; function GetThenBranch: IAstNode; function GetElseBranch: IAstNode; {$endregion} property Condition: IAstNode read GetCondition; property ThenBranch: IAstNode read GetThenBranch; property ElseBranch: IAstNode read GetElseBranch; end; ILambdaExpressionNode = interface(IAstNode) {$region 'private'} function GetParameters: TArray; function GetBody: IAstNode; function GetScopeDescriptor: IScopeDescriptor; function GetUpvalues: TArray; {$endregion} property Parameters: TArray read GetParameters; property Body: IAstNode read GetBody; property ScopeDescriptor: IScopeDescriptor read GetScopeDescriptor; property Upvalues: TArray read GetUpvalues; end; IFunctionCallNode = interface(IAstNode) {$region 'private'} function GetCallee: IAstNode; function GetArguments: TList; {$endregion} property Callee: IAstNode read GetCallee; property Arguments: TList read GetArguments; end; IBlockExpressionNode = interface(IAstNode) {$region 'private'} function GetExpressions: TList; {$endregion} property Expressions: TList read GetExpressions; end; IVariableDeclarationNode = interface(IAstNode) {$region 'private'} function GetIdentifier: IIdentifierNode; function GetInitializer: IAstNode; {$endregion} property Identifier: IIdentifierNode read GetIdentifier; property Initializer: IAstNode read GetInitializer; end; IAssignmentNode = interface(IAstNode) {$region 'private'} function GetIdentifier: IIdentifierNode; function GetValue: IAstNode; {$endregion} property Identifier: IIdentifierNode read GetIdentifier; property Value: IAstNode read GetValue; end; // Represents an index access expression (e.g., series[index]). IIndexerNode = interface(IAstNode) {$region 'private'} function GetBase: IAstNode; function GetIndex: IAstNode; {$endregion} property Base: IAstNode read GetBase; property Index: IAstNode read GetIndex; end; // Represents a member access expression (e.g., series.field or record.field). IMemberAccessNode = interface(IAstNode) {$region 'private'} function GetBase: IAstNode; function GetMember: IIdentifierNode; {$endregion} property Base: IAstNode read GetBase; property Member: IIdentifierNode read GetMember; end; // Represents creating a new, empty series (e.g., new series(int)). ICreateSeriesNode = interface(IAstNode) {$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(IAstNode) {$region 'private'} function GetSeries: IIdentifierNode; function GetValue: IAstNode; function GetLookback: IAstNode; {$endregion} property Series: IIdentifierNode read GetSeries; property Value: IAstNode read GetValue; property Lookback: IAstNode read GetLookback; end; ISeriesLengthNode = interface(IAstNode) {$region 'private'} function GetSeries: IIdentifierNode; {$endregion} property Series: IIdentifierNode read GetSeries; end; implementation uses System.Classes; { TAstValue } constructor TAstValue.TVal.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: TAstValue.IClosure; begin if (FKind <> avkClosure) then raise EInvalidCast.Create('Cannot read value as a Closure.'); Result := TAstValue.IClosure(FInterface); end; function TAstValue.AsMemberSeries: TVal; begin if (FKind <> avkMemberSeries) then raise EInvalidCast.Create('Cannot read value as MemberSeries.'); Result := TVal(FInterface); end; function TAstValue.AsRecord: TScalarRecord; begin if (FKind <> avkRecord) then raise EInvalidCast.Create('Cannot read value as Record.'); Result := (FInterface as TVal).Value; end; function TAstValue.AsRecordSeries: TVal; begin if (FKind <> avkRecordSeries) then raise EInvalidCast.Create('Cannot read value as RecordSeries.'); Result := TVal(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; begin if (FKind <> avkSeries) then raise EInvalidCast.Create('Cannot read value as Series.'); Result := TVal(FInterface); end; function TAstValue.AsText: String; begin if (FKind <> avkText) then raise EInvalidCast.Create('Cannot read value as Text.'); Result := (FInterface as TVal).Value; end; class operator TAstValue.Implicit(const AValue: TAstValue.IClosure): 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.Create(AValue); Result.FScalar := Default(TScalar); end; class function TAstValue.FromRecord(const [ref] AValue: TScalarRecord): TAstValue; begin Result.FKind := avkRecord; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class function TAstValue.FromRecordSeries(const [ref] AValue: TScalarRecordSeries): TAstValue; begin Result.FKind := avkRecordSeries; Result.FInterface := TVal.Create(AValue); Result.FScalar := Default(TScalar); end; class operator TAstValue.Implicit(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.Create(AValue); Result.FScalar := Default(TScalar); end; class operator TAstValue.Implicit(const AValue: String): TAstValue; begin Result.FKind := avkText; Result.FInterface := TVal.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 := ''; avkText: Result := AsText; avkSeries: Result := ''; avkRecordSeries: Result := ''; avkRecord: Result := ''; avkMemberSeries: Result := ''; avkUndefined: Result := ''; else Result := '[Unknown AstValue]'; end; end; class function TAstValue.Void: TAstValue; begin Result := Default(TAstValue); end; { TResolvedAddress } constructor TResolvedAddress.Create(AKind: TAddressKind; AScopeDepth, ASlotIndex: Integer); begin Kind := AKind; ScopeDepth := AScopeDepth; SlotIndex := ASlotIndex; end; class operator TResolvedAddress.Initialize(out Dest: TResolvedAddress); begin Dest.Kind := akUnresolved; Dest.ScopeDepth := -1; Dest.SlotIndex := -1; 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.