new-Series with tuple record def
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user