unit Myc.Ast.Json; interface uses System.SysUtils, Myc.Ast.Nodes; type // TAstJson provides static methods for serializing and deserializing an AST to/from JSON. TAstJson = record public class function Serialize(const ANode: IAstNode): string; static; class function Deserialize(const AJson: string): IAstNode; static; end; implementation uses System.JSON, System.Generics.Collections, Myc.Ast, Myc.Data.Scalar, Myc.Data.Value; // Added for TDataValue type // TJsonAstConverter implements the visitor pattern for serialization // and uses factory functions for deserialization. TJsonAstConverter = class(TInterfacedObject, IAstVisitor) private FJsonObjectStack: TStack; procedure ScalarToJson(const AScalar: TScalar; const AParent: TJSONObject; const AName: string); function JsonToNode(const AJson: TJSONValue): IAstNode; function JsonToScalar(const AObj: TJSONObject; const AName: string): TScalar; // Updated signatures to return specific node interface types function JsonToConstantNode(const AObj: TJSONObject): IConstantNode; function JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode; function JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode; function JsonToUnaryExprNode(const AObj: TJSONObject): IUnaryExpressionNode; function JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode; function JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode; function JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode; function JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode; 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 JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode; function JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode; function JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode; protected // IAstVisitor implementation for serialization function VisitConstant(const Node: IConstantNode): TDataValue; function VisitIdentifier(const Node: IIdentifierNode): TDataValue; function VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; function VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; function VisitIfExpression(const Node: IIfExpressionNode): TDataValue; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; function VisitAssignment(const Node: IAssignmentNode): TDataValue; function VisitIndexer(const Node: IIndexerNode): TDataValue; function VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; function VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; function VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; public constructor Create; destructor Destroy; override; function Execute(const RootNode: IAstNode): TDataValue; function Serialize(const ANode: IAstNode): string; function Deserialize(const AJson: string): IAstNode; end; { TJsonAstConverter } constructor TJsonAstConverter.Create; begin inherited; FJsonObjectStack := TStack.Create; end; destructor TJsonAstConverter.Destroy; begin FJsonObjectStack.Free; inherited; end; function TJsonAstConverter.Serialize(const ANode: IAstNode): string; var rootObj: TJSONObject; begin if not Assigned(ANode) then exit(''); FJsonObjectStack.Clear; ANode.Accept(Self); if FJsonObjectStack.Count <> 1 then raise EInvalidOpException.Create('JSON serialization stack is corrupt.'); rootObj := FJsonObjectStack.Pop; try Result := rootObj.Format(4); finally rootObj.Free; end; end; function TJsonAstConverter.Deserialize(const AJson: string): IAstNode; var jsonValue: TJSONValue; begin if AJson.IsEmpty then exit(nil); jsonValue := TJSONObject.ParseJSONValue(AJson); if jsonValue = nil then raise EJSONParseException.Create('Invalid JSON format.'); try Result := JsonToNode(jsonValue); finally jsonValue.Free; end; end; function TJsonAstConverter.Execute(const RootNode: IAstNode): TDataValue; begin Result := RootNode.Accept(Self); end; { TJsonAstConverter - IAstVisitor for Serialization } procedure TJsonAstConverter.ScalarToJson(const AScalar: TScalar; const AParent: TJSONObject; const AName: string); var scalarObj: TJSONObject; begin scalarObj := TJSONObject.Create; scalarObj.AddPair('Kind', TJSONString.Create(AScalar.Kind.ToString)); case AScalar.Kind of skInt64: scalarObj.AddPair('Value', TJSONNumber.Create(AScalar.Value.AsInt64)); skDouble: scalarObj.AddPair('Value', TJSONNumber.Create(AScalar.Value.AsDouble)); skBoolean: scalarObj.AddPair('Value', TJSONBool.Create(AScalar.Value.AsBoolean)); skString: scalarObj.AddPair('Value', TJSONString.Create(AScalar.Value.AsString)); else raise ENotSupportedException.CreateFmt('Scalar kind %s not supported for JSON serialization.', [AScalar.Kind.ToString]); end; AParent.AddPair(AName, scalarObj); end; function TJsonAstConverter.VisitConstant(const Node: IConstantNode): TDataValue; var obj: TJSONObject; begin obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('Constant')); ScalarToJson(Node.Value, obj, 'Value'); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitIdentifier(const Node: IIdentifierNode): TDataValue; var obj: TJSONObject; begin obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('Identifier')); obj.AddPair('Name', TJSONString.Create(Node.Name)); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitBinaryExpression(const Node: IBinaryExpressionNode): TDataValue; var obj, leftObj, rightObj: TJSONObject; begin Node.Left.Accept(Self); Node.Right.Accept(Self); rightObj := FJsonObjectStack.Pop; leftObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('BinaryExpr')); obj.AddPair('Operator', TJSONString.Create(Node.Operator.ToString)); obj.AddPair('Left', leftObj); obj.AddPair('Right', rightObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitUnaryExpression(const Node: IUnaryExpressionNode): TDataValue; var obj, rightObj: TJSONObject; begin Node.Right.Accept(Self); rightObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('UnaryExpr')); obj.AddPair('Operator', TJSONString.Create(Node.Operator.ToString)); obj.AddPair('Right', rightObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitIfExpression(const Node: IIfExpressionNode): TDataValue; var obj, condObj, thenObj, elseObj: TJSONObject; begin Node.Condition.Accept(Self); Node.ThenBranch.Accept(Self); if Assigned(Node.ElseBranch) then Node.ElseBranch.Accept(Self); if Assigned(Node.ElseBranch) then elseObj := FJsonObjectStack.Pop else elseObj := nil; thenObj := FJsonObjectStack.Pop; condObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('IfExpr')); obj.AddPair('Condition', condObj); obj.AddPair('ThenBranch', thenObj); if Assigned(elseObj) then obj.AddPair('ElseBranch', elseObj) else obj.AddPair('ElseBranch', TJSONNull.Create); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue; var obj, condObj, thenObj, elseObj: TJSONObject; begin Node.Condition.Accept(Self); Node.ThenBranch.Accept(Self); Node.ElseBranch.Accept(Self); elseObj := FJsonObjectStack.Pop; thenObj := FJsonObjectStack.Pop; condObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('TernaryExpr')); obj.AddPair('Condition', condObj); obj.AddPair('ThenBranch', thenObj); obj.AddPair('ElseBranch', elseObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue; var obj, bodyObj: TJSONObject; paramsArray: TJSONArray; tempParams: TArray; param: IIdentifierNode; i: Integer; begin for param in Node.Parameters do param.Accept(Self); Node.Body.Accept(Self); bodyObj := FJsonObjectStack.Pop; SetLength(tempParams, Length(Node.Parameters)); for i := High(tempParams) downto 0 do tempParams[i] := FJsonObjectStack.Pop; paramsArray := TJSONArray.Create; for i := 0 to High(tempParams) do paramsArray.Add(tempParams[i]); obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('LambdaExpr')); obj.AddPair('Parameters', paramsArray); obj.AddPair('Body', bodyObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; var obj, calleeObj: TJSONObject; argsArray: TJSONArray; tempArgs: TArray; arg: IAstNode; i: Integer; begin Node.Callee.Accept(Self); for arg in Node.Arguments do arg.Accept(Self); SetLength(tempArgs, Length(Node.Arguments)); for i := High(tempArgs) downto 0 do tempArgs[i] := FJsonObjectStack.Pop; argsArray := TJSONArray.Create; for i := 0 to High(tempArgs) do argsArray.Add(tempArgs[i]); calleeObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('FunctionCall')); obj.AddPair('Callee', calleeObj); obj.AddPair('Arguments', argsArray); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; var obj: TJSONObject; exprsArray: TJSONArray; tempExprs: TArray; expr: IAstNode; i: Integer; begin for expr in Node.Expressions do expr.Accept(Self); SetLength(tempExprs, Node.Expressions.Count); for i := High(tempExprs) downto 0 do tempExprs[i] := FJsonObjectStack.Pop; exprsArray := TJSONArray.Create; for i := 0 to High(tempExprs) do exprsArray.Add(tempExprs[i]); obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('Block')); obj.AddPair('Expressions', exprsArray); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; var obj, identObj, initObj: TJSONObject; begin Node.Identifier.Accept(Self); if Assigned(Node.Initializer) then Node.Initializer.Accept(Self); if Assigned(Node.Initializer) then initObj := FJsonObjectStack.Pop else initObj := nil; identObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('VarDecl')); obj.AddPair('Identifier', identObj); if Assigned(initObj) then obj.AddPair('Initializer', initObj) else obj.AddPair('Initializer', TJSONNull.Create); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitAssignment(const Node: IAssignmentNode): TDataValue; var obj, identObj, valueObj: TJSONObject; begin Node.Identifier.Accept(Self); Node.Value.Accept(Self); valueObj := FJsonObjectStack.Pop; identObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('Assignment')); obj.AddPair('Identifier', identObj); obj.AddPair('Value', valueObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitIndexer(const Node: IIndexerNode): TDataValue; var obj, baseObj, indexObj: TJSONObject; begin Node.Base.Accept(Self); Node.Index.Accept(Self); indexObj := FJsonObjectStack.Pop; baseObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('Indexer')); obj.AddPair('Base', baseObj); obj.AddPair('Index', indexObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitMemberAccess(const Node: IMemberAccessNode): TDataValue; var obj, baseObj, memberObj: TJSONObject; begin Node.Base.Accept(Self); Node.Member.Accept(Self); memberObj := FJsonObjectStack.Pop; baseObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('MemberAccess')); obj.AddPair('Base', baseObj); obj.AddPair('Member', memberObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitCreateSeries(const Node: ICreateSeriesNode): TDataValue; var obj: TJSONObject; begin obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('CreateSeries')); obj.AddPair('Definition', TJSONString.Create(Node.Definition)); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitAddSeriesItem(const Node: IAddSeriesItemNode): TDataValue; var obj, seriesObj, valueObj, lookbackObj: TJSONObject; begin Node.Series.Accept(Self); Node.Value.Accept(Self); if Assigned(Node.Lookback) then Node.Lookback.Accept(Self); if Assigned(Node.Lookback) then lookbackObj := FJsonObjectStack.Pop else lookbackObj := nil; valueObj := FJsonObjectStack.Pop; seriesObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('AddSeriesItem')); obj.AddPair('Series', seriesObj); obj.AddPair('Value', valueObj); if Assigned(lookbackObj) then obj.AddPair('Lookback', lookbackObj) else obj.AddPair('Lookback', TJSONNull.Create); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; function TJsonAstConverter.VisitSeriesLength(const Node: ISeriesLengthNode): TDataValue; var obj, seriesObj: TJSONObject; begin Node.Series.Accept(Self); seriesObj := FJsonObjectStack.Pop; obj := TJSONObject.Create; obj.AddPair('NodeType', TJSONString.Create('SeriesLength')); obj.AddPair('Series', seriesObj); FJsonObjectStack.Push(obj); Result := TDataValue.Void; end; { TJsonAstConverter - Deserialization } function TJsonAstConverter.JsonToScalar(const AObj: TJSONObject; const AName: string): TScalar; var scalarObj: TJSONObject; kindStr: string; scalarKind: TScalarKind; jsonValue: TJSONValue; begin scalarObj := AObj.GetValue(AName); kindStr := scalarObj.GetValue('Kind'); scalarKind := TScalar.StringToKind(kindStr); jsonValue := scalarObj.GetValue('Value'); case scalarKind of skInt64: Result := TScalar.FromInt64((jsonValue as TJSONNumber).AsInt64); skDouble: Result := TScalar.FromDouble((jsonValue as TJSONNumber).AsDouble); skBoolean: Result := TScalar.FromBoolean((jsonValue as TJSONBool).AsBoolean); skString: Result := TScalar.FromString((jsonValue as TJSONString).Value); else raise ENotSupportedException.CreateFmt('Scalar kind %s not supported for JSON deserialization.', [kindStr]); end; end; function TJsonAstConverter.JsonToConstantNode(const AObj: TJSONObject): IConstantNode; begin Result := TAst.Constant(JsonToScalar(AObj, 'Value')); end; function TJsonAstConverter.JsonToIdentifierNode(const AObj: TJSONObject): IIdentifierNode; begin Result := TAst.Identifier(AObj.GetValue('Name')); end; function TJsonAstConverter.JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode; var opStr: string; op: TBinaryOperator; leftNode, rightNode: IAstNode; begin opStr := AObj.GetValue('Operator'); for op := Low(TBinaryOperator) to High(TBinaryOperator) do if SameText(op.ToString, opStr) then begin leftNode := JsonToNode(AObj.GetValue('Left')); rightNode := JsonToNode(AObj.GetValue('Right')); Result := TAst.BinaryExpr(leftNode, op, rightNode); exit; end; raise EInvalidOpException.CreateFmt('Unknown binary operator "%s"', [opStr]); end; function TJsonAstConverter.JsonToUnaryExprNode(const AObj: TJSONObject): IUnaryExpressionNode; var opStr: string; op: TUnaryOperator; rightNode: IAstNode; begin opStr := AObj.GetValue('Operator'); for op := Low(TUnaryOperator) to High(TUnaryOperator) do if SameText(op.ToString, opStr) then begin rightNode := JsonToNode(AObj.GetValue('Right')); Result := TAst.UnaryExpr(op, rightNode); exit; end; raise EInvalidOpException.CreateFmt('Unknown unary operator "%s"', [opStr]); end; function TJsonAstConverter.JsonToIfExprNode(const AObj: TJSONObject): IIfExpressionNode; var condNode, thenNode, elseNode: IAstNode; begin condNode := JsonToNode(AObj.GetValue('Condition')); thenNode := JsonToNode(AObj.GetValue('ThenBranch')); if not (AObj.GetValue('ElseBranch') is TJSONNull) then elseNode := JsonToNode(AObj.GetValue('ElseBranch')) else elseNode := nil; Result := TAst.IfExpr(condNode, thenNode, elseNode); end; function TJsonAstConverter.JsonToTernaryExprNode(const AObj: TJSONObject): ITernaryExpressionNode; var condNode, thenNode, elseNode: IAstNode; begin condNode := JsonToNode(AObj.GetValue('Condition')); thenNode := JsonToNode(AObj.GetValue('ThenBranch')); elseNode := JsonToNode(AObj.GetValue('ElseBranch')); Result := TAst.TernaryExpr(condNode, thenNode, elseNode); end; function TJsonAstConverter.JsonToLambdaExprNode(const AObj: TJSONObject): ILambdaExpressionNode; var params: TArray; body: IAstNode; paramArray: TJSONArray; i: Integer; begin paramArray := AObj.GetValue('Parameters'); SetLength(params, paramArray.Count); for i := 0 to paramArray.Count - 1 do params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); body := JsonToNode(AObj.GetValue('Body')); Result := TAst.LambdaExpr(params, body); end; function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode; var callee: IAstNode; args: TArray; argsArray: TJSONArray; i: Integer; begin callee := JsonToNode(AObj.GetValue('Callee')); argsArray := AObj.GetValue('Arguments'); SetLength(args, argsArray.Count); for i := 0 to argsArray.Count - 1 do args[i] := JsonToNode(argsArray.Items[i]); Result := TAst.FunctionCall(callee, args); end; function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode; var expressions: TArray; exprsArray: TJSONArray; i: Integer; begin exprsArray := AObj.GetValue('Expressions'); SetLength(expressions, exprsArray.Count); for i := 0 to exprsArray.Count - 1 do expressions[i] := JsonToNode(exprsArray.Items[i]); Result := TAst.Block(expressions); end; function TJsonAstConverter.JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode; var ident: IIdentifierNode; initializer: IAstNode; begin ident := JsonToIdentifierNode(AObj.GetValue('Identifier') as TJSONObject); if not (AObj.GetValue('Initializer') is TJSONNull) then initializer := JsonToNode(AObj.GetValue('Initializer')) else initializer := nil; Result := TAst.VarDecl(ident, initializer); end; function TJsonAstConverter.JsonToAssignmentNode(const AObj: TJSONObject): IAssignmentNode; var ident: IIdentifierNode; value: IAstNode; begin ident := JsonToIdentifierNode(AObj.GetValue('Identifier') as TJSONObject); value := JsonToNode(AObj.GetValue('Value')); Result := TAst.Assign(ident, 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')), JsonToIdentifierNode(AObj.GetValue('Member') as TJSONObject)); end; function TJsonAstConverter.JsonToCreateSeriesNode(const AObj: TJSONObject): ICreateSeriesNode; begin Result := TAst.CreateSeries(AObj.GetValue('Definition')); end; function TJsonAstConverter.JsonToAddSeriesItemNode(const AObj: TJSONObject): IAddSeriesItemNode; var lookbackNode: IAstNode; begin if not (AObj.GetValue('Lookback') is TJSONNull) then lookbackNode := JsonToNode(AObj.GetValue('Lookback')) else lookbackNode := nil; Result := TAst.AddSeriesItem(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject), JsonToNode(AObj.GetValue('Value')), lookbackNode); end; function TJsonAstConverter.JsonToSeriesLengthNode(const AObj: TJSONObject): ISeriesLengthNode; begin Result := TAst.SeriesLength(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject)); end; function TJsonAstConverter.JsonToNode(const AJson: TJSONValue): IAstNode; var obj: TJSONObject; nodeType: string; begin if not (AJson is TJSONObject) then raise EInvalidCast.Create('Expected a JSON object for node deserialization.'); 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 = 'BinaryExpr' then Result := JsonToBinaryExprNode(obj) else if nodeType = 'UnaryExpr' then Result := JsonToUnaryExprNode(obj) else if nodeType = 'IfExpr' then Result := JsonToIfExprNode(obj) else if nodeType = 'TernaryExpr' then Result := JsonToTernaryExprNode(obj) else if nodeType = 'LambdaExpr' then Result := JsonToLambdaExprNode(obj) else if nodeType = 'FunctionCall' then Result := JsonToFunctionCallNode(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 = 'CreateSeries' then Result := JsonToCreateSeriesNode(obj) else if nodeType = 'AddSeriesItem' then Result := JsonToAddSeriesItemNode(obj) else if nodeType = 'SeriesLength' then Result := JsonToSeriesLengthNode(obj) else raise ENotSupportedException.CreateFmt('Unsupported NodeType "%s" for JSON deserialization.', [nodeType]); end; { TAstJson } class function TAstJson.Deserialize(const AJson: string): IAstNode; var converter: TJsonAstConverter; begin converter := TJsonAstConverter.Create; try Result := converter.Deserialize(AJson); finally converter.Free; end; end; class function TAstJson.Serialize(const ANode: IAstNode): string; var converter: TJsonAstConverter; begin converter := TJsonAstConverter.Create; try Result := converter.Serialize(ANode); finally converter.Free; end; end; end.