Keywords as basic scalar type
Script enhancements
This commit is contained in:
+75
-24
@@ -161,6 +161,15 @@ type
|
||||
property Definition: IScalarRecordDefinition read FDefinition;
|
||||
end;
|
||||
|
||||
// Represents a bound record literal that maps to a generic (non-scalar) record
|
||||
TBoundGenericRecordLiteralNode = class(TRecordLiteralNode)
|
||||
private
|
||||
FDefinition: IGenericRecordDefinition;
|
||||
public
|
||||
constructor Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: IGenericRecordDefinition);
|
||||
property Definition: IGenericRecordDefinition read FDefinition;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
@@ -340,6 +349,13 @@ begin
|
||||
FIsTailCall := AIsTailCall;
|
||||
end;
|
||||
|
||||
{ TBoundGenericRecordLiteralNode }
|
||||
constructor TBoundGenericRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: IGenericRecordDefinition);
|
||||
begin
|
||||
inherited Create(AFields);
|
||||
FDefinition := ADef;
|
||||
end;
|
||||
|
||||
{ TBoundRecordLiteralNode }
|
||||
constructor TBoundRecordLiteralNode.Create(const AFields: TArray<TRecordFieldLiteral>; const ADef: IScalarRecordDefinition);
|
||||
begin
|
||||
@@ -932,20 +948,35 @@ begin
|
||||
elemType := TTypes.Unknown;
|
||||
if (baseType.Kind <> TStaticTypeKind.stUnknown) then
|
||||
begin
|
||||
if (baseType.Kind <> TStaticTypeKind.stRecord) and (baseType.Kind <> TStaticTypeKind.stRecordSeries) then
|
||||
raise ETypeException.CreateFmt('Member access requires a record or record series, but got %s', [baseType.ToString]);
|
||||
if (baseType.Kind = TStaticTypeKind.stRecord) or (baseType.Kind = TStaticTypeKind.stRecordSeries) then
|
||||
begin
|
||||
// --- SALAR PATH ---
|
||||
fieldIndex := baseType.Definition.IndexOf(Node.Member.Value);
|
||||
if fieldIndex < 0 then
|
||||
raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]);
|
||||
|
||||
// Use IndexOf(string) which correctly delegates to IndexOf(IKeyword)
|
||||
fieldIndex := baseType.Definition.IndexOf(Node.Member.Value);
|
||||
if fieldIndex < 0 then
|
||||
raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]);
|
||||
var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Value);
|
||||
|
||||
var fieldType := TTypes.FromScalarKind(baseType.Definition.Fields[fieldIndex].Value);
|
||||
if baseType.Kind = TStaticTypeKind.stRecord then
|
||||
elemType := fieldType
|
||||
else // stRecordSeries
|
||||
elemType := TTypes.CreateSeries(fieldType);
|
||||
end
|
||||
else if (baseType.Kind = TStaticTypeKind.stGenericRecord) then
|
||||
begin
|
||||
// --- GENERIC PATH ---
|
||||
var genDef := baseType.GenericDefinition;
|
||||
fieldIndex := genDef.IndexOf(Node.Member.Value);
|
||||
if fieldIndex < 0 then
|
||||
raise ETypeException.CreateFmt('Member "%s" not found in type %s', [Node.Member.Value.Name, baseType.ToString]);
|
||||
|
||||
if baseType.Kind = TStaticTypeKind.stRecord then
|
||||
elemType := fieldType
|
||||
else // stRecordSeries
|
||||
elemType := TTypes.CreateSeries(fieldType);
|
||||
// Type is stored directly in the generic definition
|
||||
elemType := genDef.Fields[fieldIndex].Value;
|
||||
end
|
||||
else
|
||||
begin
|
||||
raise ETypeException.CreateFmt('Member access requires a record type, but got %s', [baseType.ToString]);
|
||||
end;
|
||||
end;
|
||||
|
||||
var boundNode := TAst.MemberAccess(baseNode, Node.Member);
|
||||
@@ -956,24 +987,25 @@ function TAstBinder.VisitRecordLiteral(const Node: IRecordLiteralNode): TDataVal
|
||||
var
|
||||
i: Integer;
|
||||
boundFields: TArray<TRecordFieldLiteral>;
|
||||
defFields: TArray<TScalarRecordField>;
|
||||
scalarDefFields: TArray<TScalarRecordField>; // Renamed
|
||||
def: IScalarRecordDefinition;
|
||||
staticType: IStaticType;
|
||||
boundNode: IRecordLiteralNode;
|
||||
valNode: IAstNode;
|
||||
valType: IStaticType;
|
||||
scalarKind: TScalar.TKind;
|
||||
allScalar: Boolean; // Added
|
||||
begin
|
||||
FNextIsTail := False;
|
||||
SetLength(boundFields, Length(Node.Fields));
|
||||
SetLength(defFields, Length(Node.Fields));
|
||||
SetLength(scalarDefFields, Length(Node.Fields)); // Renamed
|
||||
allScalar := True; // Added
|
||||
|
||||
for i := 0 to High(Node.Fields) do
|
||||
begin
|
||||
valNode := Accept(Node.Fields[i].Value).AsIntf<IAstNode>;
|
||||
valType := (valNode as TAstNode).StaticType;
|
||||
|
||||
// Path A: Records can now store Ordinal, Float, or Keyword
|
||||
// Check if this field fits the scalar path
|
||||
if (valType.Kind = stOrdinal) then
|
||||
scalarKind := TScalar.TKind.Ordinal
|
||||
else if (valType.Kind = stFloat) then
|
||||
@@ -981,21 +1013,40 @@ begin
|
||||
else if (valType.Kind = stKeyword) then
|
||||
scalarKind := TScalar.TKind.Keyword
|
||||
else
|
||||
raise ETypeException.CreateFmt(
|
||||
'Record fields must be scalar (Ordinal, Float, or Keyword), but field ":%s" is %s',
|
||||
[Node.Fields[i].Key.Value.Name, valType.ToString]);
|
||||
begin
|
||||
allScalar := False; // It's a generic record
|
||||
scalarKind := TScalar.TKind.Ordinal; // Dummy value, won't be used
|
||||
end;
|
||||
|
||||
boundFields[i] := TRecordFieldLiteral.Create(Node.Fields[i].Key, valNode);
|
||||
|
||||
// Create the definition field using the Keyword and its TScalar.TKind
|
||||
defFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind);
|
||||
// Conditionally fill the scalar definition array
|
||||
if allScalar then
|
||||
scalarDefFields[i] := TScalarRecordField.Create(Node.Fields[i].Key.Value, scalarKind);
|
||||
end;
|
||||
|
||||
def := TScalarRecordRegistry.Intern(defFields);
|
||||
staticType := TTypes.CreateRecord(def);
|
||||
boundNode := TBoundRecordLiteralNode.Create(boundFields, def);
|
||||
// Now, create the correct bound node based on the flag
|
||||
if allScalar then
|
||||
begin
|
||||
// --- EXISTING SCALAR PATH ---
|
||||
def := TScalarRecordRegistry.Intern(scalarDefFields);
|
||||
staticType := TTypes.CreateRecord(def);
|
||||
var boundNode := TBoundRecordLiteralNode.Create(boundFields, def); // Old bound node
|
||||
Result := SetType(TDataValue.FromIntf<IRecordLiteralNode>(boundNode), staticType);
|
||||
end
|
||||
else
|
||||
begin
|
||||
// --- NEW GENERIC PATH ---
|
||||
var genDefFields: TArray<TPair<IKeyword, IStaticType>>;
|
||||
SetLength(genDefFields, Length(boundFields));
|
||||
for i := 0 to High(boundFields) do
|
||||
genDefFields[i] := TPair<IKeyword, IStaticType>.Create(boundFields[i].Key.Value, (boundFields[i].Value as TAstNode).StaticType);
|
||||
|
||||
Result := SetType(TDataValue.FromIntf<IRecordLiteralNode>(boundNode), staticType);
|
||||
var genDef := TGenericRecordRegistry.Intern(genDefFields);
|
||||
staticType := TTypes.CreateGenericRecord(genDef);
|
||||
var genBoundNode := TBoundGenericRecordLiteralNode.Create(boundFields, genDef);
|
||||
Result := SetType(TDataValue.FromIntf<IRecordLiteralNode>(genBoundNode), staticType);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TAstBinder.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
|
||||
Reference in New Issue
Block a user