Macro expander integrated in binder

This commit is contained in:
Michael Schimmel
2025-10-04 22:41:01 +02:00
parent 7c48e9e203
commit 54bf350c70
12 changed files with 480 additions and 73 deletions
+102 -36
View File
@@ -39,6 +39,7 @@ type
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;
@@ -62,6 +63,7 @@ type
function VisitUnquote(const Node: IUnquoteNode): TDataValue; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue; override;
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue; override;
function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue; override;
function VisitRecurNode(const Node: IRecurNode): TDataValue; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue; override;
@@ -301,19 +303,46 @@ begin
Result := TDataValue.Void;
end;
function TJsonAstConverter.JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
function TJsonAstConverter.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Result := TAst.Quasiquote(JsonToNode(AObj.GetValue('Expression')));
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Quasiquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
function TJsonAstConverter.VisitUnquote(const Node: IUnquoteNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Result := TAst.Unquote(JsonToNode(AObj.GetValue('Expression')));
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Unquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
function TJsonAstConverter.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
var
obj, exprObj: TJSONObject;
begin
Result := TAst.UnquoteSplicing(JsonToNode(AObj.GetValue('Expression')));
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('UnquoteSplicing'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
@@ -346,6 +375,45 @@ begin
Result := TDataValue.Void;
end;
function TJsonAstConverter.VisitMacroExpansionNode(const Node: IMacroExpansionNode): TDataValue;
var
obj, calleeObj, bodyObj: TJSONObject;
argsArray: TJSONArray;
tempArgs: TArray<TJSONObject>;
arg: IAstNode;
i: Integer;
begin
// Serialize all children first: Callee, Arguments, and the new ExpandedBody
Node.Callee.Accept(Self);
for arg in Node.Arguments do
arg.Accept(Self);
Node.ExpandedBody.Accept(Self);
// Pop children's JSON from stack in reverse order of visitation
bodyObj := FJsonObjectStack.Pop;
SetLength(tempArgs, Length(Node.Arguments));
for i := High(tempArgs) downto 0 do
tempArgs[i] := FJsonObjectStack.Pop;
calleeObj := FJsonObjectStack.Pop;
// Build JSON array for arguments
argsArray := TJSONArray.Create;
for var argObj in tempArgs do
argsArray.Add(argObj);
// Create the final JSON object for this node
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('MacroExpansion'));
obj.AddPair('Callee', calleeObj);
obj.AddPair('Arguments', argsArray);
obj.AddPair('ExpandedBody', bodyObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
end;
function TJsonAstConverter.VisitRecurNode(const Node: IRecurNode): TDataValue;
var
obj: TJSONObject;
@@ -667,46 +735,42 @@ begin
Result := TAst.MacroDef(name, params, body);
end;
function TJsonAstConverter.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
function TJsonAstConverter.JsonToMacroExpansionNode(const AObj: TJSONObject): IMacroExpansionNode;
var
obj, exprObj: TJSONObject;
callee, expandedBody: IAstNode;
args: TArray<IAstNode>;
argsArray: TJSONArray;
i: Integer;
tempCallNode: IFunctionCallNode;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
// Recursively deserialize all parts of the macro expansion node
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
args[i] := JsonToNode(argsArray.Items[i]);
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Quasiquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
// Create a temporary IFunctionCallNode to pass to the factory
tempCallNode := TAst.FunctionCall(callee, args);
// Use the new global factory function from the TAst record
Result := TAst.MacroExpansionNode(tempCallNode, expandedBody);
end;
function TJsonAstConverter.VisitUnquote(const Node: IUnquoteNode): TDataValue;
var
obj, exprObj: TJSONObject;
function TJsonAstConverter.JsonToQuasiquoteNode(const AObj: TJSONObject): IQuasiquoteNode;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('Unquote'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
Result := TAst.Quasiquote(JsonToNode(AObj.GetValue('Expression')));
end;
function TJsonAstConverter.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
var
obj, exprObj: TJSONObject;
function TJsonAstConverter.JsonToUnquoteNode(const AObj: TJSONObject): IUnquoteNode;
begin
Node.Expression.Accept(Self);
exprObj := FJsonObjectStack.Pop;
Result := TAst.Unquote(JsonToNode(AObj.GetValue('Expression')));
end;
obj := TJSONObject.Create;
obj.AddPair('NodeType', TJSONString.Create('UnquoteSplicing'));
obj.AddPair('Expression', exprObj);
FJsonObjectStack.Push(obj);
Result := TDataValue.Void;
function TJsonAstConverter.JsonToUnquoteSplicingNode(const AObj: TJSONObject): IUnquoteSplicingNode;
begin
Result := TAst.UnquoteSplicing(JsonToNode(AObj.GetValue('Expression')));
end;
function TJsonAstConverter.JsonToFunctionCallNode(const AObj: TJSONObject): IFunctionCallNode;
@@ -837,6 +901,8 @@ begin
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