Json Schema for LLMs
This commit is contained in:
+18
-11
@@ -288,7 +288,7 @@ begin
|
|||||||
CompilerStageBox.BringToFront;
|
CompilerStageBox.BringToFront;
|
||||||
ClearButtonClick(Self);
|
ClearButtonClick(Self);
|
||||||
|
|
||||||
Memo1.Lines.Add(TAstSchema.GenerateFullSystemPrompt);
|
Memo1.Lines.Add(TAstSchema.GenerateFullSystemPrompt(FEnvironment.RootScope));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TForm1.ShowVizualization;
|
procedure TForm1.ShowVizualization;
|
||||||
@@ -743,45 +743,52 @@ end;
|
|||||||
procedure TForm1.FromJSONButtonClick(Sender: TObject);
|
procedure TForm1.FromJSONButtonClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
jsonString: string;
|
jsonString: string;
|
||||||
jsonObj: TJSONObject;
|
jsonValue: TJSONValue;
|
||||||
converter: IJsonAstConverter;
|
converter: IJsonAstConverter;
|
||||||
begin
|
begin
|
||||||
Memo1.Lines.BeginUpdate;
|
Memo1.Lines.BeginUpdate;
|
||||||
try
|
try
|
||||||
jsonString := Memo1.Lines.Text;
|
jsonString := Memo1.Lines.Text;
|
||||||
Memo1.Lines.Clear;
|
|
||||||
|
|
||||||
if jsonString.IsEmpty then
|
if jsonString.IsEmpty then
|
||||||
begin
|
begin
|
||||||
|
Memo1.Lines.Clear;
|
||||||
Memo1.Lines.Add('Memo is empty. Please paste an AST JSON string.');
|
Memo1.Lines.Add('Memo is empty. Please paste an AST JSON string.');
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
try
|
try
|
||||||
converter := TJsonAstConverter.Create;
|
converter := TJsonAstConverter.Create;
|
||||||
jsonObj := TJSONObject.ParseJSONValue(jsonString) as TJSONObject;
|
// TJSONValue.ParseJSONValue ist der korrekte Einstiegspunkt
|
||||||
if not Assigned(jsonObj) then
|
jsonValue := TJSONValue.ParseJSONValue(jsonString);
|
||||||
raise Exception.Create('Invalid JSON format.');
|
|
||||||
|
if not Assigned(jsonValue) then
|
||||||
|
raise Exception.Create('Invalid JSON syntax.');
|
||||||
|
|
||||||
try
|
try
|
||||||
FCurrUnboundAst := converter.Deserialize(jsonObj);
|
if not (jsonValue is TJSONArray) then
|
||||||
|
raise Exception.Create('AST Root must be a JSON Array.');
|
||||||
|
|
||||||
// Run the full pipeline via environment
|
FCurrUnboundAst := converter.Deserialize(jsonValue);
|
||||||
|
|
||||||
|
// Die Pipeline nutzt den Environment-Helper (Managed Record)
|
||||||
|
// Compile akzeptiert IAstNode und erzeugt intern ein Lambda
|
||||||
FCurrCompiled := FEnvironment.Compile(FCurrUnboundAst);
|
FCurrCompiled := FEnvironment.Compile(FCurrUnboundAst);
|
||||||
FCurrExec := FEnvironment.Link(FCurrCompiled);
|
FCurrExec := FEnvironment.Link(FCurrCompiled);
|
||||||
|
|
||||||
|
Memo1.Lines.Clear;
|
||||||
Memo1.Lines.Add('AST deserialized and bound successfully from JSON.');
|
Memo1.Lines.Add('AST deserialized and bound successfully from JSON.');
|
||||||
Memo1.Lines.Add('You can now visualize it (Middle Mouse Click) or pretty-print it.');
|
Memo1.Lines.Add('You can now visualize it (Middle Mouse Click) or pretty-print it.');
|
||||||
finally
|
finally
|
||||||
jsonObj.Free;
|
jsonValue.Free;
|
||||||
end;
|
end;
|
||||||
except
|
except
|
||||||
on E: Exception do
|
on E: Exception do
|
||||||
begin
|
begin
|
||||||
|
Memo1.Lines.Clear;
|
||||||
Memo1.Lines.Add('Error deserializing AST from JSON:');
|
Memo1.Lines.Add('Error deserializing AST from JSON:');
|
||||||
Memo1.Lines.Add(E.Message);
|
Memo1.Lines.Add(E.Message);
|
||||||
Memo1.Lines.Add('--- Original JSON ---');
|
Memo1.Lines.Add('--- Original JSON ---');
|
||||||
Memo1.Lines.Text := Memo1.Lines.Text + sLineBreak + jsonString;
|
Memo1.Lines.Add(jsonString);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
unit Myc.Ast.Attributes;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
system.sysutils;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ Defines the content type for the LLM schema generation. }
|
||||||
|
TFieldKind = (
|
||||||
|
fkNode, // IAstNode (recursive structure)
|
||||||
|
fkTuple, // ITupleNode (explicit ["Tuple", [...]] structure)
|
||||||
|
fkString, // Raw String (for identifiers/names)
|
||||||
|
fkValue, // TDataValue (primitive constants like number, string, boolean)
|
||||||
|
fkNullableNode, // Optional Node (emits 'AstNode | null' in TypeScript)
|
||||||
|
fkArrayOfPairs // Special structure for CondExpr: [[Cond, Branch], ...]
|
||||||
|
);
|
||||||
|
|
||||||
|
{ AstTagAttribute: Defines the JSON Tag for an AST Node. }
|
||||||
|
AstTagAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FTag: string;
|
||||||
|
public
|
||||||
|
constructor Create(const ATag: string);
|
||||||
|
property Tag: string read FTag;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstFieldAttribute: Defines a field within the JSON Array. }
|
||||||
|
AstFieldAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FName: string;
|
||||||
|
FKind: TFieldKind;
|
||||||
|
FIndex: Integer;
|
||||||
|
public
|
||||||
|
constructor Create(AIndex: Integer; const AName: string; AKind: TFieldKind);
|
||||||
|
property Index: Integer read FIndex;
|
||||||
|
property Name: string read FName;
|
||||||
|
property Kind: TFieldKind read FKind;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstDocAttribute: Provides semantic documentation for the LLM. }
|
||||||
|
AstDocAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FDescription: string;
|
||||||
|
public
|
||||||
|
constructor Create(const ADescription: string);
|
||||||
|
property Description: string read FDescription;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstScriptExampleAttribute: Provides an example in script syntax.
|
||||||
|
The generator converts this to JSON AST for the LLM prompt. }
|
||||||
|
AstScriptExampleAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FScript: string;
|
||||||
|
public
|
||||||
|
constructor Create(const AScript: string);
|
||||||
|
property Script: string read FScript;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstSignatureAttribute: Defines a specific overload signature for an RTL function. }
|
||||||
|
AstSignatureAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
FSignature: string;
|
||||||
|
public
|
||||||
|
constructor Create(const ASignature: string);
|
||||||
|
property Signature: string read FSignature;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ AstTagAttribute }
|
||||||
|
|
||||||
|
constructor AstTagAttribute.Create(const ATag: string);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FTag := ATag;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstFieldAttribute }
|
||||||
|
|
||||||
|
constructor AstFieldAttribute.Create(AIndex: Integer; const AName: string; AKind: TFieldKind);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FIndex := AIndex;
|
||||||
|
FName := AName;
|
||||||
|
FKind := AKind;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstDocAttribute }
|
||||||
|
|
||||||
|
constructor AstDocAttribute.Create(const ADescription: string);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FDescription := ADescription;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstScriptExampleAttribute }
|
||||||
|
|
||||||
|
constructor AstScriptExampleAttribute.Create(const AScript: string);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FScript := AScript;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ AstSignatureAttribute }
|
||||||
|
|
||||||
|
constructor AstSignatureAttribute.Create(const ASignature: string);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FSignature := ASignature;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
+292
-249
@@ -1,14 +1,11 @@
|
|||||||
//==================================================================================================
|
|
||||||
//== FULL UNIT START: Myc.Ast.Json (from Myc.Ast.Json.pas)
|
|
||||||
//==================================================================================================
|
|
||||||
unit Myc.Ast.Json;
|
unit Myc.Ast.Json;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
System.SysUtils,
|
system.sysutils,
|
||||||
System.Generics.Collections,
|
system.generics.collections,
|
||||||
System.JSON,
|
system.json,
|
||||||
Myc.Data.Scalar,
|
Myc.Data.Scalar,
|
||||||
Myc.Data.Value,
|
Myc.Data.Value,
|
||||||
Myc.Ast,
|
Myc.Ast,
|
||||||
@@ -21,19 +18,16 @@ type
|
|||||||
function Deserialize(const AJson: TJSONValue): IAstNode;
|
function Deserialize(const AJson: TJSONValue): IAstNode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Compact JSON Converter: [Kind, Arg1, Arg2, ...]
|
{ Compact JSON Converter: [Tag, Arg1, Arg2, ...] }
|
||||||
TJsonAstConverter = class(TAstVisitor<TJSONValue>, IJsonAstConverter)
|
TJsonAstConverter = class(TAstVisitor<TJSONValue>, IJsonAstConverter)
|
||||||
private
|
private
|
||||||
// Helpers for compact data values
|
|
||||||
function DataValueToJson(const AValue: TDataValue): TJSONValue;
|
function DataValueToJson(const AValue: TDataValue): TJSONValue;
|
||||||
function JsonToDataValue(const AJson: TJSONValue): TDataValue;
|
function JsonToDataValue(const AJson: TJSONValue): TDataValue;
|
||||||
|
|
||||||
// Deserialization Dispatcher
|
|
||||||
function JsonToNode(const AJson: TJSONValue): IAstNode;
|
function JsonToNode(const AJson: TJSONValue): IAstNode;
|
||||||
function JsonToTuple(const AArray: TJSONArray): ITupleNode;
|
function JsonToTuple(const AArray: TJSONArray): ITupleNode;
|
||||||
|
|
||||||
strict private
|
strict private
|
||||||
// Serialization Visitors (Array Builders)
|
|
||||||
function VisitConstant(const Node: IAstNode): TJSONValue;
|
function VisitConstant(const Node: IAstNode): TJSONValue;
|
||||||
function VisitIdentifier(const Node: IAstNode): TJSONValue;
|
function VisitIdentifier(const Node: IAstNode): TJSONValue;
|
||||||
function VisitKeyword(const Node: IAstNode): TJSONValue;
|
function VisitKeyword(const Node: IAstNode): TJSONValue;
|
||||||
@@ -42,16 +36,16 @@ type
|
|||||||
function VisitIfExpression(const Node: IAstNode): TJSONValue;
|
function VisitIfExpression(const Node: IAstNode): TJSONValue;
|
||||||
function VisitCondExpression(const Node: IAstNode): TJSONValue;
|
function VisitCondExpression(const Node: IAstNode): TJSONValue;
|
||||||
function VisitLambdaExpression(const Node: IAstNode): TJSONValue;
|
function VisitLambdaExpression(const Node: IAstNode): TJSONValue;
|
||||||
function VisitMacroDefinition(const Node: IAstNode): TJSONValue;
|
|
||||||
function VisitQuasiquote(const Node: IAstNode): TJSONValue;
|
|
||||||
function VisitUnquote(const Node: IAstNode): TJSONValue;
|
|
||||||
function VisitUnquoteSplicing(const Node: IAstNode): TJSONValue;
|
|
||||||
function VisitFunctionCall(const Node: IAstNode): TJSONValue;
|
function VisitFunctionCall(const Node: IAstNode): TJSONValue;
|
||||||
function VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
|
function VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
|
||||||
function VisitRecurNode(const Node: IAstNode): TJSONValue;
|
function VisitRecurNode(const Node: IAstNode): TJSONValue;
|
||||||
function VisitBlockExpression(const Node: IAstNode): TJSONValue;
|
function VisitBlockExpression(const Node: IAstNode): TJSONValue;
|
||||||
function VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
|
function VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
|
||||||
function VisitAssignment(const Node: IAstNode): TJSONValue;
|
function VisitAssignment(const Node: IAstNode): TJSONValue;
|
||||||
|
function VisitMacroDefinition(const Node: IAstNode): TJSONValue;
|
||||||
|
function VisitQuasiquote(const Node: IAstNode): TJSONValue;
|
||||||
|
function VisitUnquote(const Node: IAstNode): TJSONValue;
|
||||||
|
function VisitUnquoteSplicing(const Node: IAstNode): TJSONValue;
|
||||||
function VisitIndexer(const Node: IAstNode): TJSONValue;
|
function VisitIndexer(const Node: IAstNode): TJSONValue;
|
||||||
function VisitMemberAccess(const Node: IAstNode): TJSONValue;
|
function VisitMemberAccess(const Node: IAstNode): TJSONValue;
|
||||||
function VisitRecordLiteral(const Node: IAstNode): TJSONValue;
|
function VisitRecordLiteral(const Node: IAstNode): TJSONValue;
|
||||||
@@ -125,31 +119,7 @@ begin
|
|||||||
Result := JsonToNode(AJson);
|
Result := JsonToNode(AJson);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// --- Serialization (AST -> JSON Array) ---
|
// --- Serialization Helpers ---
|
||||||
|
|
||||||
function TJsonAstConverter.VisitIdentifier(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Id'));
|
|
||||||
arr.AddElement(TJSONString.Create(Node.AsIdentifier.Name));
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitKeyword(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Key'));
|
|
||||||
arr.AddElement(TJSONString.Create(Node.AsKeyword.Value.Name));
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitConstant(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Const'));
|
|
||||||
arr.AddElement(DataValueToJson(Node.AsConstant.Value));
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.DataValueToJson(const AValue: TDataValue): TJSONValue;
|
function TJsonAstConverter.DataValueToJson(const AValue: TDataValue): TJSONValue;
|
||||||
begin
|
begin
|
||||||
@@ -177,97 +147,74 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitTuple(const Node: IAstNode): TJSONValue;
|
// --- Visitor Implementations ---
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitConstant(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Tuple'));
|
arr.Add('Const');
|
||||||
var elems := TJSONArray.Create;
|
arr.AddElement(DataValueToJson(Node.AsConstant.Value));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitIdentifier(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
begin
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Id');
|
||||||
|
arr.Add(Node.AsIdentifier.Name);
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitKeyword(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
begin
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Key');
|
||||||
|
arr.Add(Node.AsKeyword.Value.Name);
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitTuple(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr, elems: TJSONArray;
|
||||||
|
begin
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Tuple');
|
||||||
|
elems := TJSONArray.Create;
|
||||||
for var item in Node.AsTuple.Elements do
|
for var item in Node.AsTuple.Elements do
|
||||||
elems.AddElement(Visit(item));
|
elems.AddElement(Visit(item));
|
||||||
arr.AddElement(elems);
|
arr.AddElement(elems);
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitFunctionCall(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitRecordField(const Node: IAstNode): TJSONValue;
|
||||||
var
|
var
|
||||||
C: IFunctionCallNode;
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
C := Node.AsFunctionCall;
|
arr := TJSONArray.Create;
|
||||||
var arr := TJSONArray.Create;
|
arr.Add('Field');
|
||||||
arr.AddElement(TJSONString.Create('Call'));
|
arr.AddElement(Visit(Node.AsRecordField.Key));
|
||||||
arr.AddElement(Visit(C.Callee));
|
arr.AddElement(Visit(Node.AsRecordField.Value));
|
||||||
arr.AddElement(Visit(C.Arguments)); // Arguments is a Tuple
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitBlockExpression(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Block'));
|
|
||||||
arr.AddElement(Visit(Node.AsBlockExpression.Expressions)); // Tuple
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitLambdaExpression(const Node: IAstNode): TJSONValue;
|
|
||||||
var
|
|
||||||
L: ILambdaExpressionNode;
|
|
||||||
begin
|
|
||||||
L := Node.AsLambdaExpression;
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Fn'));
|
|
||||||
arr.AddElement(Visit(L.Parameters)); // Tuple
|
|
||||||
arr.AddElement(Visit(L.Body));
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitMacroDefinition(const Node: IAstNode): TJSONValue;
|
|
||||||
var
|
|
||||||
M: IMacroDefinitionNode;
|
|
||||||
begin
|
|
||||||
M := Node.AsMacroDefinition;
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Macro'));
|
|
||||||
arr.AddElement(Visit(M.Name));
|
|
||||||
arr.AddElement(Visit(M.Parameters));
|
|
||||||
arr.AddElement(Visit(M.Body));
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
|
|
||||||
var
|
|
||||||
V: IVariableDeclarationNode;
|
|
||||||
begin
|
|
||||||
V := Node.AsVariableDeclaration;
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Var'));
|
|
||||||
arr.AddElement(Visit(V.Target));
|
|
||||||
if Assigned(V.Initializer) then
|
|
||||||
arr.AddElement(Visit(V.Initializer))
|
|
||||||
else
|
|
||||||
arr.AddElement(TJSONNull.Create);
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitAssignment(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Assign'));
|
|
||||||
arr.AddElement(Visit(Node.AsAssignment.Target));
|
|
||||||
arr.AddElement(Visit(Node.AsAssignment.Value));
|
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitIfExpression(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitIfExpression(const Node: IAstNode): TJSONValue;
|
||||||
var
|
var
|
||||||
E: IIfExpressionNode;
|
arr: TJSONArray;
|
||||||
|
n: IIfExpressionNode;
|
||||||
begin
|
begin
|
||||||
E := Node.AsIfExpression;
|
n := Node.AsIfExpression;
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('If'));
|
arr.Add('If');
|
||||||
arr.AddElement(Visit(E.Condition));
|
arr.AddElement(Visit(n.Condition));
|
||||||
arr.AddElement(Visit(E.ThenBranch));
|
arr.AddElement(Visit(n.ThenBranch));
|
||||||
if Assigned(E.ElseBranch) then
|
if Assigned(n.ElseBranch) then
|
||||||
arr.AddElement(Visit(E.ElseBranch))
|
arr.AddElement(Visit(n.ElseBranch))
|
||||||
else
|
else
|
||||||
arr.AddElement(TJSONNull.Create);
|
arr.AddElement(TJSONNull.Create);
|
||||||
Result := arr;
|
Result := arr;
|
||||||
@@ -275,147 +222,248 @@ end;
|
|||||||
|
|
||||||
function TJsonAstConverter.VisitCondExpression(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitCondExpression(const Node: IAstNode): TJSONValue;
|
||||||
var
|
var
|
||||||
E: ICondExpressionNode;
|
arr, pairs: TJSONArray;
|
||||||
pairs: TJSONArray;
|
n: ICondExpressionNode;
|
||||||
begin
|
begin
|
||||||
E := Node.AsCondExpression;
|
n := Node.AsCondExpression;
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Cond'));
|
arr.Add('Cond');
|
||||||
pairs := TJSONArray.Create;
|
pairs := TJSONArray.Create;
|
||||||
for var p in E.Pairs do
|
for var p in n.Pairs do
|
||||||
begin
|
begin
|
||||||
var pArr := TJSONArray.Create;
|
var pairArr := TJSONArray.Create;
|
||||||
pArr.AddElement(Visit(p.Condition));
|
pairArr.AddElement(Visit(p.Condition));
|
||||||
pArr.AddElement(Visit(p.Branch));
|
pairArr.AddElement(Visit(p.Branch));
|
||||||
pairs.AddElement(pArr);
|
pairs.AddElement(pairArr);
|
||||||
end;
|
end;
|
||||||
arr.AddElement(pairs);
|
arr.AddElement(pairs);
|
||||||
if Assigned(E.ElseBranch) then
|
if Assigned(n.ElseBranch) then
|
||||||
arr.AddElement(Visit(E.ElseBranch))
|
arr.AddElement(Visit(n.ElseBranch))
|
||||||
else
|
else
|
||||||
arr.AddElement(TJSONNull.Create);
|
arr.AddElement(TJSONNull.Create);
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitQuasiquote(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitLambdaExpression(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: ILambdaExpressionNode;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
n := Node.AsLambdaExpression;
|
||||||
arr.AddElement(TJSONString.Create('Quote'));
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Fn');
|
||||||
|
arr.AddElement(Visit(n.Parameters));
|
||||||
|
arr.AddElement(Visit(n.Body));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitFunctionCall(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IFunctionCallNode;
|
||||||
|
begin
|
||||||
|
n := Node.AsFunctionCall;
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Call');
|
||||||
|
arr.AddElement(Visit(n.Callee));
|
||||||
|
arr.AddElement(Visit(n.Arguments));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
|
||||||
|
begin
|
||||||
|
Result := Visit(Node.AsMacroExpansion.CallNode);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitBlockExpression(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
begin
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Block');
|
||||||
|
arr.AddElement(Visit(Node.AsBlockExpression.Expressions));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IVariableDeclarationNode;
|
||||||
|
begin
|
||||||
|
n := Node.AsVariableDeclaration;
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Var');
|
||||||
|
arr.AddElement(Visit(n.Target));
|
||||||
|
if Assigned(n.Initializer) then
|
||||||
|
arr.AddElement(Visit(n.Initializer))
|
||||||
|
else
|
||||||
|
arr.AddElement(TJSONNull.Create);
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitAssignment(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IAssignmentNode;
|
||||||
|
begin
|
||||||
|
n := Node.AsAssignment;
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Assign');
|
||||||
|
arr.AddElement(Visit(n.Target));
|
||||||
|
arr.AddElement(Visit(n.Value));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitMacroDefinition(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IMacroDefinitionNode;
|
||||||
|
begin
|
||||||
|
n := Node.AsMacroDefinition;
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Macro');
|
||||||
|
arr.AddElement(Visit(n.Name));
|
||||||
|
arr.AddElement(Visit(n.Parameters));
|
||||||
|
arr.AddElement(Visit(n.Body));
|
||||||
|
Result := arr;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TJsonAstConverter.VisitQuasiquote(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
begin
|
||||||
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Quote');
|
||||||
arr.AddElement(Visit(Node.AsQuasiquote.Expression));
|
arr.AddElement(Visit(Node.AsQuasiquote.Expression));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitUnquote(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitUnquote(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Unquote'));
|
arr.Add('Unquote');
|
||||||
arr.AddElement(Visit(Node.AsUnquote.Expression));
|
arr.AddElement(Visit(Node.AsUnquote.Expression));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitUnquoteSplicing(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitUnquoteSplicing(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Splice'));
|
arr.Add('Splice');
|
||||||
arr.AddElement(Visit(Node.AsUnquoteSplicing.Expression));
|
arr.AddElement(Visit(Node.AsUnquoteSplicing.Expression));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitRecurNode(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Recur'));
|
|
||||||
arr.AddElement(Visit(Node.AsRecur.Arguments)); // Tuple
|
|
||||||
Result := arr;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitIndexer(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitIndexer(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IIndexerNode;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
n := Node.AsIndexer;
|
||||||
arr.AddElement(TJSONString.Create('Index'));
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(Visit(Node.AsIndexer.Base));
|
arr.Add('Index');
|
||||||
arr.AddElement(Visit(Node.AsIndexer.Index));
|
arr.AddElement(Visit(n.Base));
|
||||||
|
arr.AddElement(Visit(n.Index));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitMemberAccess(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitMemberAccess(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IMemberAccessNode;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
n := Node.AsMemberAccess;
|
||||||
arr.AddElement(TJSONString.Create('Member'));
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(Visit(Node.AsMemberAccess.Base));
|
arr.Add('Member');
|
||||||
arr.AddElement(Visit(Node.AsMemberAccess.Member));
|
arr.AddElement(Visit(n.Base));
|
||||||
Result := arr;
|
arr.AddElement(Visit(n.Member));
|
||||||
end;
|
|
||||||
|
|
||||||
function TJsonAstConverter.VisitRecordField(const Node: IAstNode): TJSONValue;
|
|
||||||
begin
|
|
||||||
// Helper for RecordLiteral
|
|
||||||
var arr := TJSONArray.Create;
|
|
||||||
arr.AddElement(TJSONString.Create('Field'));
|
|
||||||
arr.AddElement(Visit(Node.AsRecordField.Key));
|
|
||||||
arr.AddElement(Visit(Node.AsRecordField.Value));
|
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitRecordLiteral(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitRecordLiteral(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Record'));
|
arr.Add('Record');
|
||||||
arr.AddElement(Visit(Node.AsRecordLiteral.Fields)); // Tuple
|
arr.AddElement(Visit(Node.AsRecordLiteral.Fields));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitCreateSeries(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitCreateSeries(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Series'));
|
arr.Add('Series');
|
||||||
arr.AddElement(Visit(Node.AsCreateSeries.DefinitionNode));
|
arr.AddElement(Visit(Node.AsCreateSeries.DefinitionNode));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitAddSeriesItem(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitAddSeriesItem(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IAddSeriesItemNode;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
n := Node.AsAddSeriesItem;
|
||||||
arr.AddElement(TJSONString.Create('Add'));
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(Visit(Node.AsAddSeriesItem.Series));
|
arr.Add('Add');
|
||||||
arr.AddElement(Visit(Node.AsAddSeriesItem.Value));
|
arr.AddElement(Visit(n.Series));
|
||||||
if Assigned(Node.AsAddSeriesItem.Lookback) then
|
arr.AddElement(Visit(n.Value));
|
||||||
arr.AddElement(Visit(Node.AsAddSeriesItem.Lookback))
|
if Assigned(n.Lookback) then
|
||||||
|
arr.AddElement(Visit(n.Lookback))
|
||||||
else
|
else
|
||||||
arr.AddElement(TJSONNull.Create);
|
arr.AddElement(TJSONNull.Create);
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitSeriesLength(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitSeriesLength(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Count'));
|
arr.Add('Count');
|
||||||
arr.AddElement(Visit(Node.AsSeriesLength.Series));
|
arr.AddElement(Visit(Node.AsSeriesLength.Series));
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitPipe(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitRecurNode(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
var arr := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
arr.AddElement(TJSONString.Create('Pipe'));
|
arr.Add('Recur');
|
||||||
arr.AddElement(Visit(Node.AsPipe.Inputs));
|
arr.AddElement(Visit(Node.AsRecur.Arguments));
|
||||||
arr.AddElement(Visit(Node.AsPipe.Transformation));
|
|
||||||
Result := arr;
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitNop(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitNop(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
begin
|
begin
|
||||||
Result := TJSONArray.Create;
|
arr := TJSONArray.Create;
|
||||||
TJSONArray(Result).AddElement(TJSONString.Create('Nop'));
|
arr.Add('Nop');
|
||||||
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
|
function TJsonAstConverter.VisitPipe(const Node: IAstNode): TJSONValue;
|
||||||
|
var
|
||||||
|
arr: TJSONArray;
|
||||||
|
n: IPipeNode;
|
||||||
begin
|
begin
|
||||||
// Serialize original call
|
n := Node.AsPipe;
|
||||||
Result := Visit(Node.AsMacroExpansion.CallNode);
|
arr := TJSONArray.Create;
|
||||||
|
arr.Add('Pipe');
|
||||||
|
arr.AddElement(Visit(n.Inputs));
|
||||||
|
arr.AddElement(Visit(n.Transformation));
|
||||||
|
Result := arr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// --- Deserialization (JSON Array -> AST) ---
|
// --- Deserialization ---
|
||||||
|
|
||||||
function TJsonAstConverter.JsonToDataValue(const AJson: TJSONValue): TDataValue;
|
function TJsonAstConverter.JsonToDataValue(const AJson: TJSONValue): TDataValue;
|
||||||
var
|
var
|
||||||
@@ -458,8 +506,18 @@ function TJsonAstConverter.JsonToNode(const AJson: TJSONValue): IAstNode;
|
|||||||
var
|
var
|
||||||
arr: TJSONArray;
|
arr: TJSONArray;
|
||||||
kind: string;
|
kind: string;
|
||||||
|
|
||||||
|
function UnpackTuple(Val: TJSONValue): TArray<IAstNode>;
|
||||||
|
begin
|
||||||
|
var n := JsonToNode(Val);
|
||||||
|
if Assigned(n) then
|
||||||
|
Result := n.AsTuple.Elements
|
||||||
|
else
|
||||||
|
Result := [];
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if AJson is TJSONNull then
|
if (not Assigned(AJson)) or (AJson is TJSONNull) then
|
||||||
exit(nil);
|
exit(nil);
|
||||||
|
|
||||||
if not (AJson is TJSONArray) then
|
if not (AJson is TJSONArray) then
|
||||||
@@ -472,32 +530,45 @@ begin
|
|||||||
kind := arr.Items[0].Value;
|
kind := arr.Items[0].Value;
|
||||||
|
|
||||||
if kind = 'Id' then
|
if kind = 'Id' then
|
||||||
Exit(TAst.Identifier(arr.Items[1].Value));
|
exit(TAst.Identifier(arr.Items[1].Value));
|
||||||
if kind = 'Key' then
|
if kind = 'Key' then
|
||||||
Exit(TAst.Keyword(arr.Items[1].Value));
|
exit(TAst.Keyword(arr.Items[1].Value));
|
||||||
if kind = 'Const' then
|
if kind = 'Const' then
|
||||||
Exit(TAst.Constant(JsonToDataValue(arr.Items[1])));
|
exit(TAst.Constant(JsonToDataValue(arr.Items[1])));
|
||||||
if kind = 'Tuple' then
|
|
||||||
Exit(JsonToTuple(arr.Items[1] as TJSONArray));
|
|
||||||
if kind = 'Block' then
|
|
||||||
Exit(TAst.Block(JsonToTuple(arr.Items[1] as TJSONArray).Elements));
|
|
||||||
if kind = 'Nop' then
|
if kind = 'Nop' then
|
||||||
Exit(TAst.Nop);
|
exit(TAst.Nop);
|
||||||
|
|
||||||
|
if kind = 'Tuple' then
|
||||||
|
exit(JsonToTuple(arr.Items[1] as TJSONArray));
|
||||||
|
if kind = 'Block' then
|
||||||
|
exit(TAst.Block(UnpackTuple(arr.Items[1])));
|
||||||
|
if kind = 'Record' then
|
||||||
|
begin
|
||||||
|
var fields := UnpackTuple(arr.Items[1]);
|
||||||
|
var recFields := TList<IRecordFieldNode>.Create;
|
||||||
|
try
|
||||||
|
for var f in fields do
|
||||||
|
recFields.Add(f.AsRecordField);
|
||||||
|
exit(TAst.RecordLiteral(recFields.ToArray));
|
||||||
|
finally
|
||||||
|
recFields.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if kind = 'Field' then
|
||||||
|
exit(TAst.RecordField(JsonToNode(arr.Items[1]).AsKeyword, JsonToNode(arr.Items[2])));
|
||||||
if kind = 'Call' then
|
if kind = 'Call' then
|
||||||
Exit(TAst.FunctionCall(JsonToNode(arr.Items[1]), JsonToTuple(arr.Items[2] as TJSONArray).Elements));
|
exit(TAst.FunctionCall(JsonToNode(arr.Items[1]), UnpackTuple(arr.Items[2])));
|
||||||
|
|
||||||
if kind = 'Fn' then
|
if kind = 'Fn' then
|
||||||
// Pass TIdentities.Structural as Identity to satisfy the overload requiring (Identity, Tuple, Body, ...)
|
exit(TAst.LambdaExpr(TIdentities.Structural, JsonToNode(arr.Items[1]).AsTuple, JsonToNode(arr.Items[2])));
|
||||||
Exit(TAst.LambdaExpr(TIdentities.Structural, JsonToTuple(arr.Items[1] as TJSONArray), JsonToNode(arr.Items[2])));
|
if kind = 'Recur' then
|
||||||
|
exit(TAst.Recur(UnpackTuple(arr.Items[1])));
|
||||||
|
|
||||||
if kind = 'Macro' then
|
if kind = 'Macro' then
|
||||||
// Pass TIdentities.Structural as Identity
|
exit(
|
||||||
Exit(
|
|
||||||
TAst.MacroDef(
|
TAst.MacroDef(
|
||||||
TIdentities.Structural,
|
TIdentities.Structural,
|
||||||
JsonToNode(arr.Items[1]).AsIdentifier,
|
JsonToNode(arr.Items[1]).AsIdentifier,
|
||||||
JsonToTuple(arr.Items[2] as TJSONArray),
|
JsonToNode(arr.Items[2]).AsTuple,
|
||||||
JsonToNode(arr.Items[3])
|
JsonToNode(arr.Items[3])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -505,20 +576,20 @@ begin
|
|||||||
if kind = 'Var' then
|
if kind = 'Var' then
|
||||||
begin
|
begin
|
||||||
var init: IAstNode := nil;
|
var init: IAstNode := nil;
|
||||||
if arr.Count > 2 then
|
if (arr.Count > 2) and (not (arr.Items[2] is TJSONNull)) then
|
||||||
init := JsonToNode(arr.Items[2]);
|
init := JsonToNode(arr.Items[2]);
|
||||||
Exit(TAst.VarDecl(JsonToNode(arr.Items[1]), init));
|
exit(TAst.VarDecl(JsonToNode(arr.Items[1]), init));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if kind = 'Assign' then
|
if kind = 'Assign' then
|
||||||
Exit(TAst.Assign(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
|
exit(TAst.Assign(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
|
||||||
|
|
||||||
if kind = 'If' then
|
if kind = 'If' then
|
||||||
begin
|
begin
|
||||||
var el: IAstNode := nil;
|
var el: IAstNode := nil;
|
||||||
if arr.Count > 3 then
|
if (arr.Count > 3) and (not (arr.Items[3] is TJSONNull)) then
|
||||||
el := JsonToNode(arr.Items[3]);
|
el := JsonToNode(arr.Items[3]);
|
||||||
Exit(TAst.IfExpr(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2]), el));
|
exit(TAst.IfExpr(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2]), el));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if kind = 'Cond' then
|
if kind = 'Cond' then
|
||||||
@@ -532,68 +603,40 @@ begin
|
|||||||
pairs[i] := TCondPair.Create(JsonToNode(p.Items[0]), JsonToNode(p.Items[1]));
|
pairs[i] := TCondPair.Create(JsonToNode(p.Items[0]), JsonToNode(p.Items[1]));
|
||||||
end;
|
end;
|
||||||
var el: IAstNode := nil;
|
var el: IAstNode := nil;
|
||||||
if arr.Count > 2 then
|
if (arr.Count > 2) and (not (arr.Items[2] is TJSONNull)) then
|
||||||
el := JsonToNode(arr.Items[2]);
|
el := JsonToNode(arr.Items[2]);
|
||||||
Exit(TAst.CondExpr(pairs, el));
|
exit(TAst.CondExpr(pairs, el));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if kind = 'Quote' then
|
if kind = 'Quote' then
|
||||||
Exit(TAst.Quasiquote(JsonToNode(arr.Items[1])));
|
exit(TAst.Quasiquote(JsonToNode(arr.Items[1])));
|
||||||
if kind = 'Unquote' then
|
if kind = 'Unquote' then
|
||||||
Exit(TAst.Unquote(JsonToNode(arr.Items[1])));
|
exit(TAst.Unquote(JsonToNode(arr.Items[1])));
|
||||||
|
|
||||||
|
// Splice Fix: Direkte Instanziierung um Factory-Overload E2250 zu umgehen
|
||||||
if kind = 'Splice' then
|
if kind = 'Splice' then
|
||||||
Exit(TAst.UnquoteSplicing(JsonToNode(arr.Items[1]).AsQuasiquote));
|
exit(TUnquoteSplicingNode.Create(JsonToNode(arr.Items[1]), TIdentities.Structural(nil)));
|
||||||
if kind = 'Recur' then
|
|
||||||
Exit(TAst.Recur(JsonToTuple(arr.Items[1] as TJSONArray).Elements));
|
|
||||||
|
|
||||||
if kind = 'Index' then
|
if kind = 'Index' then
|
||||||
Exit(TAst.Indexer(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
|
exit(TAst.Indexer(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
|
||||||
if kind = 'Member' then
|
if kind = 'Member' then
|
||||||
Exit(TAst.MemberAccess(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2]).AsKeyword));
|
exit(TAst.MemberAccess(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2]).AsKeyword));
|
||||||
|
|
||||||
if kind = 'Record' then
|
|
||||||
begin
|
|
||||||
var fieldsTuple := JsonToTuple(arr.Items[1] as TJSONArray);
|
|
||||||
var recFields: TList<IRecordFieldNode> := TList<IRecordFieldNode>.Create;
|
|
||||||
try
|
|
||||||
for var elem in fieldsTuple.Elements do
|
|
||||||
begin
|
|
||||||
if elem.Kind = akRecordField then
|
|
||||||
recFields.Add(elem.AsRecordField)
|
|
||||||
else
|
|
||||||
raise EInvalidCast.Create('Expected RecordField');
|
|
||||||
end;
|
|
||||||
Exit(TAst.RecordLiteral(recFields.ToArray));
|
|
||||||
finally
|
|
||||||
recFields.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// Explicit RecordField deserializer support
|
|
||||||
if kind = 'Field' then
|
|
||||||
Exit(TAst.RecordField(JsonToNode(arr.Items[1]).AsKeyword, JsonToNode(arr.Items[2])));
|
|
||||||
|
|
||||||
if kind = 'Series' then
|
if kind = 'Series' then
|
||||||
Exit(TAst.CreateSeries(JsonToNode(arr.Items[1])));
|
exit(TAst.CreateSeries(JsonToNode(arr.Items[1])));
|
||||||
|
if kind = 'Count' then
|
||||||
|
exit(TAst.SeriesLength(JsonToNode(arr.Items[1]).AsIdentifier));
|
||||||
|
if kind = 'Pipe' then
|
||||||
|
exit(TAst.Pipe(JsonToNode(arr.Items[1]).AsTuple, JsonToNode(arr.Items[2]).AsLambdaExpression));
|
||||||
|
|
||||||
if kind = 'Add' then
|
if kind = 'Add' then
|
||||||
begin
|
begin
|
||||||
var lb: IAstNode := nil;
|
var lb: IAstNode := nil;
|
||||||
if arr.Count > 3 then
|
if (arr.Count > 3) and (not (arr.Items[3] is TJSONNull)) then
|
||||||
lb := JsonToNode(arr.Items[3]);
|
lb := JsonToNode(arr.Items[3]);
|
||||||
Exit(TAst.AddSeriesItem(JsonToNode(arr.Items[1]).AsIdentifier, JsonToNode(arr.Items[2]), lb));
|
exit(TAst.AddSeriesItem(JsonToNode(arr.Items[1]).AsIdentifier, JsonToNode(arr.Items[2]), lb));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if kind = 'Count' then
|
|
||||||
Exit(TAst.SeriesLength(JsonToNode(arr.Items[1]).AsIdentifier));
|
|
||||||
|
|
||||||
if kind = 'Pipe' then
|
|
||||||
Exit(TAst.Pipe(JsonToTuple(arr.Items[1] as TJSONArray), JsonToNode(arr.Items[2]).AsLambdaExpression));
|
|
||||||
|
|
||||||
raise ENotSupportedException.Create('Unknown JSON AST Kind: ' + kind);
|
raise ENotSupportedException.Create('Unknown JSON AST Kind: ' + kind);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
//==================================================================================================
|
|
||||||
//== FULL UNIT END: Myc.Ast.Json
|
|
||||||
//==================================================================================================
|
|
||||||
|
|||||||
+239
-113
@@ -9,16 +9,28 @@ uses
|
|||||||
system.generics.defaults,
|
system.generics.defaults,
|
||||||
system.rtti,
|
system.rtti,
|
||||||
system.typinfo,
|
system.typinfo,
|
||||||
|
system.json,
|
||||||
|
Myc.Data.Scalar,
|
||||||
|
Myc.Data.Value,
|
||||||
Myc.Ast.Nodes,
|
Myc.Ast.Nodes,
|
||||||
Myc.Ast.Attributes,
|
Myc.Ast.Attributes,
|
||||||
Myc.Ast.RTL,
|
Myc.Ast.RTL,
|
||||||
Myc.Ast.RTL.Core;
|
Myc.Ast.RTL.Core,
|
||||||
|
Myc.Ast.Scope,
|
||||||
|
Myc.Ast.Types,
|
||||||
|
Myc.Ast.Script,
|
||||||
|
Myc.Ast.Json;
|
||||||
|
|
||||||
type
|
type
|
||||||
{ Scans AST and RTL metadata to generate a high-precision 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;
|
||||||
@@ -26,18 +38,23 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
class function GetTsType(Kind: TFieldKind): string; static;
|
class function GetTsType(Kind: TFieldKind): string; static;
|
||||||
|
class function TypeToTs(const AType: IStaticType): string; static;
|
||||||
|
class function GetRtlMetadata: TDictionary<string, TRtlMeta>; static;
|
||||||
public
|
public
|
||||||
// Generates the TypeScript definition including JSDoc and multiple @example entries
|
// Generates the TypeScript definition for AST nodes
|
||||||
class function GenerateTypeScriptDefinition: string; static;
|
class function GenerateTypeScriptDefinition: string; static;
|
||||||
|
|
||||||
// Generates documented RTL function signatures with all overloads
|
// Unified section: Lists only symbols available in the current scope with their docs/types
|
||||||
class function GenerateRtlDocumentation: string; static;
|
class function GenerateAvailableSymbols(const AScope: IExecutionScope): string; static;
|
||||||
|
|
||||||
// Detailed generation rules to eliminate ambiguity
|
// Documentation for all RTL functions (used as fallback or for general prompts)
|
||||||
|
class function GenerateAllRtlDocumentation: string; static;
|
||||||
|
|
||||||
|
// Detailed generation rules
|
||||||
class function GenerateGenerationRules: string; static;
|
class function GenerateGenerationRules: string; static;
|
||||||
|
|
||||||
// The final consolidated system prompt
|
// The final consolidated system prompt for the AI
|
||||||
class function GenerateFullSystemPrompt: string; static;
|
class function GenerateFullSystemPrompt(const AScope: IExecutionScope = nil): string; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@@ -58,6 +75,103 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TAstSchema.TypeToTs(const AType: IStaticType): string;
|
||||||
|
begin
|
||||||
|
if not Assigned(AType) then
|
||||||
|
exit('any');
|
||||||
|
|
||||||
|
case AType.Kind of
|
||||||
|
stOrdinal, stFloat: Result := 'number';
|
||||||
|
stBoolean: Result := 'boolean';
|
||||||
|
stDateTime: Result := 'datetime';
|
||||||
|
stText: Result := 'string';
|
||||||
|
stKeyword: Result := 'keyword';
|
||||||
|
stSeries: Result := Format('Series<%s>', [TypeToTs(AType.AsSeries.ElementType)]);
|
||||||
|
stRecord:
|
||||||
|
begin
|
||||||
|
var def := AType.AsRecord.Definition;
|
||||||
|
var fields := TList<string>.Create;
|
||||||
|
try
|
||||||
|
for var i := 0 to def.Count - 1 do
|
||||||
|
fields.Add(Format('%s: %s', [def.Keywords[i].Name, def[i].ToString.ToLower]));
|
||||||
|
Result := '{ ' + string.Join(', ', fields.ToArray) + ' }';
|
||||||
|
finally
|
||||||
|
fields.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
stRecordSeries: Result := 'Stream<' + TypeToTs(TTypes.CreateRecord(AType.AsRecord.Definition)) + '>';
|
||||||
|
stMethod:
|
||||||
|
begin
|
||||||
|
if Length(AType.AsMethod.Signatures) = 0 then
|
||||||
|
exit('function');
|
||||||
|
var sig := AType.AsMethod.Signatures[0];
|
||||||
|
var args := TList<string>.Create;
|
||||||
|
try
|
||||||
|
for var p in sig.ParamTypes do
|
||||||
|
args.Add(TypeToTs(p));
|
||||||
|
Result := Format('(%s) => %s', [string.Join(', ', args.ToArray), TypeToTs(sig.ReturnType)]);
|
||||||
|
finally
|
||||||
|
args.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
Result := 'any';
|
||||||
|
end;
|
||||||
|
|
||||||
|
if AType.IsOptional then
|
||||||
|
Result := Result + ' | null';
|
||||||
|
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;
|
||||||
@@ -71,9 +185,11 @@ var
|
|||||||
tag, doc: string;
|
tag, doc: string;
|
||||||
fieldList: TList<TFieldInfo>;
|
fieldList: TList<TFieldInfo>;
|
||||||
exampleList: TList<string>;
|
exampleList: TList<string>;
|
||||||
|
jsonConv: IJsonAstConverter;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
ctx := TRttiContext.Create;
|
ctx := TRttiContext.Create;
|
||||||
|
jsonConv := TJsonAstConverter.Create;
|
||||||
nodeDefs := TDictionary<string, TList<TFieldInfo>>.Create;
|
nodeDefs := TDictionary<string, TList<TFieldInfo>>.Create;
|
||||||
nodeDocs := TDictionary<string, string>.Create;
|
nodeDocs := TDictionary<string, string>.Create;
|
||||||
nodeExamples := TDictionary<string, TList<string>>.Create;
|
nodeExamples := TDictionary<string, TList<string>>.Create;
|
||||||
@@ -84,27 +200,33 @@ begin
|
|||||||
begin
|
begin
|
||||||
if typ.TypeKind <> tkInterface then
|
if typ.TypeKind <> tkInterface then
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tag := '';
|
tag := '';
|
||||||
doc := '';
|
doc := '';
|
||||||
fieldList := nil;
|
fieldList := nil;
|
||||||
exampleList := nil;
|
exampleList := nil;
|
||||||
|
|
||||||
for attr in typ.GetAttributes do
|
for attr in typ.GetAttributes do
|
||||||
begin
|
begin
|
||||||
if attr is AstTagAttribute then
|
if attr is AstTagAttribute then
|
||||||
tag := AstTagAttribute(attr).Tag;
|
tag := AstTagAttribute(attr).Tag;
|
||||||
|
|
||||||
if attr is AstDocAttribute then
|
if attr is AstDocAttribute then
|
||||||
doc := AstDocAttribute(attr).Description;
|
doc := AstDocAttribute(attr).Description;
|
||||||
|
if attr is AstScriptExampleAttribute then
|
||||||
if attr is AstExampleAttribute then
|
|
||||||
begin
|
begin
|
||||||
if exampleList = nil then
|
if exampleList = nil then
|
||||||
exampleList := TList<string>.Create;
|
exampleList := TList<string>.Create;
|
||||||
exampleList.Add(AstExampleAttribute(attr).Example);
|
try
|
||||||
|
var node := TAstScript.Parse(AstScriptExampleAttribute(attr).Script);
|
||||||
|
var jsonVal := jsonConv.Serialize(node);
|
||||||
|
try
|
||||||
|
exampleList.Add(jsonVal.ToJSON);
|
||||||
|
finally
|
||||||
|
jsonVal.Free;
|
||||||
|
end;
|
||||||
|
except
|
||||||
|
on E: Exception do
|
||||||
|
exampleList.Add('/* Error in example */');
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if attr is AstFieldAttribute then
|
if attr is AstFieldAttribute then
|
||||||
begin
|
begin
|
||||||
if fieldList = nil then
|
if fieldList = nil then
|
||||||
@@ -116,7 +238,6 @@ begin
|
|||||||
fieldList.Add(f);
|
fieldList.Add(f);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if tag <> '' then
|
if tag <> '' then
|
||||||
begin
|
begin
|
||||||
unionTypes.Add(tag);
|
unionTypes.Add(tag);
|
||||||
@@ -134,13 +255,8 @@ begin
|
|||||||
exampleList.Free;
|
exampleList.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
sb.AppendLine('// AST Schema Definition' + sLineBreak + '// Format: Compact JSON Arrays [Tag, Arg1, Arg2, ...]' + sLineBreak);
|
||||||
sb.AppendLine('// AST Schema Definition (Auto-Generated)');
|
|
||||||
sb.AppendLine('// Format: Compact JSON Arrays [Tag, Arg1, Arg2, ...]');
|
|
||||||
sb.AppendLine;
|
|
||||||
|
|
||||||
unionTypes.Sort;
|
unionTypes.Sort;
|
||||||
|
|
||||||
sb.AppendLine('type AstNode = ');
|
sb.AppendLine('type AstNode = ');
|
||||||
for i := 0 to unionTypes.Count - 1 do
|
for i := 0 to unionTypes.Count - 1 do
|
||||||
begin
|
begin
|
||||||
@@ -148,38 +264,33 @@ begin
|
|||||||
if i < unionTypes.Count - 1 then
|
if i < unionTypes.Count - 1 then
|
||||||
sb.AppendLine;
|
sb.AppendLine;
|
||||||
end;
|
end;
|
||||||
sb.AppendLine(';');
|
sb.AppendLine(
|
||||||
sb.AppendLine;
|
';'
|
||||||
|
+ sLineBreak
|
||||||
sb.AppendLine('/** Explicit list structure */');
|
+ sLineBreak
|
||||||
sb.AppendLine('type Tuple = ["Tuple", AstNode[]];');
|
+ '/** Explicit list structure */'
|
||||||
sb.AppendLine;
|
+ sLineBreak
|
||||||
|
+ 'type Tuple = ["Tuple", AstNode[]];'
|
||||||
|
+ sLineBreak
|
||||||
|
);
|
||||||
for tag in unionTypes do
|
for tag in unionTypes do
|
||||||
begin
|
begin
|
||||||
if tag = 'Tuple' then
|
if tag = 'Tuple' then
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sb.Append('/** ');
|
sb.Append('/** ');
|
||||||
if nodeDocs.TryGetValue(tag, doc) then
|
if nodeDocs.TryGetValue(tag, doc) then
|
||||||
sb.Append(doc);
|
sb.Append(doc);
|
||||||
|
|
||||||
if nodeExamples.TryGetValue(tag, exampleList) then
|
if nodeExamples.TryGetValue(tag, exampleList) then
|
||||||
begin
|
|
||||||
for var ex in exampleList do
|
for var ex in exampleList do
|
||||||
sb.Append(sLineBreak + ' @example ' + ex);
|
sb.Append(sLineBreak + ' @example ' + ex);
|
||||||
end;
|
|
||||||
sb.AppendLine(' */');
|
sb.AppendLine(' */');
|
||||||
|
|
||||||
fieldList := nodeDefs[tag];
|
fieldList := nodeDefs[tag];
|
||||||
fieldList.Sort(TComparer<TFieldInfo>.Construct(function(const L, R: TFieldInfo): Integer begin Result := L.Idx - R.Idx; end));
|
fieldList.Sort(TComparer<TFieldInfo>.Construct(function(const L, R: TFieldInfo): Integer begin Result := L.Idx - R.Idx; end));
|
||||||
|
|
||||||
sb.Append('type ' + tag + ' = ["' + tag + '"');
|
sb.Append('type ' + tag + ' = ["' + tag + '"');
|
||||||
for var f in fieldList do
|
for var f in fieldList do
|
||||||
sb.Append(Format(', %s /* %s */', [GetTsType(f.Kind), f.Name]));
|
sb.Append(Format(', %s /* %s */', [GetTsType(f.Kind), f.Name]));
|
||||||
sb.AppendLine('];');
|
sb.AppendLine('];');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := sb.ToString;
|
Result := sb.ToString;
|
||||||
finally
|
finally
|
||||||
for fieldList in nodeDefs.Values do
|
for fieldList in nodeDefs.Values do
|
||||||
@@ -195,111 +306,126 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TAstSchema.GenerateRtlDocumentation: string;
|
class function TAstSchema.GenerateAvailableSymbols(const AScope: IExecutionScope): string;
|
||||||
var
|
var
|
||||||
ctx: TRttiContext;
|
|
||||||
typ: TRttiType;
|
|
||||||
meth: TRttiMethod;
|
|
||||||
attr: TCustomAttribute;
|
|
||||||
doc, rtlName: string;
|
|
||||||
sigs: TList<string>;
|
|
||||||
sb: TStringBuilder;
|
sb: TStringBuilder;
|
||||||
processedNames: THashSet<string>;
|
rtlMeta: TDictionary<string, TRtlMeta>;
|
||||||
|
layout: IScopeLayout;
|
||||||
|
symbols: TArray<string>;
|
||||||
|
name: string;
|
||||||
|
meta: TRtlMeta;
|
||||||
|
typ: IStaticType;
|
||||||
begin
|
begin
|
||||||
ctx := TRttiContext.Create;
|
if not Assigned(AScope) then
|
||||||
|
exit('');
|
||||||
|
|
||||||
|
rtlMeta := GetRtlMetadata;
|
||||||
sb := TStringBuilder.Create;
|
sb := TStringBuilder.Create;
|
||||||
sigs := TList<string>.Create;
|
|
||||||
processedNames := THashSet<string>.Create;
|
|
||||||
try
|
try
|
||||||
typ := ctx.GetType(TypeInfo(TRtlFunctions));
|
layout := AScope.Descriptor.Layout;
|
||||||
sb.AppendLine('### 3. Runtime Library (Available Functions)');
|
symbols := layout.GetSymbols;
|
||||||
|
TArray.Sort<string>(symbols);
|
||||||
|
|
||||||
|
sb.AppendLine('### 3. Available Symbols (Environment & Library)');
|
||||||
|
sb.AppendLine('The following symbols are currently defined and can be used in your script:');
|
||||||
sb.AppendLine;
|
sb.AppendLine;
|
||||||
|
|
||||||
for meth in typ.GetMethods do
|
for name in symbols do
|
||||||
begin
|
begin
|
||||||
doc := '';
|
if name.StartsWith('<') or name.EndsWith('>') then
|
||||||
rtlName := '';
|
continue;
|
||||||
sigs.Clear;
|
|
||||||
|
|
||||||
for attr in meth.GetAttributes do
|
sb.Append(Format('- `%s`', [name]));
|
||||||
begin
|
|
||||||
if attr is AstDocAttribute then
|
|
||||||
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 <> '') and (not processedNames.Contains(rtlName)) then
|
if rtlMeta.TryGetValue(name, meta) then
|
||||||
begin
|
begin
|
||||||
sb.Append(Format('- `%s`', [rtlName]));
|
if Length(meta.Signatures) > 0 then
|
||||||
if sigs.Count > 0 then
|
sb.Append(': ' + string.Join(' | ', meta.Signatures));
|
||||||
sb.Append(': ' + string.Join(' | ', sigs.ToArray));
|
if meta.Doc <> '' then
|
||||||
if doc <> '' then
|
sb.Append(' — ' + meta.Doc);
|
||||||
sb.Append(' — ' + doc);
|
end
|
||||||
sb.AppendLine;
|
else
|
||||||
processedNames.Add(rtlName);
|
begin
|
||||||
|
typ := AScope.Descriptor.GetSymbolType(layout.FindSlot(name));
|
||||||
|
sb.Append(': ' + TypeToTs(typ));
|
||||||
end;
|
end;
|
||||||
|
sb.AppendLine;
|
||||||
end;
|
end;
|
||||||
Result := sb.ToString;
|
Result := sb.ToString;
|
||||||
finally
|
finally
|
||||||
processedNames.Free;
|
|
||||||
sigs.Free;
|
|
||||||
sb.Free;
|
sb.Free;
|
||||||
ctx.Free;
|
rtlMeta.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TAstSchema.GenerateAllRtlDocumentation: string;
|
||||||
|
var
|
||||||
|
rtlMeta: TDictionary<string, TRtlMeta>;
|
||||||
|
sb: TStringBuilder;
|
||||||
|
pair: TPair<string, TRtlMeta>;
|
||||||
|
begin
|
||||||
|
rtlMeta := GetRtlMetadata;
|
||||||
|
sb := TStringBuilder.Create;
|
||||||
|
try
|
||||||
|
sb.AppendLine('### 3. Runtime Library (Global Functions)');
|
||||||
|
sb.AppendLine;
|
||||||
|
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;
|
end;
|
||||||
|
|
||||||
class function TAstSchema.GenerateGenerationRules: string;
|
class function TAstSchema.GenerateGenerationRules: string;
|
||||||
var
|
|
||||||
sb: TStringBuilder;
|
|
||||||
begin
|
|
||||||
sb := TStringBuilder.Create;
|
|
||||||
try
|
|
||||||
sb.AppendLine('**⚠️ CRITICAL GENERATION RULES:**');
|
|
||||||
sb.AppendLine;
|
|
||||||
sb.AppendLine('1. **NO JSON OBJECTS:** Do not use `{}`. Every node MUST be a JSON Array `["Tag", Arg1, Arg2]`.');
|
|
||||||
sb.AppendLine('2. **EXPLICIT TUPLES:** Fields defined as `Tuple` MUST be wrapped in `["Tuple", [...]]`.');
|
|
||||||
sb.AppendLine('3. **EXPLICIT NULLS:** Optional fields (`| null`) MUST be explicit `null` if not present.');
|
|
||||||
sb.AppendLine('4. **STRICT ORDER:** Array elements must follow the schema index exactly. Never swap arguments.');
|
|
||||||
sb.AppendLine(
|
|
||||||
'5. **OPERATORS:** Use `Call` with an `Id` for operators: `["Call", ["Id", "+"], ["Tuple", [["Const", 1], ["Const", 2]]]]`.'
|
|
||||||
);
|
|
||||||
sb.AppendLine(
|
|
||||||
'6. **ID VS KEY:** Use `Key` for record keys (e.g. `["Field", ["Key", "p"], ...]`). Use `Id` for variables, functions, and operators.'
|
|
||||||
);
|
|
||||||
sb.AppendLine('7. **BOOLEANS:** The literals `true` and `false` are identifiers: `["Id", "true"]` or `["Id", "false"]`.');
|
|
||||||
sb.AppendLine(
|
|
||||||
'8. **SCALAR TYPES:** Valid types for series definitions are: `:Ordinal`, `:Float`, `:Boolean`, `:Text`, `:DateTime`.'
|
|
||||||
);
|
|
||||||
sb.AppendLine('9. **NESTED ARRAYS:** In "Cond", the pairs are an array of arrays: `[ [cond1, branch1], [cond2, branch2] ]`.');
|
|
||||||
sb.AppendLine('10. **RECURSION:** Use `Recur` for tail-recursive calls to enable optimization.');
|
|
||||||
sb.AppendLine('11. **NO COMMENTS:** Output raw JSON only. No explanations.');
|
|
||||||
|
|
||||||
Result := sb.ToString;
|
|
||||||
finally
|
|
||||||
sb.Free;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
class function TAstSchema.GenerateFullSystemPrompt: string;
|
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
'You are a compiler frontend for a domain-specific scripting language.'
|
'''
|
||||||
+ sLineBreak
|
**⚠️ CRITICAL GENERATION RULES:**
|
||||||
+ 'Your task is to generate a valid Abstract Syntax Tree (AST) in a specific Compact JSON format.'
|
|
||||||
+ sLineBreak
|
1. **NO JSON OBJECTS:** Do not use `{}`. Every node MUST be a JSON Array `["Tag", Arg1, Arg2]`.
|
||||||
+ sLineBreak
|
2. **EXPLICIT TUPLES:** Fields defined as `Tuple` MUST be wrapped in `["Tuple", [...]]`.
|
||||||
+ '### 1. AST Schema (TypeScript Definition)'
|
3. **EXPLICIT NULLS:** Optional fields (`| null`) MUST be explicit `null` if not present.
|
||||||
|
4. **STRICT ORDER:** Array elements must follow the schema index exactly.
|
||||||
|
5. **OPERATORS:** Use `Call` with an `Id` for operators: `["Call", ["Id", "+"], ["Tuple", [["Const", 1], ["Const", 2]]]]`.
|
||||||
|
6. **ID VS KEY:** Use `Key` for record keys. Use `Id` for variables, functions, and operators.
|
||||||
|
7. **BOOLEANS:** The literals `true` and `false` are identifiers: `["Id", "true"]` or `["Id", "false"]`.
|
||||||
|
8. **SCALAR TYPES:** Valid types for series definitions are: `:Ordinal`, `:Float`, `:Boolean`, `:Text`, `:DateTime`.
|
||||||
|
9. **NESTED ARRAYS:** In "Cond", the pairs are an array of arrays: `[ [cond1, branch1], [cond2, branch2] ]`.
|
||||||
|
10. **RECURSION:** Use `Recur` for tail-recursive calls to enable optimization.
|
||||||
|
11. **NO COMMENTS:** Output raw JSON only.
|
||||||
|
''';
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TAstSchema.GenerateFullSystemPrompt(const AScope: IExecutionScope): string;
|
||||||
|
begin
|
||||||
|
Result :=
|
||||||
|
'''
|
||||||
|
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.
|
||||||
|
|
||||||
|
### 1. AST Schema (TypeScript Definition)
|
||||||
|
'''
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ GenerateTypeScriptDefinition
|
+ GenerateTypeScriptDefinition
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ '### 2. Constraints & Rules'
|
+ '### 2. Constraints & Rules'
|
||||||
+ sLineBreak
|
+ sLineBreak
|
||||||
+ GenerateGenerationRules
|
+ GenerateGenerationRules
|
||||||
+ sLineBreak
|
+ sLineBreak;
|
||||||
+ GenerateRtlDocumentation;
|
|
||||||
|
if Assigned(AScope) then
|
||||||
|
Result := Result + GenerateAvailableSymbols(AScope)
|
||||||
|
else
|
||||||
|
Result := Result + GenerateAllRtlDocumentation;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
+68
-102
@@ -206,18 +206,18 @@ type
|
|||||||
property IsPure: Boolean read GetIsPure;
|
property IsPure: Boolean read GetIsPure;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// --- Specialized Node Interfaces with Examples and Docs ---
|
// --- Specialized Node Interfaces with Metadata ---
|
||||||
|
|
||||||
[AstTag('Nop')]
|
[AstTag('Nop')]
|
||||||
[AstDoc('A placeholder that performs no action.')]
|
[AstDoc('A placeholder that performs no action.')]
|
||||||
[AstExample('["Nop"]')]
|
[AstScriptExample('...')]
|
||||||
INopNode = interface(IAstTypedNode)
|
INopNode = interface(IAstTypedNode)
|
||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Const')]
|
[AstTag('Const')]
|
||||||
[AstDoc('A literal value (number, string, or boolean).')]
|
[AstDoc('A literal value (number, string, or boolean).')]
|
||||||
[AstExample('["Const", 42]')]
|
[AstScriptExample('42')]
|
||||||
[AstExample('["Const", "Myc"]')]
|
[AstScriptExample('"Myc Script"')]
|
||||||
[AstField(0, 'value', fkValue)]
|
[AstField(0, 'value', fkValue)]
|
||||||
IConstantNode = interface(IAstTypedNode)
|
IConstantNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -228,7 +228,8 @@ type
|
|||||||
|
|
||||||
[AstTag('Id')]
|
[AstTag('Id')]
|
||||||
[AstDoc('A name referring to a variable, parameter or function.')]
|
[AstDoc('A name referring to a variable, parameter or function.')]
|
||||||
[AstExample('["Id", "x"]')]
|
[AstScriptExample('price')]
|
||||||
|
[AstScriptExample('+')]
|
||||||
[AstField(0, 'name', fkString)]
|
[AstField(0, 'name', fkString)]
|
||||||
IIdentifierNode = interface(IAstTypedNode)
|
IIdentifierNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -240,8 +241,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Key')]
|
[AstTag('Key')]
|
||||||
[AstDoc('An interned keyword literal.')]
|
[AstDoc('A keyword literal, typically used as record keys.')]
|
||||||
[AstExample('["Key", "volume"]')]
|
[AstScriptExample(':volume')]
|
||||||
[AstField(0, 'name', fkString)]
|
[AstField(0, 'name', fkString)]
|
||||||
IKeywordNode = interface(IAstTypedNode)
|
IKeywordNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -252,7 +253,8 @@ type
|
|||||||
|
|
||||||
[AstTag('Tuple')]
|
[AstTag('Tuple')]
|
||||||
[AstDoc('A positional collection of elements (Vector).')]
|
[AstDoc('A positional collection of elements (Vector).')]
|
||||||
[AstExample('["Tuple", [["Const", 1], ["Id", "y"]]]')]
|
[AstScriptExample('[1 2 3]')]
|
||||||
|
[AstScriptExample('["a" :b c]')]
|
||||||
[AstField(0, 'elements', fkNode)]
|
[AstField(0, 'elements', fkNode)]
|
||||||
ITupleNode = interface(IAstTypedNode)
|
ITupleNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -276,17 +278,8 @@ type
|
|||||||
|
|
||||||
[AstTag('If')]
|
[AstTag('If')]
|
||||||
[AstDoc('Conditional ternary expression.')]
|
[AstDoc('Conditional ternary expression.')]
|
||||||
[
|
[AstScriptExample('(if (> x 0) 1 -1)')]
|
||||||
AstExample(
|
[AstScriptExample('(if true "yes")')]
|
||||||
'''
|
|
||||||
["If",
|
|
||||||
["Call", ["Id", ">"], ["Tuple", [["Id", "x"], ["Const", 0]]]],
|
|
||||||
["Const", "ok"],
|
|
||||||
["Const", "fail"]
|
|
||||||
]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
]
|
|
||||||
[AstField(0, 'cond', fkNode)]
|
[AstField(0, 'cond', fkNode)]
|
||||||
[AstField(1, 'then', fkNode)]
|
[AstField(1, 'then', fkNode)]
|
||||||
[AstField(2, 'else', fkNullableNode)]
|
[AstField(2, 'else', fkNullableNode)]
|
||||||
@@ -304,15 +297,11 @@ type
|
|||||||
[AstTag('Cond')]
|
[AstTag('Cond')]
|
||||||
[AstDoc('Multi-branch condition. Pairs are [ [cond, branch], ... ].')]
|
[AstDoc('Multi-branch condition. Pairs are [ [cond, branch], ... ].')]
|
||||||
[
|
[
|
||||||
AstExample(
|
AstScriptExample(
|
||||||
'''
|
'''
|
||||||
["Cond",
|
(? (> x 0) :positive
|
||||||
[
|
(< x 0) :negative
|
||||||
[["Call", ["Id", "="], ["Tuple", [["Id", "s"], ["Const", 1]]]], ["Key", "up"]],
|
:zero)
|
||||||
[["Call", ["Id", "="], ["Tuple", [["Id", "s"], ["Const", 2]]]], ["Key", "down"]]
|
|
||||||
],
|
|
||||||
["Key", "flat"]
|
|
||||||
]
|
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@@ -328,17 +317,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Fn')]
|
[AstTag('Fn')]
|
||||||
[AstDoc('Anonymous function definition (lambda).')]
|
[AstDoc('An anonymous function definition (lambda).')]
|
||||||
[
|
[AstScriptExample('(fn [a b] (+ a b))')]
|
||||||
AstExample(
|
|
||||||
'''
|
|
||||||
["Fn",
|
|
||||||
["Tuple", [["Id", "a"], ["Id", "b"]]],
|
|
||||||
["Call", ["Id", "+"], ["Tuple", [["Id", "a"], ["Id", "b"]]]]
|
|
||||||
]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
]
|
|
||||||
[AstField(0, 'params', fkTuple)]
|
[AstField(0, 'params', fkTuple)]
|
||||||
[AstField(1, 'body', fkNode)]
|
[AstField(1, 'body', fkNode)]
|
||||||
ILambdaExpressionNode = interface(IFunctionDefinition)
|
ILambdaExpressionNode = interface(IFunctionDefinition)
|
||||||
@@ -355,8 +335,9 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Call')]
|
[AstTag('Call')]
|
||||||
[AstDoc('Function or operator invocation.')]
|
[AstDoc('A function or operator invocation.')]
|
||||||
[AstExample('["Call", ["Id", "abs"], ["Tuple", [["Const", -5]]]]')]
|
[AstScriptExample('(abs -5)')]
|
||||||
|
[AstScriptExample('(SMA src 14)')]
|
||||||
[AstField(0, 'callee', fkNode)]
|
[AstField(0, 'callee', fkNode)]
|
||||||
[AstField(1, 'args', fkTuple)]
|
[AstField(1, 'args', fkTuple)]
|
||||||
IFunctionCallNode = interface(IAstTypedNode)
|
IFunctionCallNode = interface(IAstTypedNode)
|
||||||
@@ -375,15 +356,14 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Block')]
|
[AstTag('Block')]
|
||||||
[AstDoc('Sequential execution of nodes.')]
|
[AstDoc('Sequential execution of nodes, returning the last result.')]
|
||||||
[
|
[
|
||||||
AstExample(
|
AstScriptExample(
|
||||||
'''
|
'''
|
||||||
["Block", ["Tuple", [
|
(do
|
||||||
["Var", ["Id", "a"], ["Const", 1]],
|
(def x 10)
|
||||||
["Assign", ["Id", "a"], ["Call", ["Id", "+"], ["Tuple", [["Id", "a"], ["Const", 1]]]]],
|
(assign x (* x 2))
|
||||||
["Id", "a"]
|
x)
|
||||||
]]]
|
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@@ -396,8 +376,9 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Var')]
|
[AstTag('Var')]
|
||||||
[AstDoc('Variable declaration.')]
|
[AstDoc('Declares a new variable in the current scope.')]
|
||||||
[AstExample('["Var", ["Id", "val"], ["Const", 0]]')]
|
[AstScriptExample('(def x 10)')]
|
||||||
|
[AstScriptExample('(def y)')]
|
||||||
[AstField(0, 'target', fkNode)]
|
[AstField(0, 'target', fkNode)]
|
||||||
[AstField(1, 'init', fkNullableNode)]
|
[AstField(1, 'init', fkNullableNode)]
|
||||||
IVariableDeclarationNode = interface(IAstTypedNode)
|
IVariableDeclarationNode = interface(IAstTypedNode)
|
||||||
@@ -412,8 +393,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Assign')]
|
[AstTag('Assign')]
|
||||||
[AstDoc('Variable assignment.')]
|
[AstDoc('Updates the value of an existing variable.')]
|
||||||
[AstExample('["Assign", ["Id", "x"], ["Const", 1]]')]
|
[AstScriptExample('(assign x 20)')]
|
||||||
[AstField(0, 'target', fkNode)]
|
[AstField(0, 'target', fkNode)]
|
||||||
[AstField(1, 'value', fkNode)]
|
[AstField(1, 'value', fkNode)]
|
||||||
IAssignmentNode = interface(IAstTypedNode)
|
IAssignmentNode = interface(IAstTypedNode)
|
||||||
@@ -426,15 +407,12 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Macro')]
|
[AstTag('Macro')]
|
||||||
[AstDoc('Syntactic macro definition.')]
|
[AstDoc('Defines a compile-time syntactic macro.')]
|
||||||
[
|
[
|
||||||
AstExample(
|
AstScriptExample(
|
||||||
'''
|
'''
|
||||||
["Macro",
|
(defmacro unless [c b]
|
||||||
["Id", "unless"],
|
`(if ~c ... ~b))
|
||||||
["Tuple", [["Id", "condition"], ["Id", "body"]]],
|
|
||||||
["Quote", ["If", ["Id", "condition"], ["Nop"], ["Unquote", ["Id", "body"]]]]
|
|
||||||
]
|
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@@ -453,7 +431,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Quote')]
|
[AstTag('Quote')]
|
||||||
[AstDoc('Suppresses evaluation of an expression.')]
|
[AstDoc('Quotes an expression to prevent immediate evaluation.')]
|
||||||
|
[AstScriptExample('`(+ 1 2)')]
|
||||||
[AstField(0, 'expr', fkNode)]
|
[AstField(0, 'expr', fkNode)]
|
||||||
IQuasiquoteNode = interface(IAstNode)
|
IQuasiquoteNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -463,7 +442,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Unquote')]
|
[AstTag('Unquote')]
|
||||||
[AstDoc('Enables evaluation inside a quoted context.')]
|
[AstDoc('Evaluates an expression inside a quoted context.')]
|
||||||
|
[AstScriptExample('~x')]
|
||||||
[AstField(0, 'expr', fkNode)]
|
[AstField(0, 'expr', fkNode)]
|
||||||
IUnquoteNode = interface(IAstNode)
|
IUnquoteNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -473,18 +453,19 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Splice')]
|
[AstTag('Splice')]
|
||||||
[AstDoc('Splicing evaluation into a list.')]
|
[AstDoc('Unrolls a list into the surrounding quoted list.')]
|
||||||
[AstField(0, 'expr', fkNode)]
|
[AstField(0, 'expr', fkNode)]
|
||||||
IUnquoteSplicingNode = interface(IAstNode)
|
IUnquoteSplicingNode = interface(IAstNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
function GetExpression: IQuasiquoteNode;
|
// BUGFIX: Should return IAstNode, not IQuasiquoteNode
|
||||||
|
function GetExpression: IAstNode;
|
||||||
{$endregion}
|
{$endregion}
|
||||||
property Expression: IQuasiquoteNode read GetExpression;
|
property Expression: IAstNode read GetExpression;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Index')]
|
[AstTag('Index')]
|
||||||
[AstDoc('Element access by position.')]
|
[AstDoc('Positional access to a vector or series element.')]
|
||||||
[AstExample('["Index", ["Id", "v"], ["Const", 0]]')]
|
[AstScriptExample('(get prices 0)')]
|
||||||
[AstField(0, 'base', fkNode)]
|
[AstField(0, 'base', fkNode)]
|
||||||
[AstField(1, 'index', fkNode)]
|
[AstField(1, 'index', fkNode)]
|
||||||
IIndexerNode = interface(IAstTypedNode)
|
IIndexerNode = interface(IAstTypedNode)
|
||||||
@@ -497,8 +478,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Member')]
|
[AstTag('Member')]
|
||||||
[AstDoc('Field access by keyword.')]
|
[AstDoc('Accesses a record field or stream member by key.')]
|
||||||
[AstExample('["Member", ["Id", "rec"], ["Key", "price"]]')]
|
[AstScriptExample('(.price rec)')]
|
||||||
[AstField(0, 'base', fkNode)]
|
[AstField(0, 'base', fkNode)]
|
||||||
[AstField(1, 'member', fkNode)]
|
[AstField(1, 'member', fkNode)]
|
||||||
IMemberAccessNode = interface(IAstTypedNode)
|
IMemberAccessNode = interface(IAstTypedNode)
|
||||||
@@ -511,17 +492,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Record')]
|
[AstTag('Record')]
|
||||||
[AstDoc('Defines a record literal.')]
|
[AstDoc('A literal key-value mapping.')]
|
||||||
[
|
[AstScriptExample('{:x 1 :y 2}')]
|
||||||
AstExample(
|
|
||||||
'''
|
|
||||||
["Record", ["Tuple", [
|
|
||||||
["Field", ["Key", "p"], ["Id", "p_val"]],
|
|
||||||
["Field", ["Key", "q"], ["Const", 100]]
|
|
||||||
]]]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
]
|
|
||||||
[AstField(0, 'fields', fkTuple)]
|
[AstField(0, 'fields', fkTuple)]
|
||||||
IRecordLiteralNode = interface(IAstTypedNode)
|
IRecordLiteralNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -535,8 +507,9 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Series')]
|
[AstTag('Series')]
|
||||||
[AstDoc('Stream schema definition.')]
|
[AstDoc('Defines a new data series schema.')]
|
||||||
[AstExample('["Series", ["Key", "Float"]]')]
|
[AstScriptExample('(new-series :Float)')]
|
||||||
|
[AstScriptExample('(new-series [[:p :Float] [:v :Ordinal]])')]
|
||||||
[AstField(0, 'definition', fkNode)]
|
[AstField(0, 'definition', fkNode)]
|
||||||
ICreateSeriesNode = interface(IAstTypedNode)
|
ICreateSeriesNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -548,8 +521,9 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Add')]
|
[AstTag('Add')]
|
||||||
[AstDoc('Pushes data to a series.')]
|
[AstDoc('Appends a value to a data series.')]
|
||||||
[AstExample('["Add", ["Id", "s"], ["Const", 10]]')]
|
[AstScriptExample('(add-item s 10.5)')]
|
||||||
|
[AstScriptExample('(add-item s 10.5 100)')]
|
||||||
[AstField(0, 'series', fkNode)]
|
[AstField(0, 'series', fkNode)]
|
||||||
[AstField(1, 'value', fkNode)]
|
[AstField(1, 'value', fkNode)]
|
||||||
[AstField(2, 'lookback', fkNullableNode)]
|
[AstField(2, 'lookback', fkNullableNode)]
|
||||||
@@ -565,8 +539,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Count')]
|
[AstTag('Count')]
|
||||||
[AstDoc('Series length.')]
|
[AstDoc('Returns the current number of elements in a series.')]
|
||||||
[AstExample('["Count", ["Id", "src"]]')]
|
[AstScriptExample('(count prices)')]
|
||||||
[AstField(0, 'series', fkNode)]
|
[AstField(0, 'series', fkNode)]
|
||||||
ISeriesLengthNode = interface(IAstTypedNode)
|
ISeriesLengthNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -576,8 +550,8 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
[AstTag('Recur')]
|
[AstTag('Recur')]
|
||||||
[AstDoc('Tail-recursive jump.')]
|
[AstDoc('Tail-recursive call to the current function.')]
|
||||||
[AstExample('["Recur", ["Tuple", [["Call", ["Id", "-"], ["Tuple", [["Id", "i"], ["Const", 1]]]]]]]')]
|
[AstScriptExample('(recur (- n 1))')]
|
||||||
[AstField(0, 'args', fkTuple)]
|
[AstField(0, 'args', fkTuple)]
|
||||||
IRecurNode = interface(IAstTypedNode)
|
IRecurNode = interface(IAstTypedNode)
|
||||||
{$region 'private'}
|
{$region 'private'}
|
||||||
@@ -589,18 +563,10 @@ type
|
|||||||
[AstTag('Pipe')]
|
[AstTag('Pipe')]
|
||||||
[AstDoc('Reactive pipeline from source streams to a transformation lambda.')]
|
[AstDoc('Reactive pipeline from source streams to a transformation lambda.')]
|
||||||
[
|
[
|
||||||
AstExample(
|
AstScriptExample(
|
||||||
'''
|
'''
|
||||||
["Pipe",
|
(pipe [[src [:val]]]
|
||||||
["Tuple", [
|
(fn [v] {:res (* v 2)}))
|
||||||
["Tuple", [["Id", "src"], ["Tuple", [["Key", "price"]]]]]
|
|
||||||
]],
|
|
||||||
["Fn", ["Tuple", [["Id", "p"]]],
|
|
||||||
["Record", ["Tuple", [
|
|
||||||
["Field", ["Key", "res"], ["Call", ["Id", "*"], ["Tuple", [["Id", "p"], ["Const", 2]]]]]
|
|
||||||
]]]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@@ -946,12 +912,12 @@ type
|
|||||||
|
|
||||||
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
|
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
|
||||||
private
|
private
|
||||||
FExpression: IQuasiquoteNode;
|
FExpression: IAstNode; // Changed to IAstNode
|
||||||
function GetExpression: IQuasiquoteNode;
|
function GetExpression: IAstNode;
|
||||||
protected
|
protected
|
||||||
function GetKind: TAstNodeKind; override;
|
function GetKind: TAstNodeKind; override;
|
||||||
public
|
public
|
||||||
constructor Create(const AExpression: IQuasiquoteNode; const AIdentity: IAstIdentity);
|
constructor Create(const AExpression: IAstNode; const AIdentity: IAstIdentity);
|
||||||
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
|
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@@ -1859,7 +1825,7 @@ end;
|
|||||||
|
|
||||||
{ TUnquoteSplicingNode }
|
{ TUnquoteSplicingNode }
|
||||||
|
|
||||||
constructor TUnquoteSplicingNode.Create(const AExpression: IQuasiquoteNode; const AIdentity: IAstIdentity);
|
constructor TUnquoteSplicingNode.Create(const AExpression: IAstNode; const AIdentity: IAstIdentity);
|
||||||
begin
|
begin
|
||||||
inherited Create(AIdentity);
|
inherited Create(AIdentity);
|
||||||
FExpression := AExpression;
|
FExpression := AExpression;
|
||||||
@@ -1869,7 +1835,7 @@ function TUnquoteSplicingNode.GetKind: TAstNodeKind;
|
|||||||
begin
|
begin
|
||||||
Result := akUnquoteSplicing;
|
Result := akUnquoteSplicing;
|
||||||
end;
|
end;
|
||||||
function TUnquoteSplicingNode.GetExpression: IQuasiquoteNode;
|
function TUnquoteSplicingNode.GetExpression: IAstNode;
|
||||||
begin
|
begin
|
||||||
Result := FExpression;
|
Result := FExpression;
|
||||||
end;
|
end;
|
||||||
|
|||||||
Reference in New Issue
Block a user