752 lines
25 KiB
ObjectPascal
752 lines
25 KiB
ObjectPascal
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<TJSONObject>;
|
|
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<TJSONObject>.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<TJSONObject>;
|
|
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<TJSONObject>;
|
|
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<TJSONObject>;
|
|
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<TJSONObject>(AName);
|
|
kindStr := scalarObj.GetValue<string>('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<string>('Name'));
|
|
end;
|
|
|
|
function TJsonAstConverter.JsonToBinaryExprNode(const AObj: TJSONObject): IBinaryExpressionNode;
|
|
var
|
|
opStr: string;
|
|
op: TBinaryOperator;
|
|
leftNode, rightNode: IAstNode;
|
|
begin
|
|
opStr := AObj.GetValue<string>('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<string>('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<IIdentifierNode>;
|
|
body: IAstNode;
|
|
paramArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
paramArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
argsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
callee := JsonToNode(AObj.GetValue('Callee'));
|
|
argsArray := AObj.GetValue<TJSONArray>('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<IAstNode>;
|
|
exprsArray: TJSONArray;
|
|
i: Integer;
|
|
begin
|
|
exprsArray := AObj.GetValue<TJSONArray>('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<string>('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<string>('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.
|