Json Schema for LLMs
This commit is contained in:
@@ -98,7 +98,8 @@ type
|
|||||||
|
|
||||||
function Run(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []; const Args: TArray<TDataValue> = []): TDataValue;
|
function Run(const ANode: IAstNode; const Params: TArray<IIdentifierNode> = []; const Args: TArray<TDataValue> = []): TDataValue;
|
||||||
|
|
||||||
procedure Define(const Name: String; const AScript: IAstNode);
|
// UPDATED: Now supports Documentation
|
||||||
|
procedure Define(const Name: String; const AScript: IAstNode; const Doc: string = '');
|
||||||
|
|
||||||
property Environment: IEnvironment read FEnvironment;
|
property Environment: IEnvironment read FEnvironment;
|
||||||
property RootScope: IExecutionScope read GetRootScope;
|
property RootScope: IExecutionScope read GetRootScope;
|
||||||
@@ -261,11 +262,12 @@ begin
|
|||||||
Result := FEnvironment.CreateEnvironment;
|
Result := FEnvironment.CreateEnvironment;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAstEnvironment.Define(const Name: String; const AScript: IAstNode);
|
procedure TAstEnvironment.Define(const Name: String; const AScript: IAstNode; const Doc: string);
|
||||||
begin
|
begin
|
||||||
var compiled := Compile(AScript);
|
var compiled := Compile(AScript);
|
||||||
var linked := Link(compiled);
|
var linked := Link(compiled);
|
||||||
RootScope.Define(Name, linked.Func([]), compiled.StaticType);
|
// Pass the documentation to the scope
|
||||||
|
RootScope.Define(Name, linked.Func([]), compiled.StaticType, Doc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAstEnvironment.ExpandMacros(const Node: IAstNode): IAstNode;
|
function TAstEnvironment.ExpandMacros(const Node: IAstNode): IAstNode;
|
||||||
@@ -425,9 +427,6 @@ begin
|
|||||||
if lg.HasErrors then
|
if lg.HasErrors then
|
||||||
raise ECompilationFailed.Create(lg.GetEntries);
|
raise ECompilationFailed.Create(lg.GetEntries);
|
||||||
|
|
||||||
// Note: If types are Unknown but no errors were logged (edge case), we proceed.
|
|
||||||
// But Binder/TypeChecker logic ensures errors are logged for Unknowns that matter.
|
|
||||||
|
|
||||||
var specialized := Specialize(typedNode);
|
var specialized := Specialize(typedNode);
|
||||||
|
|
||||||
Result := specialized.AsLambdaExpression;
|
Result := specialized.AsLambdaExpression;
|
||||||
@@ -471,7 +470,6 @@ begin
|
|||||||
var cExecutionStrategy := FExecutionStrategy;
|
var cExecutionStrategy := FExecutionStrategy;
|
||||||
|
|
||||||
// The Glue: This callback performs the full compilation pipeline for a macro argument expression.
|
// The Glue: This callback performs the full compilation pipeline for a macro argument expression.
|
||||||
// It binds the node to the layout of the temporary macro scope and then executes it.
|
|
||||||
var macroEvaluator: TMacroEvaluatorProc :=
|
var macroEvaluator: TMacroEvaluatorProc :=
|
||||||
function(const Scope: IExecutionScope; const ANode: IAstNode): TDataValue
|
function(const Scope: IExecutionScope; const ANode: IAstNode): TDataValue
|
||||||
var
|
var
|
||||||
@@ -485,15 +483,12 @@ begin
|
|||||||
tempLog := TCompilerLog.Create;
|
tempLog := TCompilerLog.Create;
|
||||||
|
|
||||||
// 1. Binding
|
// 1. Binding
|
||||||
// Note: Scope is dynamic (from TMacroExpander), so Descriptor.Layout describes current variables.
|
|
||||||
boundSubAst := TAstBinder.Bind(Scope.Descriptor.Layout, ANode, tmpLayout, tempLog);
|
boundSubAst := TAstBinder.Bind(Scope.Descriptor.Layout, ANode, tmpLayout, tempLog);
|
||||||
|
|
||||||
// Macro execution is strictly fail-fast. If we can't bind arguments, we can't run the macro.
|
|
||||||
if tempLog.HasErrors then
|
if tempLog.HasErrors then
|
||||||
raise EMacroException.Create('Macro Argument Error: ' + tempLog.GetEntries[0].Message);
|
raise EMacroException.Create('Macro Argument Error: ' + tempLog.GetEntries[0].Message);
|
||||||
|
|
||||||
// 2. Scope Matching
|
// 2. Scope Matching
|
||||||
// Create a child scope to ensure correct depth resolution (Binder sees Layout at depth 0 relative to itself)
|
|
||||||
scratchScope := TScope.CreateScope(Scope, nil, nil);
|
scratchScope := TScope.CreateScope(Scope, nil, nil);
|
||||||
|
|
||||||
// 3. Execution
|
// 3. Execution
|
||||||
|
|||||||
+109
-116
@@ -14,23 +14,17 @@ uses
|
|||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Attributes,
|
Myc.Ast.Attributes,
|
||||||
Myc.Ast.RTL,
|
|
||||||
Myc.Ast.RTL.Core,
|
|
||||||
Myc.Ast.Scope,
|
Myc.Ast.Scope,
|
||||||
Myc.Ast.Types,
|
Myc.Ast.Types,
|
||||||
Myc.Ast.Script,
|
Myc.Ast.Script,
|
||||||
Myc.Ast.Json;
|
Myc.Ast.Json,
|
||||||
|
Myc.Ast;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Scans AST, RTL and Scope metadata to generate a context-aware LLM system prompt. }
|
{ Scans AST, RTL and Scope metadata to generate a context-aware LLM system prompt. }
|
||||||
TAstSchema = class
|
TAstSchema = class
|
||||||
strict private
|
strict private
|
||||||
type
|
type
|
||||||
TRtlMeta = record
|
|
||||||
Doc: string;
|
|
||||||
Signatures: TArray<string>;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TFieldInfo = record
|
TFieldInfo = record
|
||||||
Idx: Integer;
|
Idx: Integer;
|
||||||
Name: string;
|
Name: string;
|
||||||
@@ -39,18 +33,17 @@ type
|
|||||||
|
|
||||||
class function GetTsType(Kind: TFieldKind): string; static;
|
class function GetTsType(Kind: TFieldKind): string; static;
|
||||||
class function TypeToTs(const AType: IStaticType): string; static;
|
class function TypeToTs(const AType: IStaticType): string; static;
|
||||||
class function GetRtlMetadata: TDictionary<string, TRtlMeta>; static;
|
|
||||||
public
|
public
|
||||||
// Generates the TypeScript definition for AST nodes
|
// Generates the TypeScript definition for AST nodes using RTTI on the Node Interfaces
|
||||||
class function GenerateTypeScriptDefinition: string; static;
|
class function GenerateTypeScriptDefinition: string; static;
|
||||||
|
|
||||||
// Unified section: Lists only symbols available in the current scope with their docs/types
|
// Unified section: Lists symbols available in the given scope with their docs and types.
|
||||||
class function GenerateAvailableSymbols(const AScope: IExecutionScope): string; static;
|
class function GenerateAvailableSymbols(const AScope: IExecutionScope): string; static;
|
||||||
|
|
||||||
// Documentation for all RTL functions (used as fallback or for general prompts)
|
// Generates documentation for the standard library by creating a temporary scope.
|
||||||
class function GenerateAllRtlDocumentation: string; static;
|
class function GenerateAllRtlDocumentation: string; static;
|
||||||
|
|
||||||
// Detailed generation rules
|
// Detailed generation rules for the LLM
|
||||||
class function GenerateGenerationRules: string; static;
|
class function GenerateGenerationRules: string; static;
|
||||||
|
|
||||||
// The final consolidated system prompt for the AI
|
// The final consolidated system prompt for the AI
|
||||||
@@ -81,37 +74,106 @@ begin
|
|||||||
exit('any');
|
exit('any');
|
||||||
|
|
||||||
case AType.Kind of
|
case AType.Kind of
|
||||||
|
stUnknown: Result := 'any';
|
||||||
|
stVoid: Result := 'void';
|
||||||
stOrdinal, stFloat: Result := 'number';
|
stOrdinal, stFloat: Result := 'number';
|
||||||
stBoolean: Result := 'boolean';
|
stBoolean: Result := 'boolean';
|
||||||
stDateTime: Result := 'datetime';
|
stDateTime: Result := 'datetime';
|
||||||
stText: Result := 'string';
|
stText: Result := 'string';
|
||||||
stKeyword: Result := 'keyword';
|
stKeyword: Result := 'keyword';
|
||||||
|
|
||||||
stSeries: Result := Format('Series<%s>', [TypeToTs(AType.AsSeries.ElementType)]);
|
stSeries: Result := Format('Series<%s>', [TypeToTs(AType.AsSeries.ElementType)]);
|
||||||
|
|
||||||
stRecord:
|
stRecord:
|
||||||
begin
|
begin
|
||||||
var def := AType.AsRecord.Definition;
|
var def := AType.AsRecord.Definition;
|
||||||
var fields := TList<string>.Create;
|
var fields := TList<string>.Create;
|
||||||
try
|
try
|
||||||
for var i := 0 to def.Count - 1 do
|
for var i := 0 to def.Count - 1 do
|
||||||
fields.Add(Format('%s: %s', [def.Keywords[i].Name, def[i].ToString.ToLower]));
|
begin
|
||||||
|
var k := def.Keywords[i].Name;
|
||||||
|
var tStr: string;
|
||||||
|
case def[i] of
|
||||||
|
TScalar.TKind.Ordinal, TScalar.TKind.Float: tStr := 'number';
|
||||||
|
TScalar.TKind.Boolean: tStr := 'boolean';
|
||||||
|
TScalar.TKind.DateTime: tStr := 'datetime';
|
||||||
|
TScalar.TKind.Keyword: tStr := 'keyword';
|
||||||
|
else
|
||||||
|
tStr := 'any';
|
||||||
|
end;
|
||||||
|
fields.Add(Format('%s: %s', [k, tStr]));
|
||||||
|
end;
|
||||||
Result := '{ ' + string.Join(', ', fields.ToArray) + ' }';
|
Result := '{ ' + string.Join(', ', fields.ToArray) + ' }';
|
||||||
finally
|
finally
|
||||||
fields.Free;
|
fields.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
stGenericRecord:
|
||||||
|
begin
|
||||||
|
var def := AType.AsGenericRecord.GenericDefinition;
|
||||||
|
var fields := TList<string>.Create;
|
||||||
|
try
|
||||||
|
for var i := 0 to def.Count - 1 do
|
||||||
|
fields.Add(Format('%s: %s', [def.Keywords[i].Name, TypeToTs(def[i])]));
|
||||||
|
Result := '{ ' + string.Join(', ', fields.ToArray) + ' }';
|
||||||
|
finally
|
||||||
|
fields.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
stRecordSeries: Result := 'Stream<' + TypeToTs(TTypes.CreateRecord(AType.AsRecord.Definition)) + '>';
|
stRecordSeries: Result := 'Stream<' + TypeToTs(TTypes.CreateRecord(AType.AsRecord.Definition)) + '>';
|
||||||
|
|
||||||
|
stTuple:
|
||||||
|
begin
|
||||||
|
var elems := AType.AsTuple.Elements;
|
||||||
|
var elemStrings := TList<string>.Create;
|
||||||
|
try
|
||||||
|
for var t in elems do
|
||||||
|
elemStrings.Add(TypeToTs(t));
|
||||||
|
Result := '[' + string.Join(', ', elemStrings.ToArray) + ']';
|
||||||
|
finally
|
||||||
|
elemStrings.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
stVector: Result := TypeToTs(AType.AsVector.ElementType) + '[]';
|
||||||
|
|
||||||
|
stMatrix:
|
||||||
|
begin
|
||||||
|
var dims := AType.AsMatrix.Dimensions;
|
||||||
|
Result := TypeToTs(AType.AsMatrix.ElementType);
|
||||||
|
for var k := 0 to High(dims) do
|
||||||
|
Result := Result + '[]';
|
||||||
|
end;
|
||||||
|
|
||||||
stMethod:
|
stMethod:
|
||||||
begin
|
begin
|
||||||
if Length(AType.AsMethod.Signatures) = 0 then
|
var signatures := AType.AsMethod.Signatures;
|
||||||
|
if Length(signatures) = 0 then
|
||||||
exit('function');
|
exit('function');
|
||||||
var sig := AType.AsMethod.Signatures[0];
|
|
||||||
var args := TList<string>.Create;
|
var sigStrings := TList<string>.Create;
|
||||||
try
|
try
|
||||||
for var p in sig.ParamTypes do
|
for var sig in signatures do
|
||||||
args.Add(TypeToTs(p));
|
begin
|
||||||
Result := Format('(%s) => %s', [string.Join(', ', args.ToArray), TypeToTs(sig.ReturnType)]);
|
var args := TList<string>.Create;
|
||||||
|
try
|
||||||
|
for var p in sig.ParamTypes do
|
||||||
|
args.Add(TypeToTs(p));
|
||||||
|
|
||||||
|
var s := Format('(%s) => %s', [string.Join(', ', args.ToArray), TypeToTs(sig.ReturnType)]);
|
||||||
|
|
||||||
|
// Deduplicate: If multiple RTL overloads map to the same TS signature, only show it once.
|
||||||
|
if not sigStrings.Contains(s) then
|
||||||
|
sigStrings.Add(s);
|
||||||
|
finally
|
||||||
|
args.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := string.Join(' | ', sigStrings.ToArray);
|
||||||
finally
|
finally
|
||||||
args.Free;
|
sigStrings.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
else
|
else
|
||||||
@@ -122,56 +184,6 @@ begin
|
|||||||
Result := Result + ' | null';
|
Result := Result + ' | null';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAstSchema.GetRtlMetadata: TDictionary<string, TRtlMeta>;
|
|
||||||
var
|
|
||||||
ctx: TRttiContext;
|
|
||||||
typ: TRttiType;
|
|
||||||
meth: TRttiMethod;
|
|
||||||
attr: TCustomAttribute;
|
|
||||||
meta: TRtlMeta;
|
|
||||||
rtlName: string;
|
|
||||||
sigs: TList<string>;
|
|
||||||
begin
|
|
||||||
Result := TDictionary<string, TRtlMeta>.Create;
|
|
||||||
sigs := TList<string>.Create;
|
|
||||||
try
|
|
||||||
typ := ctx.GetType(TypeInfo(TRtlFunctions));
|
|
||||||
for meth in typ.GetMethods do
|
|
||||||
begin
|
|
||||||
rtlName := '';
|
|
||||||
meta.Doc := '';
|
|
||||||
sigs.Clear;
|
|
||||||
for attr in meth.GetAttributes do
|
|
||||||
begin
|
|
||||||
if attr is AstDocAttribute then
|
|
||||||
meta.Doc := AstDocAttribute(attr).Description;
|
|
||||||
if attr is TRtlExportAttribute then
|
|
||||||
rtlName := TRtlExportAttribute(attr).Name;
|
|
||||||
if attr is AstSignatureAttribute then
|
|
||||||
sigs.Add(AstSignatureAttribute(attr).Signature);
|
|
||||||
end;
|
|
||||||
if rtlName <> '' then
|
|
||||||
begin
|
|
||||||
meta.Signatures := sigs.ToArray;
|
|
||||||
if Result.ContainsKey(rtlName) then
|
|
||||||
begin
|
|
||||||
var existing := Result[rtlName];
|
|
||||||
var combinedSigs := TList<string>.Create;
|
|
||||||
combinedSigs.AddRange(existing.Signatures);
|
|
||||||
combinedSigs.AddRange(meta.Signatures);
|
|
||||||
existing.Signatures := combinedSigs.ToArray;
|
|
||||||
combinedSigs.Free;
|
|
||||||
Result[rtlName] := existing;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Result.Add(rtlName, meta);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
finally
|
|
||||||
sigs.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
class function TAstSchema.GenerateTypeScriptDefinition: string;
|
class function TAstSchema.GenerateTypeScriptDefinition: string;
|
||||||
var
|
var
|
||||||
ctx: TRttiContext;
|
ctx: TRttiContext;
|
||||||
@@ -215,6 +227,7 @@ begin
|
|||||||
if exampleList = nil then
|
if exampleList = nil then
|
||||||
exampleList := TList<string>.Create;
|
exampleList := TList<string>.Create;
|
||||||
try
|
try
|
||||||
|
// Parse example script to ensure valid JSON output in documentation
|
||||||
var node := TAstScript.Parse(AstScriptExampleAttribute(attr).Script);
|
var node := TAstScript.Parse(AstScriptExampleAttribute(attr).Script);
|
||||||
var jsonVal := jsonConv.Serialize(node);
|
var jsonVal := jsonConv.Serialize(node);
|
||||||
try
|
try
|
||||||
@@ -224,7 +237,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
exampleList.Add('/* Error in example */');
|
exampleList.Add('/* Error in example: ' + E.Message + ' */');
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if attr is AstFieldAttribute then
|
if attr is AstFieldAttribute then
|
||||||
@@ -309,87 +322,67 @@ end;
|
|||||||
class function TAstSchema.GenerateAvailableSymbols(const AScope: IExecutionScope): string;
|
class function TAstSchema.GenerateAvailableSymbols(const AScope: IExecutionScope): string;
|
||||||
var
|
var
|
||||||
sb: TStringBuilder;
|
sb: TStringBuilder;
|
||||||
rtlMeta: TDictionary<string, TRtlMeta>;
|
|
||||||
layout: IScopeLayout;
|
layout: IScopeLayout;
|
||||||
|
descriptor: IScopeDescriptor;
|
||||||
symbols: TArray<string>;
|
symbols: TArray<string>;
|
||||||
name: string;
|
name, doc: string;
|
||||||
meta: TRtlMeta;
|
|
||||||
typ: IStaticType;
|
typ: IStaticType;
|
||||||
|
slot: Integer;
|
||||||
begin
|
begin
|
||||||
if not Assigned(AScope) then
|
if not Assigned(AScope) then
|
||||||
exit('');
|
exit('');
|
||||||
|
|
||||||
rtlMeta := GetRtlMetadata;
|
|
||||||
sb := TStringBuilder.Create;
|
sb := TStringBuilder.Create;
|
||||||
try
|
try
|
||||||
layout := AScope.Descriptor.Layout;
|
descriptor := AScope.Descriptor;
|
||||||
|
layout := descriptor.Layout;
|
||||||
symbols := layout.GetSymbols;
|
symbols := layout.GetSymbols;
|
||||||
TArray.Sort<string>(symbols);
|
TArray.Sort<string>(symbols);
|
||||||
|
|
||||||
sb.AppendLine('### 3. Available Symbols (Environment & Library)');
|
sb.AppendLine('### Available Symbols (Environment & Library)');
|
||||||
sb.AppendLine('The following symbols are currently defined and can be used in your script:');
|
sb.AppendLine('The following symbols are currently defined and can be used in your script:');
|
||||||
sb.AppendLine;
|
sb.AppendLine;
|
||||||
|
|
||||||
for name in symbols do
|
for name in symbols do
|
||||||
begin
|
begin
|
||||||
|
// Filter internal compiler symbols
|
||||||
if name.StartsWith('<') or name.EndsWith('>') then
|
if name.StartsWith('<') or name.EndsWith('>') then
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
slot := layout.FindSlot(name);
|
||||||
|
typ := descriptor.GetSymbolType(slot);
|
||||||
|
doc := layout.GetSymbolDoc(name);
|
||||||
|
|
||||||
sb.Append(Format('- `%s`', [name]));
|
sb.Append(Format('- `%s`', [name]));
|
||||||
|
|
||||||
if rtlMeta.TryGetValue(name, meta) then
|
if (typ <> nil) then
|
||||||
begin
|
|
||||||
if Length(meta.Signatures) > 0 then
|
|
||||||
sb.Append(': ' + string.Join(' | ', meta.Signatures));
|
|
||||||
if meta.Doc <> '' then
|
|
||||||
sb.Append(' — ' + meta.Doc);
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
typ := AScope.Descriptor.GetSymbolType(layout.FindSlot(name));
|
|
||||||
sb.Append(': ' + TypeToTs(typ));
|
sb.Append(': ' + TypeToTs(typ));
|
||||||
end;
|
|
||||||
|
if doc <> '' then
|
||||||
|
sb.Append(' — ' + doc);
|
||||||
|
|
||||||
sb.AppendLine;
|
sb.AppendLine;
|
||||||
end;
|
end;
|
||||||
Result := sb.ToString;
|
Result := sb.ToString;
|
||||||
finally
|
finally
|
||||||
sb.Free;
|
sb.Free;
|
||||||
rtlMeta.Free;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAstSchema.GenerateAllRtlDocumentation: string;
|
class function TAstSchema.GenerateAllRtlDocumentation: string;
|
||||||
var
|
|
||||||
rtlMeta: TDictionary<string, TRtlMeta>;
|
|
||||||
sb: TStringBuilder;
|
|
||||||
pair: TPair<string, TRtlMeta>;
|
|
||||||
begin
|
begin
|
||||||
rtlMeta := GetRtlMetadata;
|
// Create a temporary root scope.
|
||||||
sb := TStringBuilder.Create;
|
// The True parameter triggers the registration of all standard libraries (RTL).
|
||||||
try
|
// This populates the scope with function definitions and their documentation strings.
|
||||||
sb.AppendLine('### 3. Runtime Library (Global Functions)');
|
var tempScope := TAst.CreateScope(nil, nil, True);
|
||||||
sb.AppendLine;
|
Result := GenerateAvailableSymbols(tempScope);
|
||||||
for pair in rtlMeta do
|
|
||||||
begin
|
|
||||||
sb.Append(Format('- `%s`', [pair.Key]));
|
|
||||||
if Length(pair.Value.Signatures) > 0 then
|
|
||||||
sb.Append(': ' + string.Join(' | ', pair.Value.Signatures));
|
|
||||||
if pair.Value.Doc <> '' then
|
|
||||||
sb.Append(' — ' + pair.Value.Doc);
|
|
||||||
sb.AppendLine;
|
|
||||||
end;
|
|
||||||
Result := sb.ToString;
|
|
||||||
finally
|
|
||||||
sb.Free;
|
|
||||||
rtlMeta.Free;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAstSchema.GenerateGenerationRules: string;
|
class function TAstSchema.GenerateGenerationRules: string;
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
'''
|
'''
|
||||||
**⚠️ CRITICAL GENERATION RULES:**
|
**CRITICAL GENERATION RULES:**
|
||||||
|
|
||||||
1. **NO JSON OBJECTS:** Do not use `{}`. Every node MUST be a JSON Array `["Tag", Arg1, Arg2]`.
|
1. **NO JSON OBJECTS:** Do not use `{}`. Every node MUST be a JSON Array `["Tag", Arg1, Arg2]`.
|
||||||
2. **EXPLICIT TUPLES:** Fields defined as `Tuple` MUST be wrapped in `["Tuple", [...]]`.
|
2. **EXPLICIT TUPLES:** Fields defined as `Tuple` MUST be wrapped in `["Tuple", [...]]`.
|
||||||
@@ -412,12 +405,12 @@ begin
|
|||||||
You are a compiler frontend for a domain-specific scripting language.
|
You are a compiler frontend for a domain-specific scripting language.
|
||||||
Your task is to generate a valid Abstract Syntax Tree (AST) in a specific Compact JSON format.
|
Your task is to generate a valid Abstract Syntax Tree (AST) in a specific Compact JSON format.
|
||||||
|
|
||||||
### 1. AST Schema (TypeScript Definition)
|
### AST Schema (TypeScript Definition)
|
||||||
'''
|
'''
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ GenerateTypeScriptDefinition
|
+ GenerateTypeScriptDefinition
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ '### 2. Constraints & Rules'
|
+ '### Constraints & Rules'
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ GenerateGenerationRules
|
+ GenerateGenerationRules
|
||||||
+ sLineBreak;
|
+ sLineBreak;
|
||||||
|
|||||||
@@ -3,12 +3,17 @@ unit Myc.Ast.RTL.Core;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
system.sysutils,
|
System.SysUtils,
|
||||||
|
System.Math,
|
||||||
|
System.DateUtils,
|
||||||
|
System.Generics.Collections,
|
||||||
Myc.Utils,
|
Myc.Utils,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
Myc.Ast.RTL,
|
Myc.Ast.RTL,
|
||||||
Myc.Ast.Attributes;
|
Myc.Ast.Attributes,
|
||||||
|
Myc.Data.Keyword,
|
||||||
|
Myc.Data.Series;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Contains the native implementations for the Myc standard library. }
|
{ Contains the native implementations for the Myc standard library. }
|
||||||
@@ -325,12 +330,6 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
|
||||||
System.Generics.Collections,
|
|
||||||
System.Math,
|
|
||||||
System.Dateutils,
|
|
||||||
Myc.Data.Decimal;
|
|
||||||
|
|
||||||
{ TRtlFunctions - Operator Implementations }
|
{ TRtlFunctions - Operator Implementations }
|
||||||
|
|
||||||
class function TRtlFunctions.Add(const Args: TArray<TDataValue>): TDataValue;
|
class function TRtlFunctions.Add(const Args: TArray<TDataValue>): TDataValue;
|
||||||
|
|||||||
@@ -56,11 +56,13 @@ type
|
|||||||
|
|
||||||
// --- Factories ---
|
// --- Factories ---
|
||||||
// Registers a factory function. T must be registered via RegisterType<T> first.
|
// Registers a factory function. T must be registered via RegisterType<T> first.
|
||||||
|
// UPDATED: Now supports documentation parameter.
|
||||||
class procedure RegisterFactory<T: IInterface>(
|
class procedure RegisterFactory<T: IInterface>(
|
||||||
const Scope: IExecutionScope;
|
const Scope: IExecutionScope;
|
||||||
const FactoryName: string;
|
const FactoryName: string;
|
||||||
const FactoryArgs: TArray<IStaticType>;
|
const FactoryArgs: TArray<IStaticType>;
|
||||||
const FactoryDelegate: TInterfaceFactoryDelegate<T>
|
const FactoryDelegate: TInterfaceFactoryDelegate<T>;
|
||||||
|
const Doc: string = ''
|
||||||
);
|
);
|
||||||
|
|
||||||
// --- Resolution ---
|
// --- Resolution ---
|
||||||
@@ -176,8 +178,6 @@ begin
|
|||||||
var rIntf := rType as TRttiInterfaceType;
|
var rIntf := rType as TRttiInterfaceType;
|
||||||
// If the Interface has an "Invoke" method and is marked as reference-to (or is generic TFunc/TProc),
|
// If the Interface has an "Invoke" method and is marked as reference-to (or is generic TFunc/TProc),
|
||||||
// map it directly to stMethod.
|
// map it directly to stMethod.
|
||||||
// Note: RTTI for "IsReferenceTo" is not always directly available,
|
|
||||||
// but we can check if there is exactly one method named "Invoke".
|
|
||||||
var method := rIntf.GetMethod('Invoke');
|
var method := rIntf.GetMethod('Invoke');
|
||||||
if Assigned(method) and (Length(rIntf.GetMethods) = 1) then
|
if Assigned(method) and (Length(rIntf.GetMethods) = 1) then
|
||||||
begin
|
begin
|
||||||
@@ -496,7 +496,8 @@ class procedure TRtlTypeRegistry.RegisterFactory<T>(
|
|||||||
const Scope: IExecutionScope;
|
const Scope: IExecutionScope;
|
||||||
const FactoryName: string;
|
const FactoryName: string;
|
||||||
const FactoryArgs: TArray<IStaticType>;
|
const FactoryArgs: TArray<IStaticType>;
|
||||||
const FactoryDelegate: TInterfaceFactoryDelegate<T>
|
const FactoryDelegate: TInterfaceFactoryDelegate<T>;
|
||||||
|
const Doc: string
|
||||||
);
|
);
|
||||||
var
|
var
|
||||||
staticType: IStaticType;
|
staticType: IStaticType;
|
||||||
@@ -518,7 +519,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
var factorySig := TTypes.CreateMethod(FactoryArgs, staticType);
|
var factorySig := TTypes.CreateMethod(FactoryArgs, staticType);
|
||||||
Scope.Define(FactoryName, TDataValue(factoryWrapper), factorySig);
|
Scope.Define(FactoryName, TDataValue(factoryWrapper), factorySig, Doc);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+17
-11
@@ -60,6 +60,7 @@ type
|
|||||||
public
|
public
|
||||||
DynamicWrapper: TDataValue.TFunc;
|
DynamicWrapper: TDataValue.TFunc;
|
||||||
Signatures: TList<IMethodSignature>;
|
Signatures: TList<IMethodSignature>;
|
||||||
|
Doc: string; // Documentation string from AstDoc attribute
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
@@ -145,6 +146,7 @@ uses
|
|||||||
System.TypInfo,
|
System.TypInfo,
|
||||||
System.Hash,
|
System.Hash,
|
||||||
System.StrUtils,
|
System.StrUtils,
|
||||||
|
Myc.Ast.Attributes,
|
||||||
Myc.Ast.RTL.Core;
|
Myc.Ast.RTL.Core;
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -228,6 +230,7 @@ begin
|
|||||||
inherited Create;
|
inherited Create;
|
||||||
Signatures := TList<IMethodSignature>.Create;
|
Signatures := TList<IMethodSignature>.Create;
|
||||||
DynamicWrapper := nil;
|
DynamicWrapper := nil;
|
||||||
|
Doc := '';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TRtlFunctionInfo.Destroy;
|
destructor TRtlFunctionInfo.Destroy;
|
||||||
@@ -262,6 +265,7 @@ var
|
|||||||
rttiParams: TArray<TRttiParameter>;
|
rttiParams: TArray<TRttiParameter>;
|
||||||
isDynamic: Boolean;
|
isDynamic: Boolean;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
docString: string;
|
||||||
begin
|
begin
|
||||||
// 1. Create global caches
|
// 1. Create global caches
|
||||||
FStaticBootstrap := TStaticBootstrapCache.Create(TStaticSignatureKeyComparer.Create);
|
FStaticBootstrap := TStaticBootstrapCache.Create(TStaticSignatureKeyComparer.Create);
|
||||||
@@ -278,13 +282,14 @@ begin
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
exportAttr := nil;
|
exportAttr := nil;
|
||||||
|
docString := '';
|
||||||
|
|
||||||
for attribute in method.GetAttributes do
|
for attribute in method.GetAttributes do
|
||||||
begin
|
begin
|
||||||
if attribute is TRtlExportAttribute then
|
if attribute is TRtlExportAttribute then
|
||||||
begin
|
exportAttr := attribute as TRtlExportAttribute
|
||||||
exportAttr := attribute as TRtlExportAttribute;
|
else if attribute is AstDocAttribute then
|
||||||
break;
|
docString := AstDocAttribute(attribute).Description;
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if not Assigned(exportAttr) then
|
if not Assigned(exportAttr) then
|
||||||
@@ -298,6 +303,10 @@ begin
|
|||||||
FStaticFuncMap.Add(rtlName, funcInfo);
|
FStaticFuncMap.Add(rtlName, funcInfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// Update documentation (if not already set or override)
|
||||||
|
if (funcInfo.Doc = '') and (docString <> '') then
|
||||||
|
funcInfo.Doc := docString;
|
||||||
|
|
||||||
// Check Signature Type (Dynamic vs Static)
|
// Check Signature Type (Dynamic vs Static)
|
||||||
rttiParams := method.GetParameters;
|
rttiParams := method.GetParameters;
|
||||||
isDynamic :=
|
isDynamic :=
|
||||||
@@ -346,10 +355,6 @@ begin
|
|||||||
if (not Assigned(funcInfo.DynamicWrapper)) and (Length(argTypes) = 1) and (argTypes[0].Kind = stUnknown) then
|
if (not Assigned(funcInfo.DynamicWrapper)) and (Length(argTypes) = 1) and (argTypes[0].Kind = stUnknown) then
|
||||||
begin
|
begin
|
||||||
funcInfo.DynamicWrapper := wrapper;
|
funcInfo.DynamicWrapper := wrapper;
|
||||||
end
|
|
||||||
else if (not Assigned(funcInfo.DynamicWrapper)) and (Length(argTypes) = 2) and (argTypes[0].Kind = stUnknown) then
|
|
||||||
begin
|
|
||||||
// Potentially handle 2-arg scalar wrappers here too if needed
|
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -492,7 +497,8 @@ begin
|
|||||||
|
|
||||||
var wrapper := funcInfo.DynamicWrapper; // Default is Void
|
var wrapper := funcInfo.DynamicWrapper; // Default is Void
|
||||||
|
|
||||||
AScope.Define(rtlName, wrapper, staticType);
|
// Pass documentation to scope definition
|
||||||
|
AScope.Define(rtlName, wrapper, staticType, funcInfo.Doc);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -766,8 +772,8 @@ end;
|
|||||||
|
|
||||||
procedure RegisterRtlFunctions(const AScope: IExecutionScope);
|
procedure RegisterRtlFunctions(const AScope: IExecutionScope);
|
||||||
begin
|
begin
|
||||||
AScope.Define('true', TDataValue(TScalar.FromBoolean(True)), TTypes.Boolean);
|
AScope.Define('true', TDataValue(TScalar.FromBoolean(True)), TTypes.Boolean, 'Boolean true.');
|
||||||
AScope.Define('false', TDataValue(TScalar.FromBoolean(False)), TTypes.Boolean);
|
AScope.Define('false', TDataValue(TScalar.FromBoolean(False)), TTypes.Boolean, 'Boolean false.');
|
||||||
|
|
||||||
TRtlRegistry.RegisterAll(AScope);
|
TRtlRegistry.RegisterAll(AScope);
|
||||||
end;
|
end;
|
||||||
|
|||||||
+108
-20
@@ -59,6 +59,7 @@ type
|
|||||||
{$endregion}
|
{$endregion}
|
||||||
|
|
||||||
function FindSlot(const Name: string): Integer;
|
function FindSlot(const Name: string): Integer;
|
||||||
|
function GetSymbolDoc(const Name: string): string;
|
||||||
|
|
||||||
// Returns all defined symbols in this layout (for debugging/reflection)
|
// Returns all defined symbols in this layout (for debugging/reflection)
|
||||||
function GetSymbols: TArray<string>;
|
function GetSymbols: TArray<string>;
|
||||||
@@ -69,7 +70,7 @@ type
|
|||||||
|
|
||||||
// 2. The Builder (Mutable).
|
// 2. The Builder (Mutable).
|
||||||
IScopeBuilder = interface(IScopeLayout)
|
IScopeBuilder = interface(IScopeLayout)
|
||||||
function Define(const Name: string): Integer;
|
function Define(const Name: string; const Doc: string = ''): Integer;
|
||||||
function Build: IScopeLayout;
|
function Build: IScopeLayout;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -95,7 +96,13 @@ type
|
|||||||
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
procedure SetValues(const Address: TResolvedAddress; const Value: TDataValue);
|
||||||
{$endregion}
|
{$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);
|
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||||
|
|
||||||
@@ -129,18 +136,25 @@ uses
|
|||||||
System.SyncObjs;
|
System.SyncObjs;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TSymbolMeta = record
|
||||||
|
Slot: Integer;
|
||||||
|
Doc: string;
|
||||||
|
constructor Create(ASlot: Integer; const ADoc: string);
|
||||||
|
end;
|
||||||
|
|
||||||
// --- Concrete Layout (Immutable) ---
|
// --- Concrete Layout (Immutable) ---
|
||||||
TScopeLayout = class(TInterfacedObject, IScopeLayout)
|
TScopeLayout = class(TInterfacedObject, IScopeLayout)
|
||||||
private
|
private
|
||||||
FParent: IScopeLayout;
|
FParent: IScopeLayout;
|
||||||
FMap: TDictionary<string, Integer>;
|
FMap: TDictionary<string, TSymbolMeta>;
|
||||||
FSlotCount: Integer; // Explicit slot count
|
FSlotCount: Integer;
|
||||||
function GetParent: IScopeLayout;
|
function GetParent: IScopeLayout;
|
||||||
function GetSlotCount: Integer;
|
function GetSlotCount: Integer;
|
||||||
public
|
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;
|
destructor Destroy; override;
|
||||||
function FindSlot(const Name: string): Integer;
|
function FindSlot(const Name: string): Integer;
|
||||||
|
function GetSymbolDoc(const Name: string): string;
|
||||||
function GetSymbols: TArray<string>;
|
function GetSymbols: TArray<string>;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -148,16 +162,17 @@ type
|
|||||||
TScopeBuilder = class(TInterfacedObject, IScopeBuilder, IScopeLayout)
|
TScopeBuilder = class(TInterfacedObject, IScopeBuilder, IScopeLayout)
|
||||||
private
|
private
|
||||||
FParentLayout: IScopeLayout;
|
FParentLayout: IScopeLayout;
|
||||||
FMap: TDictionary<string, Integer>;
|
FMap: TDictionary<string, TSymbolMeta>;
|
||||||
FNextSlot: Integer; // Counter for sequential slot allocation
|
FNextSlot: Integer;
|
||||||
function GetParent: IScopeLayout;
|
function GetParent: IScopeLayout;
|
||||||
function GetSlotCount: Integer;
|
function GetSlotCount: Integer;
|
||||||
public
|
public
|
||||||
constructor Create(const AParentLayout: IScopeLayout);
|
constructor Create(const AParentLayout: IScopeLayout);
|
||||||
destructor Destroy; override;
|
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 FindSlot(const Name: string): Integer;
|
||||||
|
function GetSymbolDoc(const Name: string): string;
|
||||||
function GetSymbols: TArray<string>;
|
function GetSymbols: TArray<string>;
|
||||||
function Build: IScopeLayout;
|
function Build: IScopeLayout;
|
||||||
end;
|
end;
|
||||||
@@ -202,6 +217,7 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AOwner: TExecutionScope);
|
constructor Create(AOwner: TExecutionScope);
|
||||||
function FindSlot(const Name: string): Integer;
|
function FindSlot(const Name: string): Integer;
|
||||||
|
function GetSymbolDoc(const Name: string): string;
|
||||||
function GetSymbols: TArray<string>;
|
function GetSymbols: TArray<string>;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -224,9 +240,12 @@ type
|
|||||||
FSlotTypes: TArray<IStaticType>;
|
FSlotTypes: TArray<IStaticType>;
|
||||||
FValues: TArray<TScopeItem>;
|
FValues: TArray<TScopeItem>;
|
||||||
FCapturedUpvalues: TArray<IValueCell>;
|
FCapturedUpvalues: TArray<IValueCell>;
|
||||||
|
|
||||||
|
// Dynamic Name Mapping
|
||||||
FNames: TDictionary<string, Integer>;
|
FNames: TDictionary<string, Integer>;
|
||||||
FNameStrings: TList<string>;
|
FNameStrings: TList<string>;
|
||||||
FNameToIndex: TDictionary<Integer, Integer>;
|
FNameToIndex: TDictionary<Integer, Integer>;
|
||||||
|
FDocs: TDictionary<string, string>; // Stores docs for dynamic symbols
|
||||||
|
|
||||||
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
procedure DumpScope(const ABuilder: TStringBuilder; AIndent: Integer);
|
||||||
procedure NeedNameToIndex;
|
procedure NeedNameToIndex;
|
||||||
@@ -242,7 +261,12 @@ type
|
|||||||
function GetNameID(const Name: String): Integer;
|
function GetNameID(const Name: String): Integer;
|
||||||
function Resolve(const Name: string): TResolvedAddress;
|
function Resolve(const Name: string): TResolvedAddress;
|
||||||
function Dump: string;
|
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);
|
procedure DefineBoxed(SlotIndex: Integer; const Value: TDataValue);
|
||||||
function Capture(const Address: TResolvedAddress): IValueCell;
|
function Capture(const Address: TResolvedAddress): IValueCell;
|
||||||
|
|
||||||
@@ -300,9 +324,17 @@ begin
|
|||||||
Dest.StaticType := TTypes.Unknown;
|
Dest.StaticType := TTypes.Unknown;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TSymbolMeta }
|
||||||
|
|
||||||
|
constructor TSymbolMeta.Create(ASlot: Integer; const ADoc: string);
|
||||||
|
begin
|
||||||
|
Slot := ASlot;
|
||||||
|
Doc := ADoc;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TScopeLayout }
|
{ 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
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FParent := AParent;
|
FParent := AParent;
|
||||||
@@ -317,11 +349,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
function TScopeLayout.FindSlot(const Name: string): Integer;
|
function TScopeLayout.FindSlot(const Name: string): Integer;
|
||||||
|
var
|
||||||
|
meta: TSymbolMeta;
|
||||||
begin
|
begin
|
||||||
if not FMap.TryGetValue(Name, Result) then
|
if FMap.TryGetValue(Name, meta) then
|
||||||
|
Result := meta.Slot
|
||||||
|
else
|
||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
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>;
|
function TScopeLayout.GetSymbols: TArray<string>;
|
||||||
begin
|
begin
|
||||||
Result := FMap.Keys.ToArray;
|
Result := FMap.Keys.ToArray;
|
||||||
@@ -343,7 +389,7 @@ constructor TScopeBuilder.Create(const AParentLayout: IScopeLayout);
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FParentLayout := AParentLayout;
|
FParentLayout := AParentLayout;
|
||||||
FMap := TDictionary<string, Integer>.Create;
|
FMap := TDictionary<string, TSymbolMeta>.Create;
|
||||||
FNextSlot := 0;
|
FNextSlot := 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -353,25 +399,38 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScopeBuilder.Define(const Name: string): Integer;
|
function TScopeBuilder.Define(const Name: string; const Doc: string): Integer;
|
||||||
begin
|
begin
|
||||||
// Rule: Shadowing / Redefinition in the same scope is forbidden.
|
// 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.');
|
Assert(not FMap.ContainsKey(Name), 'Scope Error: Variable "' + Name + '" is already defined in this scope builder.');
|
||||||
|
|
||||||
// Allocate a new slot
|
// Allocate a new slot
|
||||||
Result := FNextSlot;
|
Result := FNextSlot;
|
||||||
Inc(FNextSlot);
|
Inc(FNextSlot);
|
||||||
|
|
||||||
FMap.Add(Name, Result);
|
FMap.Add(Name, TSymbolMeta.Create(Result, Doc));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TScopeBuilder.FindSlot(const Name: string): Integer;
|
function TScopeBuilder.FindSlot(const Name: string): Integer;
|
||||||
|
var
|
||||||
|
meta: TSymbolMeta;
|
||||||
begin
|
begin
|
||||||
if not FMap.TryGetValue(Name, Result) then
|
if FMap.TryGetValue(Name, meta) then
|
||||||
|
Result := meta.Slot
|
||||||
|
else
|
||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
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>;
|
function TScopeBuilder.GetSymbols: TArray<string>;
|
||||||
begin
|
begin
|
||||||
Result := FMap.Keys.ToArray;
|
Result := FMap.Keys.ToArray;
|
||||||
@@ -380,7 +439,7 @@ end;
|
|||||||
function TScopeBuilder.Build: IScopeLayout;
|
function TScopeBuilder.Build: IScopeLayout;
|
||||||
begin
|
begin
|
||||||
// Pass FNextSlot as the total slot count
|
// 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;
|
end;
|
||||||
|
|
||||||
function TScopeBuilder.GetParent: IScopeLayout;
|
function TScopeBuilder.GetParent: IScopeLayout;
|
||||||
@@ -436,6 +495,12 @@ begin
|
|||||||
Result := -1;
|
Result := -1;
|
||||||
end;
|
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>;
|
function TExecutionScope.TDynamicLayout.GetSymbols: TArray<string>;
|
||||||
begin
|
begin
|
||||||
Result := FOwner.FNames.Keys.ToArray;
|
Result := FOwner.FNames.Keys.ToArray;
|
||||||
@@ -532,6 +597,8 @@ begin
|
|||||||
FNameStrings := TList<string>.Create;
|
FNameStrings := TList<string>.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
FDocs := nil; // Initialized on demand in Define
|
||||||
|
|
||||||
if Assigned(FLayoutIntf) then
|
if Assigned(FLayoutIntf) then
|
||||||
SetLength(FValues, FLayoutIntf.SlotCount);
|
SetLength(FValues, FLayoutIntf.SlotCount);
|
||||||
end;
|
end;
|
||||||
@@ -544,6 +611,7 @@ begin
|
|||||||
FNameStrings.Free;
|
FNameStrings.Free;
|
||||||
FNames.Free;
|
FNames.Free;
|
||||||
end;
|
end;
|
||||||
|
FDocs.Free;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -564,6 +632,13 @@ procedure TExecutionScope.Clear;
|
|||||||
begin
|
begin
|
||||||
FValues := [];
|
FValues := [];
|
||||||
FreeAndNil(FNameToIndex);
|
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;
|
end;
|
||||||
|
|
||||||
function TExecutionScope.Capture(const Address: TResolvedAddress): IValueCell;
|
function TExecutionScope.Capture(const Address: TResolvedAddress): IValueCell;
|
||||||
@@ -602,7 +677,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
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
|
var
|
||||||
id: Integer;
|
id: Integer;
|
||||||
index: Integer;
|
index: Integer;
|
||||||
@@ -630,6 +710,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
FNameToIndex.Add(id, index);
|
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.Kind := akLocalOrParent;
|
||||||
Result.ScopeDepth := 0;
|
Result.ScopeDepth := 0;
|
||||||
Result.SlotIndex := index;
|
Result.SlotIndex := index;
|
||||||
@@ -755,7 +843,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
var map := (FStaticDescriptor.Layout as TScopeLayout).FMap;
|
var map := (FStaticDescriptor.Layout as TScopeLayout).FMap;
|
||||||
for var item in map do
|
for var item in map do
|
||||||
FNameToIndex.AddOrSetValue(GetNameId(item.Key), item.Value);
|
FNameToIndex.AddOrSetValue(GetNameId(item.Key), item.Value.Slot);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@@ -843,7 +931,7 @@ end;
|
|||||||
|
|
||||||
class function TScope.CreateRootLayout: IScopeLayout;
|
class function TScope.CreateRootLayout: IScopeLayout;
|
||||||
begin
|
begin
|
||||||
Result := TScopeLayout.Create(nil, TDictionary<string, Integer>.Create, 0);
|
Result := TScopeLayout.Create(nil, TDictionary<string, TSymbolMeta>.Create, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ uses
|
|||||||
type
|
type
|
||||||
TSymProc = reference to procedure(const Symbol: String; Amount: Integer);
|
TSymProc = reference to procedure(const Symbol: String; Amount: Integer);
|
||||||
|
|
||||||
// Das Interface, das im AST-Skript verfügbar sein wird.
|
// Das Interface, das im AST-Skript als Record-Struktur verfügbar sein wird.
|
||||||
|
// Die Methodennamen dienen als Dokumentation.
|
||||||
IMycBroker = interface
|
IMycBroker = interface
|
||||||
['{D8E9F1A2-B3C4-4D5E-F6A7-B8C9D0E1F2A3}']
|
['{D8E9F1A2-B3C4-4D5E-F6A7-B8C9D0E1F2A3}']
|
||||||
|
|
||||||
@@ -27,7 +28,6 @@ type
|
|||||||
function GetPosition(const Symbol: string): Integer;
|
function GetPosition(const Symbol: string): Integer;
|
||||||
|
|
||||||
// Iteriert über alle Positionen und ruft für jede den Callback auf.
|
// Iteriert über alle Positionen und ruft für jede den Callback auf.
|
||||||
// Benötigt Registrierung von TProc<string>.
|
|
||||||
procedure ListPositions(const Callback: TSymProc);
|
procedure ListPositions(const Callback: TSymProc);
|
||||||
|
|
||||||
property Cash: Double read GetCash;
|
property Cash: Double read GetCash;
|
||||||
@@ -138,8 +138,6 @@ end;
|
|||||||
procedure RegisterBroker(const Scope: IExecutionScope);
|
procedure RegisterBroker(const Scope: IExecutionScope);
|
||||||
begin
|
begin
|
||||||
// 1. Registrierung des Callback-Typs.
|
// 1. Registrierung des Callback-Typs.
|
||||||
// Dies ermöglicht dem TypeRegistry-Marshaller, die Signatur von Invoke(string, integer) zu analysieren
|
|
||||||
// und AST-Lambdas (TDataValue.TFunc) in native TProc<string> zu wrappen.
|
|
||||||
TRtlTypeRegistry.RegisterType<TSymProc>;
|
TRtlTypeRegistry.RegisterType<TSymProc>;
|
||||||
|
|
||||||
// 2. Registrierung des Broker-Interfaces
|
// 2. Registrierung des Broker-Interfaces
|
||||||
@@ -152,7 +150,8 @@ begin
|
|||||||
Scope,
|
Scope,
|
||||||
'create-broker',
|
'create-broker',
|
||||||
argTypes,
|
argTypes,
|
||||||
function(const Args: TArray<TDataValue>): IMycBroker begin Result := TMockBroker.Create(Args[0].AsScalar.Value.AsDouble); end
|
function(const Args: TArray<TDataValue>): IMycBroker begin Result := TMockBroker.Create(Args[0].AsScalar.Value.AsDouble); end,
|
||||||
|
'Creates a new mock broker instance with the specified initial cash.' // Doc für das Symbol selbst
|
||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ begin
|
|||||||
// Für den Compiler ist es eine RecordSeries (Typ), zur Laufzeit ein Stream (Wert)
|
// Für den Compiler ist es eine RecordSeries (Typ), zur Laufzeit ein Stream (Wert)
|
||||||
StaticType := TTypes.CreateRecordSeries(Def);
|
StaticType := TTypes.CreateRecordSeries(Def);
|
||||||
|
|
||||||
Scope.Define(VarName, Stream, StaticType);
|
// UPDATED: Dokumentation für die Stream-Variable hinzufügen
|
||||||
|
Scope.Define(VarName, Stream, StaticType, 'Financial OHLC Data Stream (Time, Open, High, Low, Close, Vol).');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFinanceSimulator.AddRandomCandle(const Scope: IExecutionScope; const VarName: string);
|
procedure TFinanceSimulator.AddRandomCandle(const Scope: IExecutionScope; const VarName: string);
|
||||||
@@ -169,7 +170,8 @@ begin
|
|||||||
Sim.CreateOHLCSeries(Scope, Args[0].AsText);
|
Sim.CreateOHLCSeries(Scope, Args[0].AsText);
|
||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end,
|
end,
|
||||||
Sig
|
Sig,
|
||||||
|
'Creates a new OHLC data stream with the specified name.' // UPDATED: Doc
|
||||||
);
|
);
|
||||||
|
|
||||||
Scope.Define(
|
Scope.Define(
|
||||||
@@ -181,10 +183,11 @@ begin
|
|||||||
Sim.AddRandomCandle(Scope, Args[0].AsText);
|
Sim.AddRandomCandle(Scope, Args[0].AsText);
|
||||||
Result := TDataValue.Void;
|
Result := TDataValue.Void;
|
||||||
end,
|
end,
|
||||||
Sig
|
Sig,
|
||||||
|
'Simulates and pushes a new 5-minute candle to the specified stream.' // UPDATED: Doc
|
||||||
);
|
);
|
||||||
|
|
||||||
// Some Demo-Stream
|
// Some Demo-Stream (This will now also be documented in the scope)
|
||||||
Sim.CreateOHLCSeries(Scope, 'btc');
|
Sim.CreateOHLCSeries(Scope, 'btc');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user