Ast Refactoring

This commit is contained in:
Michael Schimmel
2025-09-03 09:47:16 +02:00
parent eb7902d9e8
commit 3e4ca283c9
11 changed files with 150 additions and 15 deletions
+1 -2
View File
@@ -9,8 +9,7 @@ uses
Myc.Ast.Nodes in '..\Src\AST\Myc.Ast.Nodes.pas',
Myc.Ast.Scope in '..\Src\AST\Myc.Ast.Scope.pas',
DraggablePanel in 'DraggablePanel.pas',
Myc.Ast.Visualizer in 'Myc.Ast.Visualizer.pas',
Myc.Ast.RttiUtils in 'Myc.Ast.RttiUtils.pas';
Myc.Ast.Visualizer in 'Myc.Ast.Visualizer.pas';
{$R *.res}
-1
View File
@@ -141,7 +141,6 @@
<DCCReference Include="..\Src\AST\Myc.Ast.Scope.pas"/>
<DCCReference Include="DraggablePanel.pas"/>
<DCCReference Include="Myc.Ast.Visualizer.pas"/>
<DCCReference Include="Myc.Ast.RttiUtils.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
+2 -2
View File
@@ -22,7 +22,7 @@ uses
FMX.Controls.Presentation,
DraggablePanel,
Myc.Ast.Visualizer,
Myc.Data.POD,
Myc.Data.Scalar,
Myc.Ast.Nodes,
Myc.Ast,
Myc.Ast.Evaluator,
@@ -77,7 +77,7 @@ implementation
uses
Myc.Ast.Scope,
Myc.Ast.RttiUtils,
Myc.Data.Scalar.JSON,
Myc.Data.Decimal,
System.Diagnostics; // For TStopwatch
-152
View File
@@ -1,152 +0,0 @@
unit Myc.Ast.RttiUtils;
interface
uses
System.SysUtils,
System.Rtti,
System.TypInfo,
Myc.Data.POD;
type
TRttiAstHelper = class
private
// Maps a Delphi RTTI type to its TScalarKind.
class function TypeToScalarKind(AType: TRttiType): TScalarKind; static;
public
// Creates a JSON definition string from a record type info.
class function RecordDefinitionToJson(ATypeInfo: PTypeInfo): string; static;
// Creates a record definition from a JSON string.
class function JsonToRecordDefinition(const AJson: string): TScalarRecordDefinition; static;
end;
implementation
uses
Myc.Data.Decimal,
System.JSON;
{ TRttiAstHelper }
class function TRttiAstHelper.JsonToRecordDefinition(const AJson: string): TScalarRecordDefinition;
var
jsonValue: TJSONValue;
rootObj: TJSONObject;
fieldsArray: TJSONArray;
i: Integer;
fieldObj: TJSONObject;
kindStr: string;
fields: TArray<TScalarRecordField>;
begin
jsonValue := TJSONObject.ParseJSONValue(AJson);
if not Assigned(jsonValue) then
exit;
try
if not (jsonValue is TJSONObject) then
exit;
rootObj := jsonValue as TJSONObject;
if not rootObj.TryGetValue<TJSONArray>('fields', fieldsArray) then
exit;
SetLength(fields, fieldsArray.Count);
for i := 0 to fieldsArray.Count - 1 do
begin
fieldObj := fieldsArray.Items[i] as TJSONObject;
if not Assigned(fieldObj) then
continue; // or raise error
fields[i].Name := fieldObj.GetValue<string>('name');
kindStr := fieldObj.GetValue<string>('kind');
fields[i].Kind := TScalarKind(GetEnumValue(TypeInfo(TScalarKind), kindStr));
end;
Result := TScalarRecordDefinition.Create(fields);
finally
jsonValue.Free;
end;
end;
class function TRttiAstHelper.RecordDefinitionToJson(ATypeInfo: PTypeInfo): string;
var
ctx: TRttiContext;
rttiType: TRttiType;
rttiRecordType: TRttiRecordType;
field: TRttiField;
rootObj: TJSONObject;
fieldsArray: TJSONArray;
fieldObj: TJSONObject;
begin
// 1. Create TRttiContext and get TRttiRecordType.
ctx := TRttiContext.Create;
rttiType := ctx.GetType(ATypeInfo);
if not (rttiType is TRttiRecordType) then
raise EArgumentException.Create('PTypeInfo provided is not a record type.');
rttiRecordType := rttiType as TRttiRecordType;
// 2. Create root TJSONObject and a TJSONArray for 'fields'.
rootObj := TJSONObject.Create;
try
fieldsArray := TJSONArray.Create;
rootObj.AddPair('fields', fieldsArray);
// 3. Loop through all fields of the record type.
for field in rttiRecordType.GetFields do
begin
// 4a. Create a TJSONObject for the field definition.
fieldObj := TJSONObject.Create;
// 4b. Add field name.
fieldObj.AddPair('name', TJSONString.Create(field.Name));
// 4c. Call TypeToScalarKind to get the type and add it.
fieldObj.AddPair('kind', TJSONString.Create(GetEnumName(TypeInfo(TScalarKind), Ord(TypeToScalarKind(field.FieldType)))));
// 4d. Add the field object to the 'fields' array.
fieldsArray.Add(fieldObj);
end;
// 5. Convert the root JSON object to a string and set it as Result.
Result := rootObj.ToJSON;
finally
rootObj.Free;
end;
end;
class function TRttiAstHelper.TypeToScalarKind(AType: TRttiType): TScalarKind;
var
typeHandle: PTypeInfo;
begin
// 1. Use a case statement or if-checks on AType.Handle.
typeHandle := AType.Handle;
// 2. Compare with TypeInfo(Integer), TypeInfo(Double), TypeInfo(TDecimal) etc.
if typeHandle = TypeInfo(Integer) then
Result := skInteger
else if typeHandle = TypeInfo(Int64) then
Result := skInt64
else if typeHandle = TypeInfo(UInt64) then
Result := skUInt64
else if typeHandle = TypeInfo(Single) then
Result := skSingle
else if typeHandle = TypeInfo(Double) then
Result := skDouble
else if typeHandle = TypeInfo(TDateTime) then
Result := skDateTime
else if typeHandle = TypeInfo(Boolean) then
Result := skBoolean
else if typeHandle = TypeInfo(Char) then
Result := skChar
else if typeHandle = TypeInfo(TDecimal) then
Result := skDecimal
else if typeHandle = TypeInfo(TTimestamp) then
Result := skTimestamp
else
// 4. Raise an exception for unsupported types.
raise EArgumentException.CreateFmt('Unsupported record field type: %s', [AType.Name]);
end;
end.