diff --git a/ASTPlayground/ASTPlayground.dpr b/ASTPlayground/ASTPlayground.dpr
index d04cda8..21890c4 100644
--- a/ASTPlayground/ASTPlayground.dpr
+++ b/ASTPlayground/ASTPlayground.dpr
@@ -42,7 +42,9 @@ uses
Myc.Data.Stream in '..\Src\Data\Myc.Data.Stream.pas',
Myc.Fmx.AstEditor.Handlers.Pipes in '..\Src\AST\Myc.Fmx.AstEditor.Handlers.Pipes.pas',
Demo.Finance in '..\Test\Demo.Finance.pas',
- Myc.Ast.Script.Print in '..\Src\AST\Myc.Ast.Script.Print.pas';
+ Myc.Ast.Script.Print in '..\Src\AST\Myc.Ast.Script.Print.pas',
+ Myc.Ast.Json.Schema in '..\Src\AST\Myc.Ast.Json.Schema.pas',
+ Myc.Ast.Attributes in 'Myc.Ast.Attributes.pas';
{$R *.res}
diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj
index 181de27..564b015 100644
--- a/ASTPlayground/ASTPlayground.dproj
+++ b/ASTPlayground/ASTPlayground.dproj
@@ -173,6 +173,8 @@
+
+
Base
diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas
index f5d2f76..aa9549f 100644
--- a/ASTPlayground/MainForm.pas
+++ b/ASTPlayground/MainForm.pas
@@ -43,6 +43,7 @@ uses
Myc.Ast.Environment,
Myc.Ast.RTL,
Myc.Ast.Compiler.Macros,
+ Myc.Ast.Json.Schema,
// Editor Units
Myc.Fmx.AstEditor,
Demo.Finance,
@@ -286,6 +287,8 @@ begin
CompilerStageBox.BringToFront;
ClearButtonClick(Self);
+
+ Memo1.Lines.Text := TAstSchema.GenerateFullSystemPrompt;
end;
procedure TForm1.ShowVizualization;
@@ -1223,24 +1226,29 @@ end;
procedure TForm1.ToJSONButtonClick(Sender: TObject);
var
- jsonObj: TJSONObject;
+ jsonVal: TJSONValue;
converter: IJsonAstConverter;
begin
Memo1.Lines.Clear;
- if not Assigned(FCurrExec.Func) then
+ // Wir prüfen besser direkt, ob der AST da ist, den wir serialisieren wollen
+ if not Assigned(FCurrUnboundAst) then
begin
- Memo1.Lines.Add('No *compiled* AST has been generated yet. Click a test button first.');
+ Memo1.Lines.Add('No AST has been generated yet. Click a test button first.');
exit;
end;
try
converter := TJsonAstConverter.Create;
- jsonObj := converter.Serialize(FCurrUnboundAst);
+ // Serialize liefert jetzt TJSONValue (Compact Array Format)
+ jsonVal := converter.Serialize(FCurrUnboundAst);
try
- Memo1.Lines.Text := jsonObj.Format(4);
+ if Assigned(jsonVal) then
+ Memo1.Lines.Text := jsonVal.Format(4)
+ else
+ Memo1.Lines.Text := 'null';
finally
- jsonObj.Free;
+ jsonVal.Free;
end;
except
on E: Exception do
diff --git a/Src/AST/Myc.Ast.JSON.pas b/Src/AST/Myc.Ast.JSON.pas
index d503567..0a090fc 100644
--- a/Src/AST/Myc.Ast.JSON.pas
+++ b/Src/AST/Myc.Ast.JSON.pas
@@ -1,3 +1,6 @@
+//==================================================================================================
+//== FULL UNIT START: Myc.Ast.Json (from Myc.Ast.Json.pas)
+//==================================================================================================
unit Myc.Ast.Json;
interface
@@ -14,80 +17,57 @@ uses
type
IJsonAstConverter = interface
- function Serialize(const RootNode: IAstNode): TJSONObject;
- function Deserialize(const AJson: TJSONObject): IAstNode;
+ function Serialize(const RootNode: IAstNode): TJSONValue;
+ function Deserialize(const AJson: TJSONValue): IAstNode;
end;
- TJsonAstConverter = class(TAstVisitor, IJsonAstConverter)
+ // Compact JSON Converter: [Kind, Arg1, Arg2, ...]
+ TJsonAstConverter = class(TAstVisitor, IJsonAstConverter)
private
- procedure DataValueToJson(const AValue: TDataValue; const AParent: TJSONObject; const AName: string);
- function JsonToNode(const AJson: TJSONValue; const ExpectedType: string = ''): IAstNode;
- function JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue;
+ // Helpers for compact data values
+ function DataValueToJson(const AValue: TDataValue): TJSONValue;
+ function JsonToDataValue(const AJson: TJSONValue): TDataValue;
- // Deserialization Helpers
- function JsonToConstantNode(const AObj: TJSONObject): IConstantNode;
- function JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode;
- function JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
- function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
- function JsonToCondExprNode(const AObj: TJSONObject): ICondExpressionNode;
- function JsonToTernaryExprNode(const AObj: TJSONObject): IAstNode;
- function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
- function JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
- function JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
- function JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
- function JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
- function JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
- function JsonToMacroExpansionNode(const AObj: TJSONObject): IMacroExpansionNode;
- function JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
- function JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
- function JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode;
- function JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
- function JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
- function JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
- function JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
- function JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
- function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
- function JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode;
- function JsonToNopNode(const AObj: TJSONObject): INopNode;
- function JsonToTupleNode(const AObj: TJSONObject): ITupleNode;
- function JsonToPipeNode(const AObj: TJSONObject): IPipeNode;
+ // Deserialization Dispatcher
+ function JsonToNode(const AJson: TJSONValue): IAstNode;
+ function JsonToTuple(const AArray: TJSONArray): ITupleNode;
strict private
- // Serialization Visitors
- function VisitConstant(const Node: IAstNode): TJSONObject;
- function VisitIdentifier(const Node: IAstNode): TJSONObject;
- function VisitKeyword(const Node: IAstNode): TJSONObject;
- function VisitTuple(const Node: IAstNode): TJSONObject;
- function VisitRecordField(const Node: IAstNode): TJSONObject;
- function VisitIfExpression(const Node: IAstNode): TJSONObject;
- function VisitCondExpression(const Node: IAstNode): TJSONObject;
- function VisitLambdaExpression(const Node: IAstNode): TJSONObject;
- function VisitMacroDefinition(const Node: IAstNode): TJSONObject;
- function VisitQuasiquote(const Node: IAstNode): TJSONObject;
- function VisitUnquote(const Node: IAstNode): TJSONObject;
- function VisitUnquoteSplicing(const Node: IAstNode): TJSONObject;
- function VisitFunctionCall(const Node: IAstNode): TJSONObject;
- function VisitMacroExpansionNode(const Node: IAstNode): TJSONObject;
- function VisitRecurNode(const Node: IAstNode): TJSONObject;
- function VisitBlockExpression(const Node: IAstNode): TJSONObject;
- function VisitVariableDeclaration(const Node: IAstNode): TJSONObject;
- function VisitAssignment(const Node: IAstNode): TJSONObject;
- function VisitIndexer(const Node: IAstNode): TJSONObject;
- function VisitMemberAccess(const Node: IAstNode): TJSONObject;
- function VisitRecordLiteral(const Node: IAstNode): TJSONObject;
- function VisitCreateSeries(const Node: IAstNode): TJSONObject;
- function VisitAddSeriesItem(const Node: IAstNode): TJSONObject;
- function VisitSeriesLength(const Node: IAstNode): TJSONObject;
- function VisitNop(const Node: IAstNode): TJSONObject;
- function VisitPipe(const Node: IAstNode): TJSONObject;
+ // Serialization Visitors (Array Builders)
+ function VisitConstant(const Node: IAstNode): TJSONValue;
+ function VisitIdentifier(const Node: IAstNode): TJSONValue;
+ function VisitKeyword(const Node: IAstNode): TJSONValue;
+ function VisitTuple(const Node: IAstNode): TJSONValue;
+ function VisitRecordField(const Node: IAstNode): TJSONValue;
+ function VisitIfExpression(const Node: IAstNode): TJSONValue;
+ function VisitCondExpression(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 VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
+ function VisitRecurNode(const Node: IAstNode): TJSONValue;
+ function VisitBlockExpression(const Node: IAstNode): TJSONValue;
+ function VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
+ function VisitAssignment(const Node: IAstNode): TJSONValue;
+ function VisitIndexer(const Node: IAstNode): TJSONValue;
+ function VisitMemberAccess(const Node: IAstNode): TJSONValue;
+ function VisitRecordLiteral(const Node: IAstNode): TJSONValue;
+ function VisitCreateSeries(const Node: IAstNode): TJSONValue;
+ function VisitAddSeriesItem(const Node: IAstNode): TJSONValue;
+ function VisitSeriesLength(const Node: IAstNode): TJSONValue;
+ function VisitNop(const Node: IAstNode): TJSONValue;
+ function VisitPipe(const Node: IAstNode): TJSONValue;
protected
procedure SetupHandlers; override;
public
constructor Create;
- function Serialize(const RootNode: IAstNode): TJSONObject;
- function Deserialize(const AJson: TJSONObject): IAstNode;
+ function Serialize(const RootNode: IAstNode): TJSONValue;
+ function Deserialize(const AJson: TJSONValue): IAstNode;
end;
implementation
@@ -133,652 +113,487 @@ begin
Register(akPipe, VisitPipe);
end;
-function TJsonAstConverter.Serialize(const RootNode: IAstNode): TJSONObject;
+function TJsonAstConverter.Serialize(const RootNode: IAstNode): TJSONValue;
begin
if not Assigned(RootNode) then
- exit(nil);
+ exit(TJSONNull.Create);
Result := Visit(RootNode);
end;
-function TJsonAstConverter.Deserialize(const AJson: TJSONObject): IAstNode;
+function TJsonAstConverter.Deserialize(const AJson: TJSONValue): IAstNode;
begin
Result := JsonToNode(AJson);
end;
-procedure TJsonAstConverter.DataValueToJson(const AValue: TDataValue; const AParent: TJSONObject; const AName: string);
-var
- valObj, scalarObj: TJSONObject;
-begin
- valObj := TJSONObject.Create;
- valObj.AddPair('Kind', TJSONString.Create(AValue.Kind.ToString));
+// --- Serialization (AST -> JSON Array) ---
+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;
+begin
case AValue.Kind of
vkScalar:
begin
- scalarObj := TJSONObject.Create;
- scalarObj.AddPair('Kind', TJSONString.Create(AValue.AsScalar.Kind.ToString));
case AValue.AsScalar.Kind of
- TScalar.TKind.Ordinal: scalarObj.AddPair('Value', TJSONNumber.Create(AValue.AsScalar.Value.AsInt64));
- TScalar.TKind.Float: scalarObj.AddPair('Value', TJSONNumber.Create(AValue.AsScalar.Value.AsDouble));
- TScalar.TKind.Boolean: scalarObj.AddPair('Value', TJSONBool.Create(AValue.AsScalar.Value.AsInt64 <> 0));
- TScalar.TKind.DateTime: scalarObj.AddPair('Value', TJSONNumber.Create(AValue.AsScalar.Value.AsDouble));
+ TScalar.TKind.Ordinal: Result := TJSONNumber.Create(AValue.AsScalar.Value.AsInt64);
+ TScalar.TKind.Float: Result := TJSONNumber.Create(AValue.AsScalar.Value.AsDouble);
+ TScalar.TKind.Boolean: Result := TJSONBool.Create(AValue.AsScalar.Value.AsInt64 <> 0);
TScalar.TKind.Keyword:
- scalarObj.AddPair('Value', TJSONString.Create(TKeywordRegistry.GetName(AValue.AsScalar.Value.AsInt64)));
+ begin
+ var obj := TJSONObject.Create;
+ obj.AddPair('Keyword', TKeywordRegistry.GetName(AValue.AsScalar.Value.AsInt64));
+ Result := obj;
+ end;
+ else
+ Result := TJSONNull.Create;
end;
- valObj.AddPair('Value', scalarObj);
end;
- vkText: valObj.AddPair('Value', TJSONString.Create(AValue.AsText));
- vkVoid:;
+ vkText: Result := TJSONString.Create(AValue.AsText);
+ vkVoid: Result := TJSONNull.Create;
else
- raise ENotSupportedException.Create('Unsupported TDataValue kind for constant serialization.');
+ Result := TJSONString.Create('');
end;
-
- AParent.AddPair(AName, valObj);
end;
-function TJsonAstConverter.VisitConstant(const Node: IAstNode): TJSONObject;
+function TJsonAstConverter.VisitTuple(const Node: IAstNode): TJSONValue;
begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Constant'));
- DataValueToJson(Node.AsConstant.Value, Result, 'Value');
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Tuple'));
+ var elems := TJSONArray.Create;
+ for var item in Node.AsTuple.Elements do
+ elems.AddElement(Visit(item));
+ arr.AddElement(elems);
+ Result := arr;
end;
-function TJsonAstConverter.VisitIdentifier(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Identifier'));
- Result.AddPair('Name', TJSONString.Create(Node.AsIdentifier.Name));
-end;
-
-function TJsonAstConverter.VisitKeyword(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Keyword'));
- Result.AddPair('Name', TJSONString.Create(Node.AsKeyword.Value.Name));
-end;
-
-function TJsonAstConverter.VisitTuple(const Node: IAstNode): TJSONObject;
-var
- T: ITupleNode;
- elemsArray: TJSONArray;
- i: Integer;
- elements: TArray;
-begin
- T := Node.AsTuple;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Tuple'));
- elemsArray := TJSONArray.Create;
-
- elements := T.Elements;
- for i := 0 to High(elements) do
- elemsArray.Add(Visit(elements[i]));
-
- Result.AddPair('Elements', elemsArray);
-end;
-
-function TJsonAstConverter.VisitIfExpression(const Node: IAstNode): TJSONObject;
-var
- E: IIfExpressionNode;
- elseObj: TJSONValue;
-begin
- E := Node.AsIfExpression;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('IfExpr'));
- Result.AddPair('Condition', Visit(E.Condition));
- Result.AddPair('ThenBranch', Visit(E.ThenBranch));
- if Assigned(E.ElseBranch) then
- elseObj := Visit(E.ElseBranch)
- else
- elseObj := TJSONNull.Create;
- Result.AddPair('ElseBranch', elseObj);
-end;
-
-function TJsonAstConverter.VisitCondExpression(const Node: IAstNode): TJSONObject;
-var
- E: ICondExpressionNode;
- pairsArray: TJSONArray;
- pairObj: TJSONObject;
- elseObj: TJSONValue;
- i: Integer;
-begin
- E := Node.AsCondExpression;
- pairsArray := TJSONArray.Create;
- for i := 0 to High(E.Pairs) do
- begin
- pairObj := TJSONObject.Create;
- pairObj.AddPair('Condition', Visit(E.Pairs[i].Condition));
- pairObj.AddPair('Branch', Visit(E.Pairs[i].Branch));
- pairsArray.Add(pairObj);
- end;
- if Assigned(E.ElseBranch) then
- elseObj := Visit(E.ElseBranch)
- else
- elseObj := TJSONNull.Create;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('CondExpr'));
- Result.AddPair('Pairs', pairsArray);
- Result.AddPair('ElseBranch', elseObj);
-end;
-
-function TJsonAstConverter.VisitLambdaExpression(const Node: IAstNode): TJSONObject;
-var
- L: ILambdaExpressionNode;
-begin
- L := Node.AsLambdaExpression;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('LambdaExpr'));
- Result.AddPair('Parameters', Visit(L.Parameters));
- Result.AddPair('Body', Visit(L.Body));
-end;
-
-function TJsonAstConverter.VisitMacroDefinition(const Node: IAstNode): TJSONObject;
-var
- M: IMacroDefinitionNode;
-begin
- M := Node.AsMacroDefinition;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('MacroDef'));
- Result.AddPair('Name', Visit(M.Name));
- Result.AddPair('Parameters', Visit(M.Parameters));
- Result.AddPair('Body', Visit(M.Body));
-end;
-
-function TJsonAstConverter.VisitQuasiquote(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Quasiquote'));
- Result.AddPair('Expression', Visit(Node.AsQuasiquote.Expression));
-end;
-
-function TJsonAstConverter.VisitUnquote(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Unquote'));
- Result.AddPair('Expression', Visit(Node.AsUnquote.Expression));
-end;
-
-function TJsonAstConverter.VisitUnquoteSplicing(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('UnquoteSplicing'));
- Result.AddPair('Expression', Visit(Node.AsUnquoteSplicing.Expression));
-end;
-
-function TJsonAstConverter.VisitFunctionCall(const Node: IAstNode): TJSONObject;
+function TJsonAstConverter.VisitFunctionCall(const Node: IAstNode): TJSONValue;
var
C: IFunctionCallNode;
begin
C := Node.AsFunctionCall;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('FunctionCall'));
- Result.AddPair('Callee', Visit(C.Callee));
- Result.AddPair('Arguments', Visit(C.Arguments));
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Call'));
+ arr.AddElement(Visit(C.Callee));
+ arr.AddElement(Visit(C.Arguments)); // Arguments is a Tuple
+ Result := arr;
end;
-function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONObject;
+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
- M: IMacroExpansionNode;
+ L: ILambdaExpressionNode;
begin
- M := Node.AsMacroExpansion;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('MacroExpansion'));
- Result.AddPair('Callee', Visit(M.CallNode.Callee));
- Result.AddPair('Arguments', Visit(M.CallNode.Arguments));
- Result.AddPair('ExpandedBody', Visit(M.ExpandedBody));
+ 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.VisitRecurNode(const Node: IAstNode): TJSONObject;
+function TJsonAstConverter.VisitMacroDefinition(const Node: IAstNode): TJSONValue;
+var
+ M: IMacroDefinitionNode;
begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Recur'));
- Result.AddPair('Arguments', Visit(Node.AsRecur.Arguments));
+ 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.VisitBlockExpression(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Block'));
- Result.AddPair('Expressions', Visit(Node.AsBlockExpression.Expressions));
-end;
-
-function TJsonAstConverter.VisitVariableDeclaration(const Node: IAstNode): TJSONObject;
+function TJsonAstConverter.VisitVariableDeclaration(const Node: IAstNode): TJSONValue;
var
V: IVariableDeclarationNode;
- initObj: TJSONValue;
begin
V := Node.AsVariableDeclaration;
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Var'));
+ arr.AddElement(Visit(V.Target));
if Assigned(V.Initializer) then
- initObj := Visit(V.Initializer)
+ arr.AddElement(Visit(V.Initializer))
else
- initObj := TJSONNull.Create;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('VarDecl'));
- Result.AddPair('Identifier', Visit(V.Target));
- Result.AddPair('Initializer', initObj);
+ arr.AddElement(TJSONNull.Create);
+ Result := arr;
end;
-function TJsonAstConverter.VisitAssignment(const Node: IAstNode): TJSONObject;
+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;
+end;
+
+function TJsonAstConverter.VisitIfExpression(const Node: IAstNode): TJSONValue;
var
- A: IAssignmentNode;
+ E: IIfExpressionNode;
begin
- A := Node.AsAssignment;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Assignment'));
- Result.AddPair('Identifier', Visit(A.Target));
- Result.AddPair('Value', Visit(A.Value));
-end;
-
-function TJsonAstConverter.VisitIndexer(const Node: IAstNode): TJSONObject;
-var
- I: IIndexerNode;
-begin
- I := Node.AsIndexer;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Indexer'));
- Result.AddPair('Base', Visit(I.Base));
- Result.AddPair('Index', Visit(I.Index));
-end;
-
-function TJsonAstConverter.VisitMemberAccess(const Node: IAstNode): TJSONObject;
-var
- M: IMemberAccessNode;
-begin
- M := Node.AsMemberAccess;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('MemberAccess'));
- Result.AddPair('Base', Visit(M.Base));
- Result.AddPair('Member', Visit(M.Member));
-end;
-
-function TJsonAstConverter.VisitRecordLiteral(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('RecordLiteral'));
- Result.AddPair('Fields', Visit(Node.AsRecordLiteral.Fields));
-end;
-
-function TJsonAstConverter.VisitRecordField(const Node: IAstNode): TJSONObject;
-var
- F: IRecordFieldNode;
-begin
- F := Node.AsRecordField;
- Result := TJSONObject.Create;
- Result.AddPair('Name', TJSONString.Create(F.Key.Value.Name));
- Result.AddPair('Value', Visit(F.Value));
-end;
-
-function TJsonAstConverter.VisitCreateSeries(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('CreateSeries'));
- // REFACTORED: Now serialize the DefinitionNode structure instead of a raw string
- Result.AddPair('DefinitionNode', Visit(Node.AsCreateSeries.DefinitionNode));
-end;
-
-function TJsonAstConverter.VisitAddSeriesItem(const Node: IAstNode): TJSONObject;
-var
- A: IAddSeriesItemNode;
- lookbackObj: TJSONValue;
-begin
- A := Node.AsAddSeriesItem;
- if Assigned(A.Lookback) then
- lookbackObj := Visit(A.Lookback)
+ E := Node.AsIfExpression;
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('If'));
+ arr.AddElement(Visit(E.Condition));
+ arr.AddElement(Visit(E.ThenBranch));
+ if Assigned(E.ElseBranch) then
+ arr.AddElement(Visit(E.ElseBranch))
else
- lookbackObj := TJSONNull.Create;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('AddSeriesItem'));
- Result.AddPair('Series', Visit(A.Series));
- Result.AddPair('Value', Visit(A.Value));
- Result.AddPair('Lookback', lookbackObj);
+ arr.AddElement(TJSONNull.Create);
+ Result := arr;
end;
-function TJsonAstConverter.VisitSeriesLength(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('SeriesLength'));
- Result.AddPair('Series', Visit(Node.AsSeriesLength.Series));
-end;
-
-function TJsonAstConverter.VisitNop(const Node: IAstNode): TJSONObject;
-begin
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Nop'));
-end;
-
-function TJsonAstConverter.VisitPipe(const Node: IAstNode): TJSONObject;
+function TJsonAstConverter.VisitCondExpression(const Node: IAstNode): TJSONValue;
var
- P: IPipeNode;
+ E: ICondExpressionNode;
+ pairs: TJSONArray;
begin
- P := Node.AsPipe;
- Result := TJSONObject.Create;
- Result.AddPair('NodeType', TJSONString.Create('Pipe'));
- Result.AddPair('Inputs', Visit(P.Inputs));
- Result.AddPair('Transformation', Visit(P.Transformation));
-end;
-
-{ Deserialization Handlers }
-
-function TJsonAstConverter.JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue;
-var
- valObj, scalarObj: TJSONObject;
- kindStr: string;
-begin
- valObj := AObj.GetValue(AName);
- kindStr := valObj.GetValue('Kind');
-
- if SameText(kindStr, 'Scalar') then
+ E := Node.AsCondExpression;
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Cond'));
+ pairs := TJSONArray.Create;
+ for var p in E.Pairs do
begin
- scalarObj := valObj.GetValue('Value');
- case TScalar.StringToKind(scalarObj.GetValue('Kind')) of
- TScalar.TKind.Ordinal: Result := TScalar.FromInt64(scalarObj.GetValue('Value').AsInt64);
- TScalar.TKind.Float: Result := TScalar.FromDouble(scalarObj.GetValue('Value').AsDouble);
- TScalar.TKind.Boolean: Result := TScalar.FromBoolean(scalarObj.GetValue('Value').AsBoolean);
- TScalar.TKind.DateTime: Result := TScalar.FromDateTime(scalarObj.GetValue('Value').AsDouble);
- TScalar.TKind.Keyword: Result := TScalar.FromKeyword(TKeywordRegistry.Intern(scalarObj.GetValue('Value')));
- end;
+ var pArr := TJSONArray.Create;
+ pArr.AddElement(Visit(p.Condition));
+ pArr.AddElement(Visit(p.Branch));
+ pairs.AddElement(pArr);
+ end;
+ arr.AddElement(pairs);
+ if Assigned(E.ElseBranch) then
+ arr.AddElement(Visit(E.ElseBranch))
+ else
+ arr.AddElement(TJSONNull.Create);
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitQuasiquote(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Quote'));
+ arr.AddElement(Visit(Node.AsQuasiquote.Expression));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitUnquote(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Unquote'));
+ arr.AddElement(Visit(Node.AsUnquote.Expression));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitUnquoteSplicing(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Splice'));
+ arr.AddElement(Visit(Node.AsUnquoteSplicing.Expression));
+ Result := arr;
+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;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Index'));
+ arr.AddElement(Visit(Node.AsIndexer.Base));
+ arr.AddElement(Visit(Node.AsIndexer.Index));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitMemberAccess(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Member'));
+ arr.AddElement(Visit(Node.AsMemberAccess.Base));
+ arr.AddElement(Visit(Node.AsMemberAccess.Member));
+ Result := arr;
+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;
+end;
+
+function TJsonAstConverter.VisitRecordLiteral(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Record'));
+ arr.AddElement(Visit(Node.AsRecordLiteral.Fields)); // Tuple
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitCreateSeries(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Series'));
+ arr.AddElement(Visit(Node.AsCreateSeries.DefinitionNode));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitAddSeriesItem(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Add'));
+ arr.AddElement(Visit(Node.AsAddSeriesItem.Series));
+ arr.AddElement(Visit(Node.AsAddSeriesItem.Value));
+ if Assigned(Node.AsAddSeriesItem.Lookback) then
+ arr.AddElement(Visit(Node.AsAddSeriesItem.Lookback))
+ else
+ arr.AddElement(TJSONNull.Create);
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitSeriesLength(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Count'));
+ arr.AddElement(Visit(Node.AsSeriesLength.Series));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitPipe(const Node: IAstNode): TJSONValue;
+begin
+ var arr := TJSONArray.Create;
+ arr.AddElement(TJSONString.Create('Pipe'));
+ arr.AddElement(Visit(Node.AsPipe.Inputs));
+ arr.AddElement(Visit(Node.AsPipe.Transformation));
+ Result := arr;
+end;
+
+function TJsonAstConverter.VisitNop(const Node: IAstNode): TJSONValue;
+begin
+ Result := TJSONArray.Create;
+ TJSONArray(Result).AddElement(TJSONString.Create('Nop'));
+end;
+
+function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONValue;
+begin
+ // Serialize original call
+ Result := Visit(Node.AsMacroExpansion.CallNode);
+end;
+
+// --- Deserialization (JSON Array -> AST) ---
+
+function TJsonAstConverter.JsonToDataValue(const AJson: TJSONValue): TDataValue;
+var
+ s: string;
+begin
+ if AJson is TJSONNumber then
+ begin
+ var d := (AJson as TJSONNumber).AsDouble;
+ if Frac(d) = 0 then
+ Result := TScalar.FromInt64(Trunc(d))
+ else
+ Result := TScalar.FromDouble(d);
end
- else if SameText(kindStr, 'Text') then
- Result := valObj.GetValue('Value')
- else if SameText(kindStr, 'Void') then
- Result := TDataValue.Void
+ else if AJson is TJSONString then
+ Result := (AJson as TJSONString).Value
+ else if AJson is TJSONBool then
+ Result := TScalar.FromBoolean((AJson as TJSONBool).AsBoolean)
+ else if (AJson is TJSONObject) and (AJson as TJSONObject).TryGetValue('Keyword', s) then
+ Result := TScalar.FromKeyword(TKeywordRegistry.Intern(s))
else
- raise ENotSupportedException.Create('Unsupported TDataValue kind.');
+ Result := TDataValue.Void;
end;
-function TJsonAstConverter.JsonToNode(const AJson: TJSONValue; const ExpectedType: string): IAstNode;
+function TJsonAstConverter.JsonToTuple(const AArray: TJSONArray): ITupleNode;
var
- obj: TJSONObject;
- nodeType: string;
-begin
- if not (AJson is TJSONObject) then
- raise EInvalidCast.Create('Expected JSON object.');
- obj := AJson as TJSONObject;
- nodeType := obj.GetValue('NodeType');
-
- if nodeType = 'Constant' then
- Result := JsonToConstantNode(obj)
- else if nodeType = 'Identifier' then
- Result := JsonToIdentifierNode(obj)
- else if nodeType = 'Keyword' then
- Result := JsonToKeywordNode(obj)
- else if nodeType = 'IfExpr' then
- Result := JsonToIfExprNode(obj)
- else if nodeType = 'CondExpr' then
- Result := JsonToCondExprNode(obj)
- else if nodeType = 'TernaryExpr' then
- Result := JsonToTernaryExprNode(obj)
- else if nodeType = 'LambdaExpr' then
- Result := JsonToLambdaExprNode(obj)
- else if nodeType = 'MacroDef' then
- Result := JsonToMacroDefNode(obj)
- else if nodeType = 'MacroExpansion' then
- Result := JsonToMacroExpansionNode(obj)
- else if nodeType = 'Quasiquote' then
- Result := JsonToQuasiquoteNode(obj)
- else if nodeType = 'Unquote' then
- Result := JsonToUnquoteNode(obj)
- else if nodeType = 'UnquoteSplicing' then
- Result := JsonToUnquoteSplicingNode(obj)
- else if nodeType = 'FunctionCall' then
- Result := JsonToFunctionCallNode(obj)
- else if nodeType = 'Recur' then
- Result := JsonToRecurNode(obj)
- else if nodeType = 'Block' then
- Result := JsonToBlockNode(obj)
- else if nodeType = 'VarDecl' then
- Result := JsonToVarDeclNode(obj)
- else if nodeType = 'Assignment' then
- Result := JsonToAssignmentNode(obj)
- else if nodeType = 'Indexer' then
- Result := JsonToIndexerNode(obj)
- else if nodeType = 'MemberAccess' then
- Result := JsonToMemberAccessNode(obj)
- else if nodeType = 'RecordLiteral' then
- Result := JsonToRecordLiteralNode(obj)
- else if nodeType = 'CreateSeries' then
- Result := JsonToCreateSeriesNode(obj)
- else if nodeType = 'AddSeriesItem' then
- Result := JsonToAddSeriesItemNode(obj)
- else if nodeType = 'SeriesLength' then
- Result := JsonToSeriesLengthNode(obj)
- else if nodeType = 'Nop' then
- Result := JsonToNopNode(obj)
- else if nodeType = 'Tuple' then
- Result := JsonToTupleNode(obj)
- else if nodeType = 'Pipe' then
- Result := JsonToPipeNode(obj)
- else
- raise ENotSupportedException.CreateFmt('Unsupported NodeType "%s".', [nodeType]);
-end;
-
-function TJsonAstConverter.JsonToConstantNode(const AObj: TJSONObject): IConstantNode;
-begin
- Result := TAst.Constant(JsonToDataValue(AObj, 'Value'));
-end;
-
-function TJsonAstConverter.JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode;
-begin
- Result := TAst.Identifier(AObj.GetValue('Name'));
-end;
-
-function TJsonAstConverter.JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
-begin
- Result := TAst.Keyword(AObj.GetValue('Name'));
-end;
-
-function TJsonAstConverter.JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode;
-var
- elseNode: IAstNode;
-begin
- if AObj.GetValue('ElseBranch') is TJSONNull then
- elseNode := nil
- else
- elseNode := JsonToNode(AObj.GetValue('ElseBranch'));
- Result := TAst.IfExpr(JsonToNode(AObj.GetValue('Condition')), JsonToNode(AObj.GetValue('ThenBranch')), elseNode);
-end;
-
-function TJsonAstConverter.JsonToCondExprNode(const AObj: TJSONObject): ICondExpressionNode;
-var
- pairsArray: TJSONArray;
- pairs: TArray;
- i: Integer;
- elseNode: IAstNode;
-begin
- pairsArray := AObj.GetValue('Pairs');
- SetLength(pairs, pairsArray.Count);
- for i := 0 to pairsArray.Count - 1 do
- pairs[i] :=
- TCondPair.Create(
- JsonToNode((pairsArray.Items[i] as TJSONObject).GetValue('Condition')),
- JsonToNode((pairsArray.Items[i] as TJSONObject).GetValue('Branch'))
- );
- if AObj.GetValue('ElseBranch') is TJSONNull then
- elseNode := nil
- else
- elseNode := JsonToNode(AObj.GetValue('ElseBranch'));
- Result := TAst.CondExpr(pairs, elseNode);
-end;
-
-function TJsonAstConverter.JsonToTernaryExprNode(const AObj: TJSONObject): IAstNode;
-begin
- Result :=
- TAst.TernaryExpr(
- JsonToNode(AObj.GetValue('Condition')),
- JsonToNode(AObj.GetValue('ThenBranch')),
- JsonToNode(AObj.GetValue('ElseBranch'))
- );
-end;
-
-function TJsonAstConverter.JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode;
-var
- identNodes: TList;
- node: IAstNode;
-begin
- identNodes := TList.Create;
- try
- for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
- identNodes.Add(node.AsIdentifier);
- Result := TAst.LambdaExpr(identNodes.ToArray, JsonToNode(AObj.GetValue('Body')));
- finally
- identNodes.Free;
- end;
-end;
-
-function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode;
-var
- identNodes: TList;
- node: IAstNode;
-begin
- identNodes := TList.Create;
- try
- for node in JsonToNode(AObj.GetValue('Parameters')).AsTuple.Elements do
- identNodes.Add(node.AsIdentifier);
- Result :=
- TAst.MacroDef(
- JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject),
- identNodes.ToArray,
- JsonToNode(AObj.GetValue('Body'))
- );
- finally
- identNodes.Free;
- end;
-end;
-
-function TJsonAstConverter.JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
-begin
- Result := TAst.Quasiquote(JsonToNode(AObj.GetValue('Expression')));
-end;
-
-function TJsonAstConverter.JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
-begin
- Result := TAst.Unquote(JsonToNode(AObj.GetValue('Expression')));
-end;
-
-function TJsonAstConverter.JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
-begin
- Result := TAst.UnquoteSplicing(JsonToNode(AObj.GetValue('Expression')).AsQuasiquote);
-end;
-
-function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
-begin
- Result := TAst.FunctionCall(JsonToNode(AObj.GetValue('Callee')), JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
-end;
-
-function TJsonAstConverter.JsonToMacroExpansionNode(const AObj: TJSONObject): IMacroExpansionNode;
-var
- callee, expandedBody: IAstNode;
- argsTuple: ITupleNode;
-begin
- callee := JsonToNode(AObj.GetValue('Callee'));
- expandedBody := JsonToNode(AObj.GetValue('ExpandedBody'));
- argsTuple := JsonToNode(AObj.GetValue('Arguments')).AsTuple;
- Result := TAst.MacroExpansionNode(TAst.FunctionCall(callee, argsTuple.Elements), expandedBody);
-end;
-
-function TJsonAstConverter.JsonToRecurNode(const AObj: TJSONObject): IRecurNode;
-begin
- Result := TAst.Recur(JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements);
-end;
-
-function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode;
-begin
- Result := TAst.Block(JsonToNode(AObj.GetValue('Expressions')).AsTuple.Elements);
-end;
-
-function TJsonAstConverter.JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode;
-var
- initNode: IAstNode;
-begin
- if AObj.GetValue('Initializer') is TJSONNull then
- initNode := nil
- else
- initNode := JsonToNode(AObj.GetValue('Initializer'));
- Result := TAst.VarDecl(JsonToIdentifierNode(AObj.GetValue('Identifier') as TJSONObject), initNode);
-end;
-
-function TJsonAstConverter.JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode;
-begin
- Result := TAst.Assign(JsonToIdentifierNode(AObj.GetValue('Identifier') as TJSONObject), JsonToNode(AObj.GetValue('Value')));
-end;
-
-function TJsonAstConverter.JsonToIndexerNode(const AObj: TJSONObject): IIndexerNode;
-begin
- Result := TAst.Indexer(JsonToNode(AObj.GetValue('Base')), JsonToNode(AObj.GetValue('Index')));
-end;
-
-function TJsonAstConverter.JsonToMemberAccessNode(const AObj: TJSONObject): IMemberAccessNode;
-begin
- Result := TAst.MemberAccess(JsonToNode(AObj.GetValue('Base')), JsonToKeywordNode(AObj.GetValue('Member') as TJSONObject).AsKeyword);
-end;
-
-function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode;
-var
- fieldsArray: TJSONArray;
- fields: TList;
- i: Integer;
-begin
- fieldsArray := AObj.GetValue('Fields');
- fields := TList.Create;
- try
- for i := 0 to fieldsArray.Count - 1 do
- begin
- var fieldObj := fieldsArray.Items[i] as TJSONObject;
- fields.Add(TAst.RecordField(TAst.Keyword(fieldObj.GetValue('Name')), JsonToNode(fieldObj.GetValue('Value'))));
- end;
- Result := TAst.RecordLiteral(fields.ToArray);
- finally
- fields.Free;
- end;
-end;
-
-function TJsonAstConverter.JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode;
-begin
- // REFACTORED: Use the definition node from JSON
- Result := TAst.CreateSeries(JsonToNode(AObj.GetValue('DefinitionNode')));
-end;
-
-function TJsonAstConverter.JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode;
-var
- lookNode: IAstNode;
-begin
- if AObj.GetValue('Lookback') is TJSONNull then
- lookNode := nil
- else
- lookNode := JsonToNode(AObj.GetValue('Lookback'));
- Result :=
- TAst.AddSeriesItem(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject), JsonToNode(AObj.GetValue('Value')), lookNode);
-end;
-
-function TJsonAstConverter.JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode;
-begin
- Result := TAst.SeriesLength(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject));
-end;
-
-function TJsonAstConverter.JsonToNopNode(const AObj: TJSONObject): INopNode;
-begin
- Result := TAst.Nop.AsNop;
-end;
-
-function TJsonAstConverter.JsonToTupleNode(const AObj: TJSONObject): ITupleNode;
-var
- elemsArray: TJSONArray;
elems: TList;
i: Integer;
begin
- elemsArray := AObj.GetValue('Elements');
elems := TList.Create;
try
- for i := 0 to elemsArray.Count - 1 do
- elems.Add(JsonToNode(elemsArray.Items[i]));
+ for i := 0 to AArray.Count - 1 do
+ elems.Add(JsonToNode(AArray.Items[i]));
Result := TAst.Tuple(elems.ToArray);
finally
elems.Free;
end;
end;
-function TJsonAstConverter.JsonToPipeNode(const AObj: TJSONObject): IPipeNode;
+function TJsonAstConverter.JsonToNode(const AJson: TJSONValue): IAstNode;
+var
+ arr: TJSONArray;
+ kind: string;
begin
- Result := TAst.Pipe(JsonToNode(AObj.GetValue('Inputs')).AsTuple, JsonToNode(AObj.GetValue('Transformation')).AsLambdaExpression);
+ if AJson is TJSONNull then
+ exit(nil);
+
+ if not (AJson is TJSONArray) then
+ raise EInvalidCast.Create('AST Node must be a JSON Array');
+
+ arr := AJson as TJSONArray;
+ if arr.Count = 0 then
+ raise EInvalidCast.Create('Empty node array');
+
+ kind := arr.Items[0].Value;
+
+ if kind = 'Id' then
+ Exit(TAst.Identifier(arr.Items[1].Value));
+ if kind = 'Key' then
+ Exit(TAst.Keyword(arr.Items[1].Value));
+ if kind = 'Const' then
+ 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
+ Exit(TAst.Nop);
+
+ if kind = 'Call' then
+ Exit(TAst.FunctionCall(JsonToNode(arr.Items[1]), JsonToTuple(arr.Items[2] as TJSONArray).Elements));
+
+ if kind = 'Fn' then
+ // Pass TIdentities.Structural as Identity to satisfy the overload requiring (Identity, Tuple, Body, ...)
+ Exit(TAst.LambdaExpr(TIdentities.Structural, JsonToTuple(arr.Items[1] as TJSONArray), JsonToNode(arr.Items[2])));
+
+ if kind = 'Macro' then
+ // Pass TIdentities.Structural as Identity
+ Exit(
+ TAst.MacroDef(
+ TIdentities.Structural,
+ JsonToNode(arr.Items[1]).AsIdentifier,
+ JsonToTuple(arr.Items[2] as TJSONArray),
+ JsonToNode(arr.Items[3])
+ )
+ );
+
+ if kind = 'Var' then
+ begin
+ var init: IAstNode := nil;
+ if arr.Count > 2 then
+ init := JsonToNode(arr.Items[2]);
+ Exit(TAst.VarDecl(JsonToNode(arr.Items[1]), init));
+ end;
+
+ if kind = 'Assign' then
+ Exit(TAst.Assign(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
+
+ if kind = 'If' then
+ begin
+ var el: IAstNode := nil;
+ if arr.Count > 3 then
+ el := JsonToNode(arr.Items[3]);
+ Exit(TAst.IfExpr(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2]), el));
+ end;
+
+ if kind = 'Cond' then
+ begin
+ var pairArr := arr.Items[1] as TJSONArray;
+ var pairs: TArray;
+ SetLength(pairs, pairArr.Count);
+ for var i := 0 to pairArr.Count - 1 do
+ begin
+ var p := pairArr.Items[i] as TJSONArray;
+ pairs[i] := TCondPair.Create(JsonToNode(p.Items[0]), JsonToNode(p.Items[1]));
+ end;
+ var el: IAstNode := nil;
+ if arr.Count > 2 then
+ el := JsonToNode(arr.Items[2]);
+ Exit(TAst.CondExpr(pairs, el));
+ end;
+
+ if kind = 'Quote' then
+ Exit(TAst.Quasiquote(JsonToNode(arr.Items[1])));
+ if kind = 'Unquote' then
+ Exit(TAst.Unquote(JsonToNode(arr.Items[1])));
+ if kind = 'Splice' then
+ Exit(TAst.UnquoteSplicing(JsonToNode(arr.Items[1]).AsQuasiquote));
+ if kind = 'Recur' then
+ Exit(TAst.Recur(JsonToTuple(arr.Items[1] as TJSONArray).Elements));
+
+ if kind = 'Index' then
+ Exit(TAst.Indexer(JsonToNode(arr.Items[1]), JsonToNode(arr.Items[2])));
+ if kind = 'Member' then
+ 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 := TList.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
+ Exit(TAst.CreateSeries(JsonToNode(arr.Items[1])));
+
+ if kind = 'Add' then
+ begin
+ var lb: IAstNode := nil;
+ if arr.Count > 3 then
+ lb := JsonToNode(arr.Items[3]);
+ Exit(TAst.AddSeriesItem(JsonToNode(arr.Items[1]).AsIdentifier, JsonToNode(arr.Items[2]), lb));
+ 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);
end;
end.
+ //==================================================================================================
+//== FULL UNIT END: Myc.Ast.Json
+//==================================================================================================
diff --git a/Src/AST/Myc.Ast.Json.Schema.pas b/Src/AST/Myc.Ast.Json.Schema.pas
new file mode 100644
index 0000000..1c9ce18
--- /dev/null
+++ b/Src/AST/Myc.Ast.Json.Schema.pas
@@ -0,0 +1,219 @@
+unit Myc.Ast.Json.Schema;
+
+interface
+
+uses
+ System.SysUtils,
+ System.Classes,
+ System.Generics.Collections,
+ System.Generics.Defaults,
+ System.Rtti,
+ System.TypInfo,
+ Myc.Ast.Nodes,
+ Myc.Ast.Attributes;
+
+type
+ TAstSchema = class
+ public
+ // Generates the TypeScript definition by scanning classes via RTTI
+ class function GenerateTypeScriptDefinition: string;
+
+ // Static rules for the format
+ class function GenerateGenerationRules: string;
+
+ // Combined prompt
+ class function GenerateFullSystemPrompt: string;
+ end;
+
+implementation
+
+type
+ // Helper structure to collect fields per type
+ // Moved here to avoid scope issues with generics
+ TFieldInfo = record
+ Idx: Integer;
+ Def: string;
+ end;
+
+{ TAstSchema }
+
+class function TAstSchema.GenerateTypeScriptDefinition: string;
+var
+ ctx: TRttiContext;
+ types: TArray;
+ typ: TRttiType;
+ attr: TCustomAttribute;
+ fieldAttr: AstFieldAttribute;
+ nodeDefs: TDictionary>;
+ unionTypes: TList;
+ fieldsList: TList;
+ sb: TStringBuilder;
+ tag: string;
+ fieldInfo: TFieldInfo;
+ f: TRttiField;
+ i: Integer;
+
+ function GetTsType(Kind: TFieldKind): string;
+ begin
+ case Kind of
+ fkNode: Result := 'AstNode';
+ fkTuple: Result := 'Tuple';
+ fkString: Result := 'string';
+ fkValue: Result := 'number | string | boolean';
+ fkNullableNode: Result := 'AstNode | null';
+ fkArrayOfPairs: Result := 'Array<[AstNode, AstNode]>';
+ else
+ Result := 'any';
+ end;
+ end;
+
+begin
+ ctx := TRttiContext.Create;
+ nodeDefs := TDictionary>.Create;
+ unionTypes := TList.Create;
+ sb := TStringBuilder.Create;
+
+ try
+ // 1. Scan all types in the application context
+ types := ctx.GetTypes;
+
+ for typ in types do
+ begin
+ if not typ.IsInstance then
+ Continue;
+
+ // Check for [AstTag] attribute on the class
+ tag := '';
+ for attr in typ.GetAttributes do
+ if attr is AstTagAttribute then
+ begin
+ tag := AstTagAttribute(attr).Tag;
+ Break;
+ end;
+
+ if tag = '' then
+ Continue;
+
+ if not nodeDefs.ContainsKey(tag) then
+ begin
+ nodeDefs.Add(tag, TList.Create);
+ unionTypes.Add(tag);
+ end;
+
+ fieldsList := nodeDefs[tag];
+
+ // Scan Fields (Variables) of the class
+ for f in typ.AsInstance.GetFields do
+ begin
+ for attr in f.GetAttributes do
+ if attr is AstFieldAttribute then
+ begin
+ fieldAttr := AstFieldAttribute(attr);
+
+ fieldInfo.Idx := fieldAttr.Index;
+ fieldInfo.Def := GetTsType(fieldAttr.Kind) + ' /*' + fieldAttr.Name + '*/';
+
+ fieldsList.Add(fieldInfo);
+ end;
+ end;
+ end;
+
+ // 2. Build the output
+ sb.AppendLine('// AST Schema Definition (Auto-Generated via RTTI)');
+ sb.AppendLine('// Format: Compact JSON Arrays [Tag, Arg1, Arg2, ...]');
+ sb.AppendLine;
+
+ unionTypes.Sort;
+
+ // Union Type Definition
+ sb.AppendLine('type AstNode = ');
+ for i := 0 to unionTypes.Count - 1 do
+ begin
+ sb.Append(' | ' + unionTypes[i]);
+ if i < unionTypes.Count - 1 then
+ sb.AppendLine;
+ end;
+ sb.AppendLine(';');
+ sb.AppendLine;
+
+ sb.AppendLine('type Tuple = ["Tuple", AstNode[]];');
+ sb.AppendLine;
+
+ // Node Definitions
+ for tag in unionTypes do
+ begin
+ // Tuple is special base type
+ if tag = 'Tuple' then
+ Continue;
+
+ fieldsList := nodeDefs[tag];
+
+ // Sort fields by Index to ensure correct JSON array order
+ fieldsList.Sort(TComparer.Construct(function(const L, R: TFieldInfo): Integer begin Result := L.Idx - R.Idx; end));
+
+ sb.Append('type ' + tag + ' = ["' + tag + '"');
+
+ for fieldInfo in fieldsList do
+ sb.Append(', ' + fieldInfo.Def);
+
+ sb.AppendLine('];');
+ end;
+
+ Result := sb.ToString;
+
+ finally
+ // Clean up lists in dictionary
+ for tag in nodeDefs.Keys do
+ nodeDefs[tag].Free;
+
+ nodeDefs.Free;
+ unionTypes.Free;
+ sb.Free;
+ ctx.Free;
+ end;
+end;
+
+class function TAstSchema.GenerateGenerationRules: string;
+var
+ sb: TStringBuilder;
+begin
+ // These rules describe the PROTOCOL (Compact Arrays), not the content.
+ // They remain static unless you change TJsonAstConverter logic significantly.
+ sb := TStringBuilder.Create;
+ try
+ sb.AppendLine('**âš ï¸ CRITICAL GENERATION RULES:**');
+ sb.AppendLine;
+ sb.AppendLine('1. **NO JSON OBJECTS:** Do not use `{ "key": "value" }`. Every node MUST be a JSON Array `["Tag", Arg1, Arg2]`.');
+ sb.AppendLine(
+ '2. **EXPLICIT TUPLES:** Whenever a field in the schema is defined as `Tuple`, you MUST wrap the list in a `["Tuple", [...]]` node.'
+ );
+ sb.AppendLine(
+ '3. **EXPLICIT NULLS:** Optional fields (marked as `| null`) MUST be explicit `null` if not present. Do not omit them.'
+ );
+ sb.AppendLine('4. **STRICT ORDER:** The order of elements in the array is fixed defined by the schema. Never swap arguments.');
+
+ Result := sb.ToString;
+ finally
+ sb.Free;
+ end;
+end;
+
+class function TAstSchema.GenerateFullSystemPrompt: string;
+begin
+ // Combine everything
+ Result :=
+ 'You are a compiler frontend for the "Myc" scripting language.'
+ + sLineBreak
+ + 'Your task is to generate a valid Abstract Syntax Tree (AST) in a specific Compact JSON format.'
+ + sLineBreak
+ + sLineBreak
+ + '### 1. AST Schema (TypeScript Definition)'
+ + sLineBreak
+ + GenerateTypeScriptDefinition
+ + sLineBreak
+ + '### 2. Constraints & Rules'
+ + sLineBreak
+ + GenerateGenerationRules;
+end;
+
+end.
diff --git a/Src/AST/Myc.Ast.Nodes.pas b/Src/AST/Myc.Ast.Nodes.pas
index dde9248..d476668 100644
--- a/Src/AST/Myc.Ast.Nodes.pas
+++ b/Src/AST/Myc.Ast.Nodes.pas
@@ -1,3 +1,6 @@
+//==================================================================================================
+//== FULL UNIT START: Myc.Ast.Nodes (from Myc.Ast.Nodes.pas)
+//==================================================================================================
unit Myc.Ast.Nodes;
interface
@@ -10,7 +13,8 @@ uses
Myc.Data.Keyword,
Myc.Ast.Scope,
Myc.Ast.Types,
- Myc.Ast.Identities;
+ Myc.Ast.Identities,
+ Myc.Ast.Attributes; // Hinzugefügt für [AstTag] und [AstField]
type
// --- Forward Declarations ---
@@ -197,7 +201,6 @@ type
function AsRecur: IRecurNode;
function AsNop: INopNode;
- // Pipes
function AsPipe: IPipeNode;
property IsTyped: Boolean read GetIsTyped;
@@ -528,9 +531,12 @@ type
property StaticType: IStaticType read GetStaticType;
end;
+ [AstTag('Field')]
TRecordFieldNode = class(TAstNode, IRecordFieldNode)
private
+ [AstField(0, 'key', fkNode)]
FKey: IKeywordNode;
+ [AstField(1, 'value', fkNode)]
FValue: IAstNode;
function GetKey: IKeywordNode;
function GetValue: IAstNode;
@@ -543,8 +549,10 @@ type
// --- Core Nodes Implementations ---
+ [AstTag('Const')]
TConstantNode = class(TAstTypedNode, IConstantNode)
private
+ [AstField(0, 'value', fkValue)]
FConstIdentity: IConstantIdentity; // Typed reference for fast access
function GetValue: TDataValue;
protected
@@ -554,8 +562,10 @@ type
function AsConstant: IConstantNode; override;
end;
+ [AstTag('Id')]
TIdentifierNode = class(TAstTypedNode, IIdentifierNode)
private
+ [AstField(0, 'name', fkString)]
FNamedIdentity: INamedIdentity; // Typed reference for fast access
FAddress: TResolvedAddress;
function GetAddress: TResolvedAddress;
@@ -567,8 +577,10 @@ type
function AsIdentifier: IIdentifierNode; override;
end;
+ [AstTag('Key')]
TKeywordNode = class(TAstTypedNode, IKeywordNode)
private
+ [AstField(0, 'name', fkString)]
FKeywordIdentity: IKeywordIdentity;
function GetValue: IKeyword;
protected
@@ -578,8 +590,10 @@ type
function AsKeyword: IKeywordNode; override;
end;
+ [AstTag('Tuple')]
TTupleNode = class(TAstTypedNode, ITupleNode)
private
+ [AstField(0, 'elements', fkNode)] // Represents array
FElements: TArray;
function GetElements: TArray;
protected
@@ -589,8 +603,10 @@ type
function AsTuple: ITupleNode; override;
end;
+ [AstTag('Series')]
TCreateSeriesNode = class(TAstTypedNode, ICreateSeriesNode)
private
+ [AstField(0, 'definition', fkNode)]
FDefinitionNode: IAstNode;
FRecordDefinition: IScalarRecordDefinition;
function GetDefinitionNode: IAstNode;
@@ -609,9 +625,15 @@ type
// --- Structural Nodes (Identity only for location) ---
+ [AstTag('If')]
TIfExpressionNode = class(TAstTypedNode, IIfExpressionNode)
private
- FCondition, FThenBranch, FElseBranch: IAstNode;
+ [AstField(0, 'cond', fkNode)]
+ FCondition: IAstNode;
+ [AstField(1, 'then', fkNode)]
+ FThenBranch: IAstNode;
+ [AstField(2, 'else', fkNullableNode)]
+ FElseBranch: IAstNode;
function GetCondition: IAstNode;
function GetThenBranch: IAstNode;
function GetElseBranch: IAstNode;
@@ -626,9 +648,12 @@ type
function AsIfExpression: IIfExpressionNode; override;
end;
+ [AstTag('Cond')]
TCondExpressionNode = class(TAstTypedNode, ICondExpressionNode)
private
+ [AstField(0, 'pairs', fkArrayOfPairs)]
FPairs: TArray;
+ [AstField(1, 'else', fkNullableNode)]
FElseBranch: IAstNode;
function GetPairs: TArray;
function GetElseBranch: IAstNode;
@@ -644,9 +669,12 @@ type
function AsCondExpression: ICondExpressionNode; override;
end;
+ [AstTag('Fn')]
TLambdaExpressionNode = class(TAstTypedNode, ILambdaExpressionNode, IFunctionDefinition)
private
+ [AstField(0, 'params', fkTuple)]
FParameters: ITupleNode;
+ [AstField(1, 'body', fkNode)]
FBody: IAstNode;
FLayout: IScopeLayout;
FDescriptor: IScopeDescriptor;
@@ -675,9 +703,12 @@ type
function AsLambdaExpression: ILambdaExpressionNode; override;
end;
+ [AstTag('Call')]
TFunctionCallNode = class(TAstTypedNode, IFunctionCallNode)
private
+ [AstField(0, 'callee', fkNode)]
FCallee: IAstNode;
+ [AstField(1, 'args', fkTuple)]
FArguments: ITupleNode;
FIsTailCall: Boolean;
FStaticTarget: TDataValue.TFunc;
@@ -702,10 +733,14 @@ type
function AsFunctionCall: IFunctionCallNode; override;
end;
+ [AstTag('Macro')]
TMacroDefinitionNode = class(TAstTypedNode, IMacroDefinitionNode)
private
+ [AstField(0, 'name', fkNode)]
FName: IIdentifierNode;
+ [AstField(1, 'params', fkTuple)]
FParameters: ITupleNode;
+ [AstField(2, 'body', fkNode)]
FBody: IAstNode;
function GetName: IIdentifierNode;
function GetParameters: ITupleNode;
@@ -735,8 +770,10 @@ type
function AsMacroExpansion: IMacroExpansionNode; override;
end;
+ [AstTag('Quote')]
TQuasiquoteNode = class(TAstNode, IQuasiquoteNode)
private
+ [AstField(0, 'expr', fkNode)]
FExpression: IAstNode;
function GetExpression: IAstNode;
protected
@@ -746,8 +783,10 @@ type
function AsQuasiquote: IQuasiquoteNode; override;
end;
+ [AstTag('Unquote')]
TUnquoteNode = class(TAstNode, IUnquoteNode)
private
+ [AstField(0, 'expr', fkNode)]
FExpression: IAstNode;
function GetExpression: IAstNode;
protected
@@ -757,8 +796,10 @@ type
function AsUnquote: IUnquoteNode; override;
end;
+ [AstTag('Splice')]
TUnquoteSplicingNode = class(TAstNode, IUnquoteSplicingNode)
private
+ [AstField(0, 'expr', fkNode)]
FExpression: IQuasiquoteNode;
function GetExpression: IQuasiquoteNode;
protected
@@ -768,8 +809,10 @@ type
function AsUnquoteSplicing: IUnquoteSplicingNode; override;
end;
+ [AstTag('Recur')]
TRecurNode = class(TAstTypedNode, IRecurNode)
private
+ [AstField(0, 'args', fkTuple)]
FArguments: ITupleNode;
function GetArguments: ITupleNode;
protected
@@ -779,8 +822,10 @@ type
function AsRecur: IRecurNode; override;
end;
+ [AstTag('Block')]
TBlockExpressionNode = class(TAstTypedNode, IBlockExpressionNode)
private
+ [AstField(0, 'expressions', fkTuple)]
FExpressions: ITupleNode;
function GetExpressions: ITupleNode;
protected
@@ -790,9 +835,13 @@ type
function AsBlockExpression: IBlockExpressionNode; override;
end;
+ [AstTag('Var')]
TVariableDeclarationNode = class(TAstTypedNode, IVariableDeclarationNode)
private
- FTarget, FInitializer: IAstNode;
+ [AstField(0, 'target', fkNode)]
+ FTarget: IAstNode;
+ [AstField(1, 'init', fkNullableNode)]
+ FInitializer: IAstNode;
FIsBoxed: Boolean;
function GetTarget: IAstNode;
function GetInitializer: IAstNode;
@@ -810,9 +859,13 @@ type
function AsVariableDeclaration: IVariableDeclarationNode; override;
end;
+ [AstTag('Assign')]
TAssignmentNode = class(TAstTypedNode, IAssignmentNode)
private
- FTarget, FValue: IAstNode;
+ [AstField(0, 'target', fkNode)]
+ FTarget: IAstNode;
+ [AstField(1, 'value', fkNode)]
+ FValue: IAstNode;
function GetTarget: IAstNode;
function GetValue: IAstNode;
protected
@@ -822,9 +875,13 @@ type
function AsAssignment: IAssignmentNode; override;
end;
+ [AstTag('Index')]
TIndexerNode = class(TAstTypedNode, IIndexerNode)
private
- FBase, FIndex: IAstNode;
+ [AstField(0, 'base', fkNode)]
+ FBase: IAstNode;
+ [AstField(1, 'index', fkNode)]
+ FIndex: IAstNode;
function GetBase: IAstNode;
function GetIndex: IAstNode;
protected
@@ -834,9 +891,12 @@ type
function AsIndexer: IIndexerNode; override;
end;
+ [AstTag('Member')]
TMemberAccessNode = class(TAstTypedNode, IMemberAccessNode)
private
+ [AstField(0, 'base', fkNode)]
FBase: IAstNode;
+ [AstField(1, 'member', fkNode)]
FMember: IKeywordNode;
function GetBase: IAstNode;
function GetMember: IKeywordNode;
@@ -852,8 +912,10 @@ type
function AsMemberAccess: IMemberAccessNode; override;
end;
+ [AstTag('Record')]
TRecordLiteralNode = class(TAstTypedNode, IRecordLiteralNode)
private
+ [AstField(0, 'fields', fkTuple)]
FFields: ITupleNode;
FScalarDef: IScalarRecordDefinition;
FGenericDef: IGenericRecordDefinition;
@@ -873,10 +935,15 @@ type
function AsRecordLiteral: IRecordLiteralNode; override;
end;
+ [AstTag('Add')]
TAddSeriesItemNode = class(TAstTypedNode, IAddSeriesItemNode)
private
+ [AstField(0, 'series', fkNode)]
FSeries: IIdentifierNode;
- FValue, FLookback: IAstNode;
+ [AstField(1, 'value', fkNode)]
+ FValue: IAstNode;
+ [AstField(2, 'lookback', fkNullableNode)]
+ FLookback: IAstNode;
function GetSeries: IIdentifierNode;
function GetValue: IAstNode;
function GetLookback: IAstNode;
@@ -892,8 +959,10 @@ type
function AsAddSeriesItem: IAddSeriesItemNode; override;
end;
+ [AstTag('Count')]
TSeriesLengthNode = class(TAstTypedNode, ISeriesLengthNode)
private
+ [AstField(0, 'series', fkNode)]
FSeries: IIdentifierNode;
function GetSeries: IIdentifierNode;
protected
@@ -903,6 +972,7 @@ type
function AsSeriesLength: ISeriesLengthNode; override;
end;
+ [AstTag('Nop')]
TNopNode = class(TAstTypedNode, INopNode)
protected
function GetKind: TAstNodeKind; override;
@@ -911,9 +981,12 @@ type
function AsNop: INopNode; override;
end;
+ [AstTag('Pipe')]
TPipeNode = class(TAstTypedNode, IPipeNode)
private
+ [AstField(0, 'inputs', fkTuple)]
FInputs: ITupleNode;
+ [AstField(1, 'transform', fkNode)]
FTransformation: ILambdaExpressionNode;
function GetInputs: ITupleNode;
function GetTransformation: ILambdaExpressionNode;
@@ -933,6 +1006,7 @@ implementation
uses
System.Classes,
+ System.TypInfo,
System.Rtti,
System.StrUtils;
@@ -949,7 +1023,7 @@ end;
function TAstNodeKindHelper.ToString: string;
begin
- Result := TRttiEnumerationType.GetName(Self);
+ Result := GetEnumName(TypeInfo(TAstNodeKind), Ord(Self));
Assert(StartsText('ak', Result));
Result := Result.Substring(2);
end;
@@ -2055,3 +2129,6 @@ begin
end;
end.
+ //==================================================================================================
+//== FULL UNIT END: Myc.Ast.Nodes
+//==================================================================================================