Json Schema for LLMs
This commit is contained in:
+108
-20
@@ -59,6 +59,7 @@ type
|
||||
{$endregion}
|
||||
|
||||
function FindSlot(const Name: string): Integer;
|
||||
function GetSymbolDoc(const Name: string): string;
|
||||
|
||||
// Returns all defined symbols in this layout (for debugging/reflection)
|
||||
function GetSymbols: TArray<string>;
|
||||
@@ -69,7 +70,7 @@ type
|
||||
|
||||
// 2. The Builder (Mutable).
|
||||
IScopeBuilder = interface(IScopeLayout)
|
||||
function Define(const Name: string): Integer;
|
||||
function Define(const Name: string; const Doc: string = ''): Integer;
|
||||
function Build: IScopeLayout;
|
||||
end;
|
||||
|
||||
@@ -95,7 +96,13 @@ type
|
||||
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||
{$endregion}
|
||||
|
||||
function Define(const Name: string; const Value: TDataValue; const AStaticType: IStaticType = nil): TResolvedAddress;
|
||||
function Define(
|
||||
const Name: string;
|
||||
const Value: TDataValue;
|
||||
const AStaticType: IStaticType = nil;
|
||||
const ADoc: string = ''
|
||||
): TResolvedAddress;
|
||||
|
||||
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
|
||||
@@ -129,18 +136,25 @@ uses
|
||||
System.SyncObjs;
|
||||
|
||||
type
|
||||
TSymbolMeta = record
|
||||
Slot: Integer;
|
||||
Doc: string;
|
||||
constructor Create(ASlot: Integer; const ADoc: string);
|
||||
end;
|
||||
|
||||
// --- Concrete Layout (Immutable) ---
|
||||
TScopeLayout = class(TInterfacedObject, IScopeLayout)
|
||||
private
|
||||
FParent: IScopeLayout;
|
||||
FMap: TDictionary<string, Integer>;
|
||||
FSlotCount: Integer; // Explicit slot count
|
||||
FMap: TDictionary<string, TSymbolMeta>;
|
||||
FSlotCount: Integer;
|
||||
function GetParent: IScopeLayout;
|
||||
function GetSlotCount: Integer;
|
||||
public
|
||||
constructor Create(const AParent: IScopeLayout; AMap: TDictionary<string, Integer>; ASlotCount: Integer);
|
||||
constructor Create(const AParent: IScopeLayout; AMap: TDictionary<string, TSymbolMeta>; ASlotCount: Integer);
|
||||
destructor Destroy; override;
|
||||
function FindSlot(const Name: string): Integer;
|
||||
function GetSymbolDoc(const Name: string): string;
|
||||
function GetSymbols: TArray<string>;
|
||||
end;
|
||||
|
||||
@@ -148,16 +162,17 @@ type
|
||||
TScopeBuilder = class(TInterfacedObject, IScopeBuilder, IScopeLayout)
|
||||
private
|
||||
FParentLayout: IScopeLayout;
|
||||
FMap: TDictionary<string, Integer>;
|
||||
FNextSlot: Integer; // Counter for sequential slot allocation
|
||||
FMap: TDictionary<string, TSymbolMeta>;
|
||||
FNextSlot: Integer;
|
||||
function GetParent: IScopeLayout;
|
||||
function GetSlotCount: Integer;
|
||||
public
|
||||
constructor Create(const AParentLayout: IScopeLayout);
|
||||
destructor Destroy; override;
|
||||
|
||||
function Define(const Name: string): Integer;
|
||||
function Define(const Name: string; const Doc: string): Integer;
|
||||
function FindSlot(const Name: string): Integer;
|
||||
function GetSymbolDoc(const Name: string): string;
|
||||
function GetSymbols: TArray<string>;
|
||||
function Build: IScopeLayout;
|
||||
end;
|
||||
@@ -202,6 +217,7 @@ type
|
||||
public
|
||||
constructor Create(AOwner: TExecutionScope);
|
||||
function FindSlot(const Name: string): Integer;
|
||||
function GetSymbolDoc(const Name: string): string;
|
||||
function GetSymbols: TArray<string>;
|
||||
end;
|
||||
|
||||
@@ -224,9 +240,12 @@ type
|
||||
FSlotTypes: TArray<IStaticType>;
|
||||
FValues: TArray<TScopeItem>;
|
||||
FCapturedUpvalues: TArray<IValueCell>;
|
||||
|
||||
// Dynamic Name Mapping
|
||||
FNames: TDictionary<string, Integer>;
|
||||
FNameStrings: TList<string>;
|
||||
FNameToIndex: TDictionary<Integer, Integer>;
|
||||
FDocs: TDictionary<string, string>; // Stores docs for dynamic symbols
|
||||
|
||||
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
||||
procedure NeedNameToIndex;
|
||||
@@ -242,7 +261,12 @@ type
|
||||
function GetNameID(const Name: String): Integer;
|
||||
function Resolve(const Name: string): TResolvedAddress;
|
||||
function Dump: string;
|
||||
function Define(const Name: string; const Value: TDataValue; const AStaticType: IStaticType = nil): TResolvedAddress;
|
||||
function Define(
|
||||
const Name: string;
|
||||
const Value: TDataValue;
|
||||
const AStaticType: IStaticType = nil;
|
||||
const ADoc: string = ''
|
||||
): TResolvedAddress;
|
||||
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||
|
||||
@@ -300,9 +324,17 @@ begin
|
||||
Dest.StaticType := TTypes.Unknown;
|
||||
end;
|
||||
|
||||
{ TSymbolMeta }
|
||||
|
||||
constructor TSymbolMeta.Create(ASlot: Integer; const ADoc: string);
|
||||
begin
|
||||
Slot := ASlot;
|
||||
Doc := ADoc;
|
||||
end;
|
||||
|
||||
{ TScopeLayout }
|
||||
|
||||
constructor TScopeLayout.Create(const AParent: IScopeLayout; AMap: TDictionary<string, Integer>; ASlotCount: Integer);
|
||||
constructor TScopeLayout.Create(const AParent: IScopeLayout; AMap: TDictionary<string, TSymbolMeta>; ASlotCount: Integer);
|
||||
begin
|
||||
inherited Create;
|
||||
FParent := AParent;
|
||||
@@ -317,11 +349,25 @@ begin
|
||||
end;
|
||||
|
||||
function TScopeLayout.FindSlot(const Name: string): Integer;
|
||||
var
|
||||
meta: TSymbolMeta;
|
||||
begin
|
||||
if not FMap.TryGetValue(Name, Result) then
|
||||
if FMap.TryGetValue(Name, meta) then
|
||||
Result := meta.Slot
|
||||
else
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TScopeLayout.GetSymbolDoc(const Name: string): string;
|
||||
var
|
||||
meta: TSymbolMeta;
|
||||
begin
|
||||
if FMap.TryGetValue(Name, meta) then
|
||||
Result := meta.Doc
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TScopeLayout.GetSymbols: TArray<string>;
|
||||
begin
|
||||
Result := FMap.Keys.ToArray;
|
||||
@@ -343,7 +389,7 @@ constructor TScopeBuilder.Create(const AParentLayout: IScopeLayout);
|
||||
begin
|
||||
inherited Create;
|
||||
FParentLayout := AParentLayout;
|
||||
FMap := TDictionary<string, Integer>.Create;
|
||||
FMap := TDictionary<string, TSymbolMeta>.Create;
|
||||
FNextSlot := 0;
|
||||
end;
|
||||
|
||||
@@ -353,25 +399,38 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TScopeBuilder.Define(const Name: string): Integer;
|
||||
function TScopeBuilder.Define(const Name: string; const Doc: string): Integer;
|
||||
begin
|
||||
// Rule: Shadowing / Redefinition in the same scope is forbidden.
|
||||
// The Client (Binder) must ensure this name is not already taken before calling Define.
|
||||
Assert(not FMap.ContainsKey(Name), 'Scope Error: Variable "' + Name + '" is already defined in this scope builder.');
|
||||
|
||||
// Allocate a new slot
|
||||
Result := FNextSlot;
|
||||
Inc(FNextSlot);
|
||||
|
||||
FMap.Add(Name, Result);
|
||||
FMap.Add(Name, TSymbolMeta.Create(Result, Doc));
|
||||
end;
|
||||
|
||||
function TScopeBuilder.FindSlot(const Name: string): Integer;
|
||||
var
|
||||
meta: TSymbolMeta;
|
||||
begin
|
||||
if not FMap.TryGetValue(Name, Result) then
|
||||
if FMap.TryGetValue(Name, meta) then
|
||||
Result := meta.Slot
|
||||
else
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TScopeBuilder.GetSymbolDoc(const Name: string): string;
|
||||
var
|
||||
meta: TSymbolMeta;
|
||||
begin
|
||||
if FMap.TryGetValue(Name, meta) then
|
||||
Result := meta.Doc
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TScopeBuilder.GetSymbols: TArray<string>;
|
||||
begin
|
||||
Result := FMap.Keys.ToArray;
|
||||
@@ -380,7 +439,7 @@ end;
|
||||
function TScopeBuilder.Build: IScopeLayout;
|
||||
begin
|
||||
// Pass FNextSlot as the total slot count
|
||||
Result := TScopeLayout.Create(FParentLayout, TDictionary<string, Integer>.Create(FMap), FNextSlot);
|
||||
Result := TScopeLayout.Create(FParentLayout, TDictionary<string, TSymbolMeta>.Create(FMap), FNextSlot);
|
||||
end;
|
||||
|
||||
function TScopeBuilder.GetParent: IScopeLayout;
|
||||
@@ -436,6 +495,12 @@ begin
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
function TExecutionScope.TDynamicLayout.GetSymbolDoc(const Name: string): string;
|
||||
begin
|
||||
if (FOwner.FDocs = nil) or (not FOwner.FDocs.TryGetValue(Name, Result)) then
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TExecutionScope.TDynamicLayout.GetSymbols: TArray<string>;
|
||||
begin
|
||||
Result := FOwner.FNames.Keys.ToArray;
|
||||
@@ -532,6 +597,8 @@ begin
|
||||
FNameStrings := TList<string>.Create;
|
||||
end;
|
||||
|
||||
FDocs := nil; // Initialized on demand in Define
|
||||
|
||||
if Assigned(FLayoutIntf) then
|
||||
SetLength(FValues, FLayoutIntf.SlotCount);
|
||||
end;
|
||||
@@ -544,6 +611,7 @@ begin
|
||||
FNameStrings.Free;
|
||||
FNames.Free;
|
||||
end;
|
||||
FDocs.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@@ -564,6 +632,13 @@ procedure TExecutionScope.Clear;
|
||||
begin
|
||||
FValues := [];
|
||||
FreeAndNil(FNameToIndex);
|
||||
// Docs are tied to Names which are persistent/shared, so FDocs should clear if this is the owner?
|
||||
// Actually FDocs is local to this scope instance if we define dynamic vars.
|
||||
// If we clear values, we should probably clear doc mappings too if they are tied to those values.
|
||||
// But Resolve uses FNames/FNameToIndex. If we clear FNameToIndex, existing name lookups fail.
|
||||
// FDocs is separate. Let's clear it too.
|
||||
if FDocs <> nil then
|
||||
FDocs.Clear;
|
||||
end;
|
||||
|
||||
function TExecutionScope.Capture(const Address: TResolvedAddress): IValueCell;
|
||||
@@ -602,7 +677,12 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExecutionScope.Define(const Name: string; const Value: TDataValue; const AStaticType: IStaticType): TResolvedAddress;
|
||||
function TExecutionScope.Define(
|
||||
const Name: string;
|
||||
const Value: TDataValue;
|
||||
const AStaticType: IStaticType;
|
||||
const ADoc: string
|
||||
): TResolvedAddress;
|
||||
var
|
||||
id: Integer;
|
||||
index: Integer;
|
||||
@@ -630,6 +710,14 @@ begin
|
||||
end;
|
||||
|
||||
FNameToIndex.Add(id, index);
|
||||
|
||||
if ADoc <> '' then
|
||||
begin
|
||||
if FDocs = nil then
|
||||
FDocs := TDictionary<string, string>.Create;
|
||||
FDocs.AddOrSetValue(Name, ADoc);
|
||||
end;
|
||||
|
||||
Result.Kind := akLocalOrParent;
|
||||
Result.ScopeDepth := 0;
|
||||
Result.SlotIndex := index;
|
||||
@@ -755,7 +843,7 @@ begin
|
||||
begin
|
||||
var map := (FStaticDescriptor.Layout as TScopeLayout).FMap;
|
||||
for var item in map do
|
||||
FNameToIndex.AddOrSetValue(GetNameId(item.Key), item.Value);
|
||||
FNameToIndex.AddOrSetValue(GetNameId(item.Key), item.Value.Slot);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@@ -843,7 +931,7 @@ end;
|
||||
|
||||
class function TScope.CreateRootLayout: IScopeLayout;
|
||||
begin
|
||||
Result := TScopeLayout.Create(nil, TDictionary<string, Integer>.Create, 0);
|
||||
Result := TScopeLayout.Create(nil, TDictionary<string, TSymbolMeta>.Create, 0);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user