932 lines
32 KiB
ObjectPascal
932 lines
32 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 implements the visitor pattern for serialization
|
|
// and uses factory functions for deserialization.
|
|
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;
|
|
|
|
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 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(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.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.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<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
|
|
begin
|
|
Result := valObj.GetValue<string>('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<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
|
|
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
|
|
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<TCondPair>;
|
|
i: Integer;
|
|
elseNode: IAstNode;
|
|
begin
|
|
pairsArray := AObj.GetValue<TJSONArray>('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<IIdentifierNode>;
|
|
paramArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
paramArray := AObj.GetValue<TJSONArray>('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<IIdentifierNode>;
|
|
paramArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
paramArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
argsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
argsArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
argsArray: TJSONArray;
|
|
i: Integer;
|
|
tempCallNode: IFunctionCallNode;
|
|
begin
|
|
callee := JsonToNode(AObj.GetValue('Callee'));
|
|
expandedBody := JsonToNode(AObj.GetValue('ExpandedBody'));
|
|
argsArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
argsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
argsArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
exprsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
exprsArray := AObj.GetValue<TJSONArray>('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<IRecordFieldNode>;
|
|
fieldsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
fieldsArray := AObj.GetValue<TJSONArray>('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<string>('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<string>('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.
|