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 implements the visitor pattern for serialization // and uses factory functions for deserialization. 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; strict private // Serialization Visitors (IAstNode signature) function VisitConstant(const Node: IAstNode): TJSONObject; function VisitIdentifier(const Node: IAstNode): TJSONObject; function VisitKeyword(const Node: IAstNode): TJSONObject; function VisitParameterList(const Node: IAstNode): TJSONObject; function VisitArgumentList(const Node: IAstNode): TJSONObject; function VisitExpressionList(const Node: IAstNode): TJSONObject; function VisitRecordFieldList(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 VisitTuple(const Node: IAstNode): TJSONObject; function VisitPipeInput(const Node: IAstNode): TJSONObject; function VisitPipeSelectorList(const Node: IAstNode): TJSONObject; function VisitPipeInputList(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; { TJsonAstConverter } constructor TJsonAstConverter.Create; begin inherited; end; procedure TJsonAstConverter.SetupHandlers; begin Register(akConstant, VisitConstant); Register(akIdentifier, VisitIdentifier); Register(akKeyword, VisitKeyword); Register(akParameterList, VisitParameterList); Register(akArgumentList, VisitArgumentList); Register(akExpressionList, VisitExpressionList); Register(akRecordFieldList, VisitRecordFieldList); 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(akTuple, VisitTuple); Register(akPipeInput, VisitPipeInput); Register(akPipeSelectorList, VisitPipeSelectorList); Register(akPipeInputList, VisitPipeInputList); Register(akPipe, VisitPipe); end; function TJsonAstConverter.Serialize(const RootNode: IAstNode): TJSONObject; begin if not Assigned(RootNode) then begin exit(nil); end; Result := Visit(RootNode); end; function TJsonAstConverter.Deserialize(const AJson: TJSONObject): IAstNode; begin Result := JsonToNode(AJson); end; { Serialization Visitors } 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.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 begin elseObj := Visit(E.ElseBranch); end else begin elseObj := TJSONNull.Create; end; 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 begin elseObj := Visit(E.ElseBranch); end else begin elseObj := TJSONNull.Create; end; 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; paramsArray: TJSONArray; i: Integer; begin L := Node.AsLambdaExpression; paramsArray := TJSONArray.Create; for i := 0 to L.Parameters.Count - 1 do begin paramsArray.Add(Visit(L.Parameters[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('LambdaExpr')); Result.AddPair('Parameters', paramsArray); Result.AddPair('Body', Visit(L.Body)); end; function TJsonAstConverter.VisitMacroDefinition(const Node: IAstNode): TJSONObject; var M: IMacroDefinitionNode; paramsArray: TJSONArray; i: Integer; begin M := Node.AsMacroDefinition; paramsArray := TJSONArray.Create; for i := 0 to M.Parameters.Count - 1 do begin paramsArray.Add(Visit(M.Parameters[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('MacroDef')); Result.AddPair('Name', Visit(M.Name)); Result.AddPair('Parameters', paramsArray); 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; argsArray: TJSONArray; i: Integer; begin C := Node.AsFunctionCall; argsArray := TJSONArray.Create; for i := 0 to C.Arguments.Count - 1 do begin argsArray.Add(Visit(C.Arguments[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('FunctionCall')); Result.AddPair('Callee', Visit(C.Callee)); Result.AddPair('Arguments', argsArray); end; function TJsonAstConverter.VisitMacroExpansionNode(const Node: IAstNode): TJSONObject; var M: IMacroExpansionNode; argsArray: TJSONArray; i: Integer; begin M := Node.AsMacroExpansion; argsArray := TJSONArray.Create; for i := 0 to M.CallNode.Arguments.Count - 1 do begin argsArray.Add(Visit(M.CallNode.Arguments[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('MacroExpansion')); Result.AddPair('Callee', Visit(M.CallNode.Callee)); Result.AddPair('Arguments', argsArray); Result.AddPair('ExpandedBody', Visit(M.ExpandedBody)); end; function TJsonAstConverter.VisitRecurNode(const Node: IAstNode): TJSONObject; var R: IRecurNode; argsArray: TJSONArray; i: Integer; begin R := Node.AsRecur; argsArray := TJSONArray.Create; for i := 0 to R.Arguments.Count - 1 do begin argsArray.Add(Visit(R.Arguments[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Recur')); Result.AddPair('Arguments', argsArray); end; function TJsonAstConverter.VisitBlockExpression(const Node: IAstNode): TJSONObject; var B: IBlockExpressionNode; exprsArray: TJSONArray; i: Integer; begin B := Node.AsBlockExpression; exprsArray := TJSONArray.Create; for i := 0 to B.Expressions.Count - 1 do begin exprsArray.Add(Visit(B.Expressions[i])); end; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Block')); Result.AddPair('Expressions', exprsArray); end; function TJsonAstConverter.VisitVariableDeclaration(const Node: IAstNode): TJSONObject; var V: IVariableDeclarationNode; initObj: TJSONValue; begin V := Node.AsVariableDeclaration; if Assigned(V.Initializer) then begin initObj := Visit(V.Initializer); end else begin initObj := TJSONNull.Create; end; 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; var R: IRecordLiteralNode; fieldsArray: TJSONArray; i: Integer; begin R := Node.AsRecordLiteral; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('RecordLiteral')); fieldsArray := TJSONArray.Create; for i := 0 to R.Fields.Count - 1 do begin fieldsArray.Add(Visit(R.Fields[i])); end; Result.AddPair('Fields', fieldsArray); 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 begin lookbackObj := Visit(A.Lookback); end else begin lookbackObj := TJSONNull.Create; end; 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.VisitTuple(const Node: IAstNode): TJSONObject; var T: ITupleNode; elemsArray: TJSONArray; i: Integer; begin T := Node.AsTuple; Result := TJSONObject.Create; Result.AddPair('NodeType', TJSONString.Create('Tuple')); elemsArray := TJSONArray.Create; for i := 0 to High(T.Elements) do begin elemsArray.Add(Visit(T.Elements[i])); end; Result.AddPair('Elements', elemsArray); end; function TJsonAstConverter.VisitParameterList(const Node: IAstNode): TJSONObject; begin Result := nil; end; function TJsonAstConverter.VisitArgumentList(const Node: IAstNode): TJSONObject; begin Result := nil; end; function TJsonAstConverter.VisitExpressionList(const Node: IAstNode): TJSONObject; begin Result := nil; end; function TJsonAstConverter.VisitRecordFieldList(const Node: IAstNode): TJSONObject; begin Result := nil; end; function TJsonAstConverter.JsonToTupleNode(const AObj: TJSONObject): ITupleNode; var elems: TArray; elemsArray: TJSONArray; i: Integer; begin elemsArray := AObj.GetValue('Elements'); SetLength(elems, elemsArray.Count); for i := 0 to elemsArray.Count - 1 do begin elems[i] := JsonToNode(elemsArray.Items[i]); end; Result := TAst.Tuple(elems); // Factory handles identity/type defaults end; function TJsonAstConverter.VisitPipeInput(const Node: IAstNode): TJSONObject; begin raise ENotSupportedException.Create('JSON Pipe Serialization not implemented.'); end; function TJsonAstConverter.VisitPipeSelectorList(const Node: IAstNode): TJSONObject; begin raise ENotSupportedException.Create('JSON Pipe Serialization not implemented.'); end; function TJsonAstConverter.VisitPipeInputList(const Node: IAstNode): TJSONObject; begin raise ENotSupportedException.Create('JSON Pipe Serialization not implemented.'); end; function TJsonAstConverter.VisitPipe(const Node: IAstNode): TJSONObject; begin raise ENotSupportedException.Create('JSON Pipe Serialization not implemented.'); 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 begin Result := valObj.GetValue('Value'); end else if SameText(kindStr, 'Void') then begin Result := TDataValue.Void; end else begin raise ENotSupportedException.Create('Unsupported TDataValue kind.'); end; end; function TJsonAstConverter.JsonToNode(const AJson: TJSONValue; const ExpectedType: string): IAstNode; var obj: TJSONObject; nodeType: string; begin if not (AJson is TJSONObject) then begin raise EInvalidCast.Create('Expected JSON object.'); end; 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 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 begin elseNode := nil; end else begin elseNode := JsonToNode(AObj.GetValue('ElseBranch')); end; 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 begin pairs[i] := TCondPair.Create( JsonToNode((pairsArray.Items[i] as TJSONObject).GetValue('Condition')), JsonToNode((pairsArray.Items[i] as TJSONObject).GetValue('Branch')) ); end; if AObj.GetValue('ElseBranch') is TJSONNull then begin elseNode := nil; end else begin elseNode := JsonToNode(AObj.GetValue('ElseBranch')); end; 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 params: TArray; paramArray: TJSONArray; i: Integer; begin paramArray := AObj.GetValue('Parameters'); SetLength(params, paramArray.Count); for i := 0 to paramArray.Count - 1 do begin params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); end; Result := TAst.LambdaExpr(params, JsonToNode(AObj.GetValue('Body'))); end; function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDefinitionNode; var params: TArray; paramArray: TJSONArray; i: Integer; begin paramArray := AObj.GetValue('Parameters'); SetLength(params, paramArray.Count); for i := 0 to paramArray.Count - 1 do begin params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); end; Result := TAst.MacroDef(JsonToIdentifierNode(AObj.GetValue('Name') as TJSONObject), params, JsonToNode(AObj.GetValue('Body'))); 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; var args: TArray; argsArray: TJSONArray; i: Integer; begin argsArray := AObj.GetValue('Arguments'); SetLength(args, argsArray.Count); for i := 0 to argsArray.Count - 1 do begin args[i] := JsonToNode(argsArray.Items[i]); end; Result := TAst.FunctionCall(JsonToNode(AObj.GetValue('Callee')), args); end; function TJsonAstConverter.JsonToMacroExpansionNode(const AObj: TJSONObject): IMacroExpansionNode; var callee, expandedBody: IAstNode; args: TArray; argsArray: TJSONArray; i: Integer; tempCallNode: IFunctionCallNode; begin callee := JsonToNode(AObj.GetValue('Callee')); expandedBody := JsonToNode(AObj.GetValue('ExpandedBody')); argsArray := AObj.GetValue('Arguments'); SetLength(args, argsArray.Count); for i := 0 to argsArray.Count - 1 do begin args[i] := JsonToNode(argsArray.Items[i]); end; tempCallNode := TAst.FunctionCall(callee, args); Result := TAst.MacroExpansionNode(tempCallNode, expandedBody); end; function TJsonAstConverter.JsonToRecurNode(const AObj: TJSONObject): IRecurNode; var args: TArray; argsArray: TJSONArray; i: Integer; begin argsArray := AObj.GetValue('Arguments'); SetLength(args, argsArray.Count); for i := 0 to argsArray.Count - 1 do begin args[i] := JsonToNode(argsArray.Items[i]); end; Result := TAst.Recur(args); end; function TJsonAstConverter.JsonToBlockNode(const AObj: TJSONObject): IBlockExpressionNode; var exprs: TArray; exprsArray: TJSONArray; i: Integer; begin exprsArray := AObj.GetValue('Expressions'); SetLength(exprs, exprsArray.Count); for i := 0 to exprsArray.Count - 1 do begin exprs[i] := JsonToNode(exprsArray.Items[i]); end; Result := TAst.Block(exprs); end; function TJsonAstConverter.JsonToVarDeclNode(const AObj: TJSONObject): IVariableDeclarationNode; var initNode: IAstNode; begin if AObj.GetValue('Initializer') is TJSONNull then begin initNode := nil; end else begin initNode := JsonToNode(AObj.GetValue('Initializer')); end; 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)); end; function TJsonAstConverter.JsonToRecordLiteralNode(const AObj: TJSONObject): IRecordLiteralNode; var fields: TArray; fieldsArray: TJSONArray; i: Integer; begin fieldsArray := AObj.GetValue('Fields'); SetLength(fields, fieldsArray.Count); for i := 0 to fieldsArray.Count - 1 do begin fields[i] := TAst.RecordField( TAst.Keyword((fieldsArray.Items[i] as TJSONObject).GetValue('Name')), JsonToNode((fieldsArray.Items[i] as TJSONObject).GetValue('Value')) ); end; Result := TAst.RecordLiteral(fields); 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 begin lookNode := nil; end else begin lookNode := JsonToNode(AObj.GetValue('Lookback')); end; 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; end.