new-Series with tuple record def

This commit is contained in:
Michael Schimmel
2026-01-06 13:38:06 +01:00
parent fb2fc8f6f9
commit 3b3966b2f7
13 changed files with 729 additions and 1131 deletions
+79 -8
View File
@@ -816,17 +816,88 @@ end;
function TTypeChecker.VisitCreateSeries(const Node: IAstNode): IAstNode;
var
C: ICreateSeriesNode;
elemType: IStaticType;
def: string;
defNode: IAstNode;
recDef: IScalarRecordDefinition;
resType: IStaticType;
elemKind: TScalar.TKind;
fields: TArray<TPair<IKeyword, TScalar.TKind>>;
tuple: ITupleNode;
elements: TArray<IAstNode>;
fieldTuple: ITupleNode;
keyNode: IKeywordNode;
typeNode: IKeywordNode;
i: Integer;
begin
C := Node.AsCreateSeries;
def := C.Definition;
if def.StartsWith('[') then
elemType := TTypes.CreateRecord(nil)
else
elemType := TTypes.FromScalarKind(TScalar.StringToKind(def));
// The definition node comes from the parser and is likely raw (untyped keywords/tuples).
// We don't necessarily need to "Visit" it for type checking children,
// but we need to analyze its structure.
defNode := C.DefinitionNode;
Result := TAst.CreateSeries(Node.Identity.AsDefinition, TTypes.CreateSeries(elemType));
recDef := nil;
resType := TTypes.Unknown;
case defNode.Kind of
akKeyword:
begin
// Case 1: Simple Series, e.g. (new-series :Float)
// DefinitionNode is a single Keyword
elemKind := TScalar.StringToKind(defNode.AsKeyword.Value.Name);
resType := TTypes.CreateSeries(TTypes.FromScalarKind(elemKind));
end;
akTuple:
begin
// Case 2: Record Series, e.g. (new-series [[:Price :Float] [:Vol :Ordinal]])
tuple := defNode.AsTuple;
elements := tuple.Elements;
SetLength(fields, Length(elements));
for i := 0 to High(elements) do
begin
if elements[i].Kind <> akTuple then
begin
if Assigned(FLog) then
FLog.AddError('Record definition elements must be vectors [Key Type]', elements[i]);
continue;
end;
fieldTuple := elements[i].AsTuple;
if Length(fieldTuple.Elements) <> 2 then
begin
if Assigned(FLog) then
FLog.AddError('Record definition entry must have exactly 2 elements [Key Type]', fieldTuple);
continue;
end;
if (fieldTuple.Elements[0].Kind <> akKeyword) or (fieldTuple.Elements[1].Kind <> akKeyword) then
begin
if Assigned(FLog) then
FLog.AddError('Record definition keys and types must be keywords', fieldTuple);
continue;
end;
keyNode := fieldTuple.Elements[0].AsKeyword;
typeNode := fieldTuple.Elements[1].AsKeyword;
elemKind := TScalar.StringToKind(typeNode.Value.Name);
fields[i] := TPair<IKeyword, TScalar.TKind>.Create(keyNode.Value, elemKind);
end;
if Length(fields) > 0 then
begin
recDef := TKeywordMappingRegistry<TScalar.TKind>.Intern(fields);
resType := TTypes.CreateRecordSeries(recDef);
end;
end
else
begin
if Assigned(FLog) then
FLog.AddError('Invalid series definition format. Expected :Type or [[:Key :Type] ...]', defNode);
end;
end;
// Return updated node with RecordDefinition (if any) and StaticType
Result := TAst.CreateSeries(Node.Identity, defNode, recDef, resType);
end;
function TTypeChecker.VisitSeriesLength(const Node: IAstNode): IAstNode;