AST Types

This commit is contained in:
Michael Schimmel
2025-10-26 09:58:42 +01:00
parent 85f2e02893
commit e379e6694c
7 changed files with 523 additions and 91 deletions
+75 -13
View File
@@ -7,12 +7,21 @@ uses
System.Generics.Collections,
System.Classes,
Myc.Data.Value,
Myc.Ast.Nodes;
Myc.Ast.Nodes,
Myc.Ast.Types;
type
IExecutionScope = interface;
IScopeDescriptor = interface;
// A resolved symbol, containing its runtime address and static type.
TResolvedSymbol = record
Address: TResolvedAddress;
StaticType: IStaticType;
constructor Create(const AAddress: TResolvedAddress; const AStaticType: IStaticType);
class operator Initialize(out Dest: TResolvedSymbol);
end;
IValueCell = interface
{$region 'private'}
function GetValue: TDataValue;
@@ -52,11 +61,16 @@ type
function GetParent: IScopeDescriptor;
function GetSlotCount: Integer;
function GetSymbols: TDictionary<string, Integer>;
function GetType(SlotIndex: Integer): IStaticType;
{$endregion}
function CreateScope(const AParent: IExecutionScope): IExecutionScope;
function Define(const Name: string): Integer;
// Defines a symbol, returns its slot index.
function Define(const Name: string; const AType: IStaticType): Integer;
// Updates the type of an already defined symbol (e.g., for lambda self-reference).
procedure UpdateType(SlotIndex: Integer; const AType: IStaticType);
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
function FindSymbol(const Name: string): TResolvedAddress;
// Finds a symbol, returns its address and type.
function FindSymbol(const Name: string): TResolvedSymbol;
function FindMacro(const Name: string): IMacroDefinitionNode;
property Parent: IScopeDescriptor read GetParent;
property SlotCount: Integer read GetSlotCount;
@@ -129,6 +143,7 @@ type
property NameStrings: TList<string> read FNameStrings;
property NameToIndex: TDictionary<Integer, Integer> read GetNameToIndex;
property Parent: IExecutionScope read FParent;
property ValuesArray: TArray<TScopeItem> read FValues; // Expose FValues for PopulateFromScope
end;
TScopeDescriptor = class(TInterfacedObject, IScopeDescriptor)
@@ -136,22 +151,39 @@ type
FParent: IScopeDescriptor;
FSymbols: TDictionary<string, Integer>;
FMacros: TDictionary<string, IMacroDefinitionNode>;
FSlotTypes: TArray<IStaticType>; // Stores types by SlotIndex
function GetParent: IScopeDescriptor;
function GetSlotCount: Integer;
function GetSymbols: TDictionary<string, Integer>;
function GetType(SlotIndex: Integer): IStaticType;
public
constructor Create(const AParent: IScopeDescriptor);
destructor Destroy; override;
class function CreateDescriptor(const Scope: IExecutionScope): IScopeDescriptor; static;
function Define(const Name: string): Integer;
function Define(const Name: string; const AType: IStaticType): Integer;
procedure UpdateType(SlotIndex: Integer; const AType: IStaticType);
procedure DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
function FindSymbol(const Name: string): TResolvedAddress;
function FindSymbol(const Name: string): TResolvedSymbol;
function FindMacro(const Name: string): IMacroDefinitionNode;
function CreateScope(const Parent: IExecutionScope): IExecutionScope;
procedure PopulateFromScope(Scope: TExecutionScope);
property Symbols: TDictionary<string, Integer> read FSymbols;
end;
{ TResolvedSymbol }
constructor TResolvedSymbol.Create(const AAddress: TResolvedAddress; const AStaticType: IStaticType);
begin
Address := AAddress;
StaticType := AStaticType;
end;
class operator TResolvedSymbol.Initialize(out Dest: TResolvedSymbol);
begin
// TResolvedAddress has its own Initialize operator
Dest.StaticType := TTypes.Unknown;
end;
{ TExecutionScope.TValueCell }
constructor TExecutionScope.TValueCell.Create(const AValue: TDataValue);
@@ -460,10 +492,12 @@ begin
FParent := AParent;
FSymbols := TDictionary<string, Integer>.Create;
FMacros := TDictionary<string, IMacroDefinitionNode>.Create;
FSlotTypes := [];
end;
destructor TScopeDescriptor.Destroy;
begin
FSlotTypes := nil;
FMacros.Free;
FSymbols.Free;
inherited;
@@ -486,10 +520,19 @@ begin
Result := TExecutionScope.Create(Parent, Self, nil);
end;
function TScopeDescriptor.Define(const Name: string): Integer;
function TScopeDescriptor.Define(const Name: string; const AType: IStaticType): Integer;
begin
Result := FSymbols.Count;
FSymbols.Add(Name, Result);
SetLength(FSlotTypes, Result + 1);
FSlotTypes[Result] := AType;
end;
procedure TScopeDescriptor.UpdateType(SlotIndex: Integer; const AType: IStaticType);
begin
if (SlotIndex < 0) or (SlotIndex >= Length(FSlotTypes)) then
raise EArgumentOutOfRangeException.Create('Invalid SlotIndex in UpdateType.');
FSlotTypes[SlotIndex] := AType;
end;
procedure TScopeDescriptor.DefineMacro(const Name: string; const Node: IMacroDefinitionNode);
@@ -512,21 +555,25 @@ begin
end;
end;
function TScopeDescriptor.FindSymbol(const Name: string): TResolvedAddress;
function TScopeDescriptor.FindSymbol(const Name: string): TResolvedSymbol;
var
currentDescriptor: IScopeDescriptor;
slotIndex: Integer;
begin
Result.Kind := akUnresolved;
Result.ScopeDepth := 0;
Result.Address.Kind := akUnresolved;
Result.Address.ScopeDepth := 0;
Result.StaticType := TTypes.Unknown;
currentDescriptor := Self;
while Assigned(currentDescriptor) do
begin
if currentDescriptor.Symbols.TryGetValue(Name, Result.SlotIndex) then
if currentDescriptor.Symbols.TryGetValue(Name, slotIndex) then
begin
Result.Kind := akLocalOrParent;
Result.Address.Kind := akLocalOrParent;
Result.Address.SlotIndex := slotIndex;
Result.StaticType := currentDescriptor.GetType(slotIndex);
exit;
end;
inc(Result.ScopeDepth);
inc(Result.Address.ScopeDepth);
currentDescriptor := currentDescriptor.Parent;
end;
end;
@@ -546,11 +593,23 @@ begin
Result := FSymbols;
end;
function TScopeDescriptor.GetType(SlotIndex: Integer): IStaticType;
begin
if (SlotIndex < 0) or (SlotIndex >= Length(FSlotTypes)) then
raise EArgumentOutOfRangeException.Create('Invalid SlotIndex in GetType.');
Result := FSlotTypes[SlotIndex];
end;
procedure TScopeDescriptor.PopulateFromScope(Scope: TExecutionScope);
var
val: TDataValue;
i: Integer;
begin
// Recreate descriptor by iterating all defined symbols in the runtime scope.
SetLength(FSlotTypes, Length(Scope.ValuesArray)); // Size the array
for i := 0 to High(FSlotTypes) do
FSlotTypes[i] := TTypes.Unknown; // Fill with Unknown
for var pair in Scope.NameToIndex do
begin
var name := Scope.NameStrings[pair.Key];
@@ -560,8 +619,11 @@ begin
if not FSymbols.ContainsKey(name) then
FSymbols.Add(name, slotIndex);
// We cannot recover the static type from the runtime scope.
// FSlotTypes[slotIndex] remains TTypes.Unknown.
// Check if the symbol is also a macro and add it to the macro table.
val := Scope.FValues[slotIndex].Value;
val := Scope.ValuesArray[slotIndex].Value;
if (val.Kind = vkInterface) and (val.AsIntf<IAstNode> is TMacroDefinitionNode) then
begin
if not FMacros.ContainsKey(name) then