Refactoring for immutable nodes

This commit is contained in:
Michael Schimmel
2025-11-05 13:21:17 +01:00
parent 9bd2d6f7ab
commit c0a689d2bc
13 changed files with 217 additions and 190 deletions
+158 -115
View File
@@ -33,7 +33,7 @@ type
class function Nop: IAstNode; static;
// --- Factory functions ---
class function Constant(const AValue: TDataValue): IConstantNode; overload; static;
class function Constant(const AValue: TDataValue; const AStaticType: IStaticType = nil): IConstantNode; overload; static;
class function Constant(const AValue: String): IConstantNode; overload; static;
class function Keyword(const AName: string): IKeywordNode; static;
class function Identifier(AName: string): IIdentifierNode; static;
@@ -71,13 +71,18 @@ type
): IAddSeriesItemNode; static;
class function SeriesLength(const ASeries: IIdentifierNode): ISeriesLengthNode; static;
class function BoundIdentifier(AName: string; const Address: TResolvedAddress): IBoundIdentifierNode; static;
class function BoundIdentifier(
AName: string;
const Address: TResolvedAddress;
const AStaticType: IStaticType = nil
): IBoundIdentifierNode; static;
end;
// Common base class for AST nodes to reduce boilerplate.
TAstNode = class(TInterfacedObject, IAstNode)
private
function GetKind: TAstNodeKind; virtual; abstract;
function GetIsTyped: Boolean; virtual;
public
constructor Create;
function Accept(const Visitor: IAstVisitor): TDataValue; virtual; abstract;
@@ -112,6 +117,7 @@ type
function AsBoundIdentifierNode: IBoundIdentifierNode; virtual;
function AsTypedNode: IAstTypedNode; virtual;
property IsTyped: Boolean read GetIsTyped;
property Kind: TAstNodeKind read GetKind;
end;
@@ -119,59 +125,13 @@ type
private
FStaticType: IStaticType;
function GetStaticType: IStaticType;
function GetIsTyped: Boolean; override;
public
constructor Create(const AStaticType: IStaticType);
function AsTypedNode: IAstTypedNode; override;
property StaticType: IStaticType read GetStaticType;
end;
TConstantNode = class(TAstTypedNode, IConstantNode)
private
FValue: TDataValue;
function GetValue: TDataValue;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: TDataValue; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsConstant: IConstantNode; override;
property Value: TDataValue read GetValue; // Value ist immutable
end;
TIdentifierNode = class(TAstTypedNode, IIdentifierNode)
private
FName: string;
function GetName: string;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsIdentifier: IIdentifierNode; override;
property Name: string read FName; // Name ist immutable
end;
TBoundIdentifierNode = class(TIdentifierNode, IBoundIdentifierNode)
private
FAddress: TResolvedAddress;
function GetAddress: TResolvedAddress;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AAddress: TResolvedAddress; const AStaticType: IStaticType);
function AsBoundIdentifierNode: IBoundIdentifierNode; override;
property Address: TResolvedAddress read GetAddress;
end;
TKeywordNode = class(TAstTypedNode, IKeywordNode)
private
FValue: IKeyword;
function GetValue: IKeyword;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: IKeyword);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsKeyword: IKeywordNode; override;
property Value: IKeyword read FValue; // Value ist immutable
end;
TBinaryExpressionNode = class(TAstTypedNode, IBinaryExpressionNode)
private
FLeft: IAstNode;
@@ -263,60 +223,6 @@ type
property HasNestedLambdas: Boolean read FHasNestedLambdas write FHasNestedLambdas;
end;
TMacroDefinitionNode = class(TAstNode, IMacroDefinitionNode)
private
FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>;
FBody: IAstNode;
function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroDefinition: IMacroDefinitionNode; override;
property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read FParameters;
property Body: IAstNode read FBody;
end;
TQuasiquoteNode = class(TAstNode, IQuasiquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsQuasiquote: IQuasiquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteNode = class(TAstNode, IUnquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquote: IUnquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
private
FExpression: IQuasiquoteNode;
function GetExpression: IQuasiquoteNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IQuasiquoteNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
property Expression: IQuasiquoteNode read GetExpression;
end;
TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode)
private
FCallee: IAstNode;
@@ -349,16 +255,16 @@ type
TMacroExpansionNode = class(TAstTypedNode, IMacroExpansionNode)
private
FCallNode: IFunctionCallNode;
FExpandedBody: IAstNode;
FExpandedBody: IAstTypedNode;
function GetCallNode: IFunctionCallNode;
function GetExpandedBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstNode; const AStaticType: IStaticType);
constructor Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstTypedNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroExpansion: IMacroExpansionNode; override;
property CallNode: IFunctionCallNode read GetCallNode;
property ExpandedBody: IAstNode read FExpandedBody;
property ExpandedBody: IAstTypedNode read FExpandedBody;
end;
TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode)
@@ -508,8 +414,108 @@ implementation
uses
System.Generics.Defaults;
// Added Nop
type
TConstantNode = class(TAstTypedNode, IConstantNode)
private
FValue: TDataValue;
function GetValue: TDataValue;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: TDataValue; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsConstant: IConstantNode; override;
property Value: TDataValue read GetValue;
end;
TIdentifierNode = class(TAstTypedNode, IIdentifierNode)
private
FName: string;
function GetName: string;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AStaticType: IStaticType);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsIdentifier: IIdentifierNode; override;
property Name: string read FName;
end;
TBoundIdentifierNode = class(TIdentifierNode, IBoundIdentifierNode)
private
FAddress: TResolvedAddress;
function GetAddress: TResolvedAddress;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: string; const AAddress: TResolvedAddress; const AStaticType: IStaticType);
function AsBoundIdentifierNode: IBoundIdentifierNode; override;
property Address: TResolvedAddress read GetAddress;
end;
TKeywordNode = class(TAstTypedNode, IKeywordNode)
private
FValue: IKeyword;
function GetValue: IKeyword;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AValue: IKeyword);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsKeyword: IKeywordNode; override;
property Value: IKeyword read FValue; // Value ist immutable
end;
TMacroDefinitionNode = class(TAstNode, IMacroDefinitionNode)
private
FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>;
FBody: IAstNode;
function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsMacroDefinition: IMacroDefinitionNode; override;
property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read FParameters;
property Body: IAstNode read FBody;
end;
TQuasiquoteNode = class(TAstNode, IQuasiquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsQuasiquote: IQuasiquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteNode = class(TAstNode, IUnquoteNode)
private
FExpression: IAstNode;
function GetExpression: IAstNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IAstNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquote: IUnquoteNode; override;
property Expression: IAstNode read GetExpression;
end;
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
private
FExpression: IQuasiquoteNode;
function GetExpression: IQuasiquoteNode;
function GetKind: TAstNodeKind; override;
public
constructor Create(const AExpression: IQuasiquoteNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override;
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
property Expression: IQuasiquoteNode read GetExpression;
end;
TNopNode = class(TAstNode, INopNode)
private
function GetKind: TAstNodeKind; override;
@@ -574,14 +580,28 @@ begin
Result := TBlockExpressionNode.Create(AExpressions, TTypes.Unknown);
end;
class function TAst.Constant(const AValue: TDataValue): IConstantNode;
class function TAst.Constant(const AValue: TDataValue; const AStaticType: IStaticType = nil): IConstantNode;
begin
Result := TConstantNode.Create(AValue, TTypes.Unknown);
var constType := AStaticType;
if constType = nil then
begin
case AValue.Kind of
TDataValueKind.vkScalar: constType := TTypes.FromScalarKind(AValue.AsScalar.Kind);
TDataValueKind.vkText: constType := TTypes.Text;
TDataValueKind.vkVoid: constType := TTypes.Void;
else
constType := TTypes.Unknown;
end;
end;
// Create a new node with the correct type
Result := TConstantNode.Create(AValue, constType);
end;
class function TAst.Constant(const AValue: String): IConstantNode;
begin
Result := TConstantNode.Create(AValue, TTypes.Unknown);
Result := TConstantNode.Create(AValue, TTypes.Text);
end;
class constructor TAst.Create;
@@ -594,9 +614,19 @@ begin
FLibraries.Free;
end;
class function TAst.BoundIdentifier(AName: string; const Address: TResolvedAddress): IBoundIdentifierNode;
class function TAst.BoundIdentifier(
AName: string;
const Address: TResolvedAddress;
const AStaticType: IStaticType = nil
): IBoundIdentifierNode;
begin
Result := TBoundIdentifierNode.Create(AName, Address, TTypes.Unknown);
Result :=
TBoundIdentifierNode.Create(
AName,
Address,
if AStaticType <> nil then AStaticType
else TTypes.Unknown
);
end;
class procedure TAst.RegisterLibrary(const AProc: TRegisterLibraryProc);
@@ -645,7 +675,10 @@ end;
class function TAst.MacroExpansionNode(const AOriginalCallNode: IFunctionCallNode; const AExpandedBody: IAstNode): IMacroExpansionNode;
begin
Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody, TTypes.Unknown);
if AExpandedBody.IsTyped then
Result := TMacroExpansionNode.Create(AOriginalCallNode, AExpandedBody.AsTypedNode)
else
Result := TMacroExpansionNode.Create(AOriginalCallNode, Block([]));
end;
class function TAst.MemberAccess(const ABase: IAstNode; const AMember: IKeywordNode): IMemberAccessNode;
@@ -871,6 +904,11 @@ begin
raise ETypeException.Create('Node is not a VariableDeclaration');
end;
function TAstNode.GetIsTyped: Boolean;
begin
Result := false;
end;
{ TAstTypedNode }
constructor TAstTypedNode.Create(const AStaticType: IStaticType);
@@ -885,6 +923,11 @@ begin
Result := Self;
end;
function TAstTypedNode.GetIsTyped: Boolean;
begin
Result := true;
end;
function TAstTypedNode.GetStaticType: IStaticType;
begin
Result := FStaticType;
@@ -1334,10 +1377,10 @@ end;
{ TMacroExpansionNode }
constructor TMacroExpansionNode.Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstNode; const AStaticType: IStaticType);
constructor TMacroExpansionNode.Create(const ACallNode: IFunctionCallNode; const AExpandedBody: IAstTypedNode);
begin
// Copy properties from the original call node
inherited Create(AStaticType);
inherited Create(AExpandedBody.StaticType);
FExpandedBody := AExpandedBody;
FCallNode := ACallNode;
end;