Script Refactoring, ParseGet reads record fields

This commit is contained in:
Michael Schimmel
2026-01-07 00:28:38 +01:00
parent 8a29cf7f74
commit 0d3ccd1c63
3 changed files with 786 additions and 376 deletions
+60 -13
View File
@@ -687,30 +687,77 @@ var
newBase, newIndex: IAstNode;
baseType, elemType: IStaticType;
isOpt: Boolean;
idx: Integer;
key: IKeyword;
begin
I := Node.AsIndexer;
newBase := Accept(I.Base);
newIndex := Accept(I.Index);
baseType := PrepareBaseType(newBase, isOpt);
// Unwrap optional types to check the underlying structure
baseType := PrepareBaseType(newBase, isOpt);
elemType := TTypes.Unknown;
if baseType.Kind = stSeries then
elemType := baseType.AsSeries.ElementType
else if baseType.Kind = stRecordSeries then
elemType := TTypes.CreateRecord(baseType.AsRecord.Definition)
else if baseType.Kind = stTuple then
begin
// Tuple Indexing (requires constant index for strong typing!)
if (newIndex.Kind = akConstant) and (newIndex.AsConstant.Value.Kind = vkScalar) then
case baseType.Kind of
// Case 1: Accessing Tuples (Heterogeneous fixed-size lists)
// Static typing requires the index to be a constant integer to determine the specific element type.
stTuple:
begin
var idx := newIndex.AsConstant.Value.AsScalar.Value.AsInt64;
var tpl := baseType.AsTuple;
if (idx >= 0) and (idx < tpl.Count) then
elemType := tpl.Elements[Integer(idx)];
if (newIndex.Kind = akConstant) and (newIndex.AsConstant.Value.Kind = vkScalar) then
begin
var intIdx := newIndex.AsConstant.Value.AsScalar.Value.AsInt64;
var tpl := baseType.AsTuple;
if (intIdx >= 0) and (intIdx < tpl.Count) then
elemType := tpl.Elements[Integer(intIdx)];
end;
end;
// Case 2: Accessing Records or Record Series (Field Access)
// Static typing requires the index to be a Keyword literal.
stRecord, stRecordSeries:
begin
if newIndex.Kind = akKeyword then
begin
key := newIndex.AsKeyword.Value;
var def := baseType.AsRecord.Definition;
idx := def.IndexOf(key);
if idx >= 0 then
begin
var fieldType := TTypes.FromScalarKind(def[idx]);
// If we access a field on a Stream/Series of Records, the result is a Series of that field (Column).
// If we access a field on a single Record, the result is the scalar value.
if baseType.Kind = stRecordSeries then
elemType := TTypes.CreateSeries(fieldType)
else
elemType := fieldType;
end
else if Assigned(FLog) then
FLog.AddError(Format('Field ":%s" not found in record definition.', [key.Name]), Node);
end
else if Assigned(FLog) then
FLog.AddError('Record access requires a constant keyword literal (e.g. :close).', Node);
end;
// Case 3: Accessing Series via Integer Index (Row Access)
// Returns the scalar element at the specific position.
stSeries:
begin
elemType := baseType.AsSeries.ElementType;
end;
// Case 4: Vector / Matrix (Homogeneous)
// Accessing a Vector returns the ElementType.
stVector:
begin
elemType := baseType.AsVector.ElementType;
end;
end;
// Propagate nullability if the base object was optional
elemType := ApplyOptionality(elemType, isOpt);
Result := TAst.Indexer(Node.Identity, newBase, newIndex, elemType);
end;
+725 -362
View File
File diff suppressed because it is too large Load Diff