Files
MycLib/Src/AST/Myc.Ast.JSON.pas
T
2026-01-06 13:38:06 +01:00

785 lines
30 KiB
ObjectPascal

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<TJSONObject>, 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<IAstNode>;
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;
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'));
// 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)
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<TJSONObject>(AName);
kindStr := valObj.GetValue<string>('Kind');
if SameText(kindStr, 'Scalar') then
begin
scalarObj := valObj.GetValue<TJSONObject>('Value');
case TScalar.StringToKind(scalarObj.GetValue<string>('Kind')) of
TScalar.TKind.Ordinal: Result := TScalar.FromInt64(scalarObj.GetValue<TJSONNumber>('Value').AsInt64);
TScalar.TKind.Float: Result := TScalar.FromDouble(scalarObj.GetValue<TJSONNumber>('Value').AsDouble);
TScalar.TKind.Boolean: Result := TScalar.FromBoolean(scalarObj.GetValue<TJSONBool>('Value').AsBoolean);
TScalar.TKind.DateTime: Result := TScalar.FromDateTime(scalarObj.GetValue<TJSONNumber>('Value').AsDouble);
TScalar.TKind.Keyword: Result := TScalar.FromKeyword(TKeywordRegistry.Intern(scalarObj.GetValue<string>('Value')));
end;
end
else if SameText(kindStr, 'Text') then
Result := valObj.GetValue<string>('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<string>('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<string>('Name'));
end;
function TJsonAstConverter.JsonToKeywordNode(const AObj: TJSONObject): IKeywordNode;
begin
Result := TAst.Keyword(AObj.GetValue<string>('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<TCondPair>;
i: Integer;
elseNode: IAstNode;
begin
pairsArray := AObj.GetValue<TJSONArray>('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<IIdentifierNode>;
node: IAstNode;
begin
identNodes := TList<IIdentifierNode>.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<IIdentifierNode>;
node: IAstNode;
begin
identNodes := TList<IIdentifierNode>.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<IRecordFieldNode>;
i: Integer;
begin
fieldsArray := AObj.GetValue<TJSONArray>('Fields');
fields := TList<IRecordFieldNode>.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<string>('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<IAstNode>;
i: Integer;
begin
elemsArray := AObj.GetValue<TJSONArray>('Elements');
elems := TList<IAstNode>.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.