Finished node immutability
This commit is contained in:
@@ -91,26 +91,6 @@ var
|
|||||||
left, right: IAstNode;
|
left, right: IAstNode;
|
||||||
nodeType: IStaticType;
|
nodeType: IStaticType;
|
||||||
begin
|
begin
|
||||||
// Get the type *before* replacing the node (it's an IAstTypedNode)
|
|
||||||
nodeType := Node.AsTypedNode.StaticType;
|
|
||||||
|
|
||||||
// --- Transformation: Keyword-as-Function ---
|
|
||||||
if Node.Callee.Kind = akKeyword then
|
|
||||||
begin
|
|
||||||
var keywordNode := Node.Callee.AsKeyword;
|
|
||||||
if Length(Node.Arguments) <> 1 then
|
|
||||||
raise EArgumentException.CreateFmt(
|
|
||||||
'Keyword :%s expects exactly one argument (the record/map), but got %d',
|
|
||||||
[keywordNode.Value.Name, Length(Node.Arguments)]);
|
|
||||||
|
|
||||||
// Visit the base node
|
|
||||||
var baseNode := Accept(Node.Arguments[0]);
|
|
||||||
|
|
||||||
// Create the new MemberAccess node, preserving the type
|
|
||||||
Result := TAst.MemberAccess(baseNode, keywordNode, nodeType);
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// --- Optimization: Operator Folding ---
|
// --- Optimization: Operator Folding ---
|
||||||
if Node.Callee.Kind = akIdentifier then
|
if Node.Callee.Kind = akIdentifier then
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -362,8 +362,12 @@ type
|
|||||||
IRecordLiteralNode = interface(IAstTypedNode)
|
IRecordLiteralNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetFields: TArray<TRecordFieldLiteral>;
|
function GetFields: TArray<TRecordFieldLiteral>;
|
||||||
|
function GetGenericDefinition: IGenericRecordDefinition;
|
||||||
|
function GetScalarDefinition: IScalarRecordDefinition;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
property Fields: TArray<TRecordFieldLiteral> read GetFields;
|
property Fields: TArray<TRecordFieldLiteral> read GetFields;
|
||||||
|
property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition;
|
||||||
|
property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ICreateSeriesNode = interface(IAstTypedNode)
|
ICreateSeriesNode = interface(IAstTypedNode)
|
||||||
|
|||||||
@@ -540,8 +540,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
def := TScalarRecordRegistry.Intern(scalarDefFields);
|
def := TScalarRecordRegistry.Intern(scalarDefFields);
|
||||||
staticType := TTypes.CreateRecord(def);
|
staticType := TTypes.CreateRecord(def);
|
||||||
Result := TRecordLiteralNode.Create(newFields, staticType);
|
Result := TAst.RecordLiteral(newFields, def, nil, staticType);
|
||||||
(Result as TRecordLiteralNode).Definition := def;
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@@ -552,8 +551,7 @@ begin
|
|||||||
|
|
||||||
var genDef := TGenericRecordRegistry.Intern(genDefFields);
|
var genDef := TGenericRecordRegistry.Intern(genDefFields);
|
||||||
staticType := TTypes.CreateGenericRecord(genDef);
|
staticType := TTypes.CreateGenericRecord(genDef);
|
||||||
Result := TGenericRecordLiteralNode.Create(newFields, staticType);
|
Result := TAst.RecordLiteral(newFields, nil, genDef, staticType);
|
||||||
(Result as TGenericRecordLiteralNode).GenericDefinition := genDef;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@@ -697,20 +697,18 @@ end;
|
|||||||
|
|
||||||
function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
|
function TAstTransformer.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
|
||||||
var
|
var
|
||||||
N: IRecordLiteralNode; // Use interface
|
|
||||||
i: Integer;
|
i: Integer;
|
||||||
newFields: TArray<TRecordFieldLiteral>;
|
newFields: TArray<TRecordFieldLiteral>;
|
||||||
hasChanged: Boolean;
|
hasChanged: Boolean;
|
||||||
begin
|
begin
|
||||||
N := Node;
|
SetLength(newFields, Length(Node.Fields));
|
||||||
SetLength(newFields, Length(N.Fields));
|
|
||||||
hasChanged := False;
|
hasChanged := False;
|
||||||
|
|
||||||
for i := 0 to High(N.Fields) do
|
for i := 0 to High(Node.Fields) do
|
||||||
begin
|
begin
|
||||||
newFields[i].Key := Accept(N.Fields[i].Key).AsKeyword;
|
newFields[i].Key := Accept(Node.Fields[i].Key).AsKeyword;
|
||||||
newFields[i].Value := Accept(N.Fields[i].Value);
|
newFields[i].Value := Accept(Node.Fields[i].Value);
|
||||||
if (newFields[i].Key <> N.Fields[i].Key) or (newFields[i].Value <> N.Fields[i].Value) then
|
if (newFields[i].Key <> Node.Fields[i].Key) or (newFields[i].Value <> Node.Fields[i].Value) then
|
||||||
hasChanged := True;
|
hasChanged := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -720,13 +718,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
// Rebuild the node, preserving its specific type and definitions
|
// Rebuild the node, preserving its specific type and definitions
|
||||||
// Use TAst factory
|
// Use TAst factory
|
||||||
Result := TAst.RecordLiteral(newFields, N.StaticType);
|
Result := TAst.RecordLiteral(newFields, Node.ScalarDefinition, Node.GenericDefinition, Node.StaticType);
|
||||||
|
|
||||||
// Copy runtime properties (casts are valid)
|
|
||||||
if N is TGenericRecordLiteralNode then
|
|
||||||
(Result as TGenericRecordLiteralNode).GenericDefinition := (N as TGenericRecordLiteralNode).GenericDefinition
|
|
||||||
else
|
|
||||||
(Result as TRecordLiteralNode).Definition := (N as TRecordLiteralNode).Definition;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
+59
-42
@@ -120,6 +120,8 @@ type
|
|||||||
): IMemberAccessNode; static;
|
): IMemberAccessNode; static;
|
||||||
class function RecordLiteral(
|
class function RecordLiteral(
|
||||||
const AFields: TArray<TRecordFieldLiteral>;
|
const AFields: TArray<TRecordFieldLiteral>;
|
||||||
|
const AScalarDefinition: IScalarRecordDefinition = nil;
|
||||||
|
const AGenericDefinition: IGenericRecordDefinition = nil;
|
||||||
const AStaticType: IStaticType = nil
|
const AStaticType: IStaticType = nil
|
||||||
): IRecordLiteralNode; static;
|
): IRecordLiteralNode; static;
|
||||||
class function CreateSeries(const ADefinition: String; const AStaticType: IStaticType = nil): ICreateSeriesNode; static;
|
class function CreateSeries(const ADefinition: String; const AStaticType: IStaticType = nil): ICreateSeriesNode; static;
|
||||||
@@ -133,6 +135,14 @@ type
|
|||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.Generics.Defaults;
|
||||||
|
|
||||||
|
type
|
||||||
|
// --- Concrete Class Definitions moved to implementation ---
|
||||||
|
|
||||||
// Common base class for AST nodes to reduce boilerplate.
|
// Common base class for AST nodes to reduce boilerplate.
|
||||||
TAstNode = class(TInterfacedObject, IAstNode)
|
TAstNode = class(TInterfacedObject, IAstNode)
|
||||||
private
|
private
|
||||||
@@ -186,38 +196,6 @@ type
|
|||||||
property StaticType: IStaticType read GetStaticType;
|
property StaticType: IStaticType read GetStaticType;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// TRecordLiteralNode is still needed in the interface
|
|
||||||
// for TGenericRecordLiteralNode
|
|
||||||
TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode)
|
|
||||||
private
|
|
||||||
FFields: TArray<TRecordFieldLiteral>;
|
|
||||||
FDefinition: IScalarRecordDefinition;
|
|
||||||
function GetFields: TArray<TRecordFieldLiteral>;
|
|
||||||
function GetKind: TAstNodeKind; override;
|
|
||||||
public
|
|
||||||
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const AStaticType: IStaticType);
|
|
||||||
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
|
||||||
function AsRecordLiteral: IRecordLiteralNode; override;
|
|
||||||
property Fields: TArray<TRecordFieldLiteral> read FFields;
|
|
||||||
property Definition: IScalarRecordDefinition read FDefinition write FDefinition;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TGenericRecordLiteralNode = class(TRecordLiteralNode, IRecordLiteralNode)
|
|
||||||
private
|
|
||||||
FGenericDefinition: IGenericRecordDefinition;
|
|
||||||
public
|
|
||||||
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const AStaticType: IStaticType);
|
|
||||||
property GenericDefinition: IGenericRecordDefinition read FGenericDefinition write FGenericDefinition;
|
|
||||||
end;
|
|
||||||
|
|
||||||
implementation
|
|
||||||
|
|
||||||
uses
|
|
||||||
System.Generics.Defaults;
|
|
||||||
|
|
||||||
type
|
|
||||||
// --- Concrete Class Definitions moved to implementation ---
|
|
||||||
|
|
||||||
TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode)
|
TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode)
|
||||||
private
|
private
|
||||||
FParameters: TArray<IIdentifierNode>;
|
FParameters: TArray<IIdentifierNode>;
|
||||||
@@ -580,6 +558,31 @@ type
|
|||||||
property Series: IIdentifierNode read FSeries;
|
property Series: IIdentifierNode read FSeries;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// TRecordLiteralNode is still needed in the interface
|
||||||
|
// for TGenericRecordLiteralNode
|
||||||
|
TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode)
|
||||||
|
private
|
||||||
|
FFields: TArray<TRecordFieldLiteral>;
|
||||||
|
FScalarDefinition: IScalarRecordDefinition;
|
||||||
|
FGenericDefinition: IGenericRecordDefinition;
|
||||||
|
function GetFields: TArray<TRecordFieldLiteral>;
|
||||||
|
function GetGenericDefinition: IGenericRecordDefinition;
|
||||||
|
function GetKind: TAstNodeKind; override;
|
||||||
|
function GetScalarDefinition: IScalarRecordDefinition;
|
||||||
|
public
|
||||||
|
constructor Create(
|
||||||
|
const AFields: TArray<TRecordFieldLiteral>;
|
||||||
|
const AScalarDefinition: IScalarRecordDefinition;
|
||||||
|
const AGenericDefinition: IGenericRecordDefinition;
|
||||||
|
const AStaticType: IStaticType
|
||||||
|
);
|
||||||
|
function Accept(const Visitor: IAstVisitor): TDataValue; override;
|
||||||
|
function AsRecordLiteral: IRecordLiteralNode; override;
|
||||||
|
property Fields: TArray<TRecordFieldLiteral> read FFields;
|
||||||
|
property ScalarDefinition: IScalarRecordDefinition read GetScalarDefinition;
|
||||||
|
property GenericDefinition: IGenericRecordDefinition read GetGenericDefinition;
|
||||||
|
end;
|
||||||
|
|
||||||
TNopNode = class(TAstNode, INopNode)
|
TNopNode = class(TAstNode, INopNode)
|
||||||
private
|
private
|
||||||
function GetKind: TAstNodeKind; override;
|
function GetKind: TAstNodeKind; override;
|
||||||
@@ -882,14 +885,18 @@ begin
|
|||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAst.RecordLiteral(const AFields: TArray<TRecordFieldLiteral>; const AStaticType: IStaticType = nil): IRecordLiteralNode;
|
class function TAst.RecordLiteral(
|
||||||
|
const AFields: TArray<TRecordFieldLiteral>;
|
||||||
|
const AScalarDefinition: IScalarRecordDefinition = nil;
|
||||||
|
const AGenericDefinition: IGenericRecordDefinition = nil;
|
||||||
|
const AStaticType: IStaticType = nil
|
||||||
|
): IRecordLiteralNode;
|
||||||
begin
|
begin
|
||||||
// By default, the parser creates the generic (most flexible) node type.
|
|
||||||
// The TypeChecker (Phase 3) is responsible for "lowering" this to a
|
|
||||||
// TRecordLiteralNode if it determines all fields are scalar.
|
|
||||||
Result :=
|
Result :=
|
||||||
TGenericRecordLiteralNode.Create(
|
TRecordLiteralNode.Create(
|
||||||
AFields,
|
AFields,
|
||||||
|
AScalarDefinition,
|
||||||
|
AGenericDefinition,
|
||||||
if AStaticType <> nil then AStaticType
|
if AStaticType <> nil then AStaticType
|
||||||
else TTypes.Unknown
|
else TTypes.Unknown
|
||||||
);
|
);
|
||||||
@@ -1870,10 +1877,17 @@ end;
|
|||||||
|
|
||||||
{ TRecordLiteralNode }
|
{ TRecordLiteralNode }
|
||||||
|
|
||||||
constructor TRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const AStaticType: IStaticType);
|
constructor TRecordLiteralNode.Create(
|
||||||
|
const AFields: TArray<TRecordFieldLiteral>;
|
||||||
|
const AScalarDefinition: IScalarRecordDefinition;
|
||||||
|
const AGenericDefinition: IGenericRecordDefinition;
|
||||||
|
const AStaticType: IStaticType
|
||||||
|
);
|
||||||
begin
|
begin
|
||||||
inherited Create(AStaticType);
|
inherited Create(AStaticType);
|
||||||
FFields := AFields;
|
FFields := AFields;
|
||||||
|
FGenericDefinition := AGenericDefinition;
|
||||||
|
FScalarDefinition := AScalarDefinition;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TRecordLiteralNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
function TRecordLiteralNode.Accept(const Visitor: IAstVisitor): TDataValue;
|
||||||
@@ -1891,16 +1905,19 @@ begin
|
|||||||
Result := FFields;
|
Result := FFields;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TRecordLiteralNode.GetGenericDefinition: IGenericRecordDefinition;
|
||||||
|
begin
|
||||||
|
Result := FGenericDefinition;
|
||||||
|
end;
|
||||||
|
|
||||||
function TRecordLiteralNode.GetKind: TAstNodeKind;
|
function TRecordLiteralNode.GetKind: TAstNodeKind;
|
||||||
begin
|
begin
|
||||||
Result := akRecordLiteral;
|
Result := akRecordLiteral;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TGenericRecordLiteralNode }
|
function TRecordLiteralNode.GetScalarDefinition: IScalarRecordDefinition;
|
||||||
|
|
||||||
constructor TGenericRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const AStaticType: IStaticType);
|
|
||||||
begin
|
begin
|
||||||
inherited Create(AFields, AStaticType);
|
Result := FScalarDefinition;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TCreateSeriesNode }
|
{ TCreateSeriesNode }
|
||||||
|
|||||||
Reference in New Issue
Block a user