unit Myc.Ast.Json; interface uses System.SysUtils, System.Generics.Collections, System.JSON, Myc.Data.Scalar, Myc.Data.Value, Myc.Ast, Myc.Ast.Visitor, Myc.Ast.Nodes; type IJsonAstConverter = interface function Serialize(const RootNode: IAstNode): TJSONObject; function Deserialize(const AJson: TJSONObject): IAstNode; end; 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; // 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; 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; protected procedure SetupHandlers; override; public constructor Create; function Serialize(const RootNode: IAstNode): TJSONObject; function Deserialize(const AJson: TJSONObject): IAstNode; end; implementation uses Myc.Data.Keyword, Myc.Ast.Identities; { TJsonAstConverter } constructor TJsonAstConverter.Create; begin inherited; end; procedure TJsonAstConverter.SetupHandlers; begin Register(akConstant, VisitConstant); Register(akIdentifier, VisitIdentifier); Register(akKeyword, VisitKeyword); Register(akTuple, VisitTuple); Register(akRecordField, VisitRecordField); Register(akIfExpression, VisitIfExpression); Register(akCondExpression, VisitCondExpression); Register(akLambdaExpression, VisitLambdaExpression); Register(akFunctionCall, VisitFunctionCall); Register(akMacroExpansion, VisitMacroExpansionNode); Register(akBlockExpression, VisitBlockExpression); Register(akVariableDeclaration, VisitVariableDeclaration); Register(akAssignment, VisitAssignment); Register(akMacroDefinition, VisitMacroDefinition); Register(akQuasiquote, VisitQuasiquote); Register(akUnquote, VisitUnquote); Register(akUnquoteSplicing, VisitUnquoteSplicing); Register(akIndexer, VisitIndexer); Register(akMemberAccess, VisitMemberAccess); Register(akRecordLiteral, VisitRecordLiteral); Register(akCreateSeries, VisitCreateSeries); Register(akAddSeriesItem, VisitAddSeriesItem); Register(akSeriesLength, VisitSeriesLength); Register(akRecur, VisitRecurNode); Register(akNop, VisitNop); Register(akPipe, VisitPipe); end; function TJsonAstConverter.Serialize(const RootNode: IAstNode): TJSONObject; begin if not Assigned(RootNode) then exit(nil); Result := Visit(RootNode); end; function TJsonAstConverter.Deserialize(const AJson: TJSONObject): 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)); 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.Keyword: scalarObj.AddPair('Value', TJSONString.Create(TKeywordRegistry.GetName(AValue.AsScalar.Value.AsInt64))); end; valObj.AddPair('Value', scalarObj); end; vkText: valObj.AddPair('Value', TJSONString.Create(AValue.AsText)); vkVoid:; else raise ENotSupportedException.Create('Unsupported TDataValue kind for constant serialization.'); end; AParent.AddPair(AName, valObj); end; function TJsonAstConverter.VisitConstant(const Node: IAstNode): TJSONObject; begin Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Constant')); DataValueToJson(Node.AsConstant.Value, Result, 'Value'); 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; // Updated: Use Elements array directly 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; 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)); end; function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONObject; var M: IMacroExpansionNode; 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)); end; function TJsonAstConverter.VisitRecurNode(const Node: IAstNode): TJSONObject; begin Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Recur')); Result.AddPair('Arguments', Visit(Node.AsRecur.Arguments)); 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; var V: IVariableDeclarationNode; initObj: TJSONValue; begin V := Node.AsVariableDeclaration; if Assigned(V.Initializer) then initObj := 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); end; function TJsonAstConverter.VisitAssignment(const Node: IAstNode): TJSONObject; var A: IAssignmentNode; 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')); Result.AddPair('Definition', TJSONString.Create(Node.AsCreateSeries.Definition)); 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) 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); 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; var P: IPipeNode; 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 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; end else if SameText(kindStr, 'Text') then Result := valObj.GetValue('Value') else if SameText(kindStr, 'Void') then Result := TDataValue.Void else raise ENotSupportedException.Create('Unsupported TDataValue kind.'); end; function TJsonAstConverter.JsonToNode(const AJson: TJSONValue; const ExpectedType: string): IAstNode; 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 // Updated: Use Elements instead of ToArray (or iterate if ToArray is missing) 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 // Updated: Use Elements 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 // Updated: Use Elements 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; // Updated: Use Elements Result := TAst.MacroExpansionNode(TAst.FunctionCall(callee, argsTuple.Elements), expandedBody); end; function TJsonAstConverter.JsonToRecurNode(const AObj: TJSONObject): IRecurNode; begin // Updated: Use Elements Result := TAst.Recur(JsonToNode(AObj.GetValue('Arguments')).AsTuple.Elements); end; function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode; begin // Updated: Use Elements 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 Result := TAst.CreateSeries(AObj.GetValue('Definition')); 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])); Result := TAst.Tuple(elems.ToArray); finally elems.Free; end; end; function TJsonAstConverter.JsonToPipeNode(const AObj: TJSONObject): IPipeNode; begin Result := TAst.Pipe(JsonToNode(AObj.GetValue('Inputs')).AsTuple, JsonToNode(AObj.GetValue('Transformation')).AsLambdaExpression); end; end.