Macro expander integrated in binder

This commit is contained in:
Michael Schimmel
2025-10-05 15:02:45 +02:00
parent 0d73a13051
commit 0edb9b800b
6 changed files with 27 additions and 17 deletions
File diff suppressed because one or more lines are too long
+7 -5
View File
@@ -24,7 +24,7 @@ type
private private
FJsonObjectStack: TStack<TJSONObject>; FJsonObjectStack: TStack<TJSONObject>;
procedure DataValueToJson(const AValue: TDataValue; const AParent: TJSONObject; const AName: string); procedure DataValueToJson(const AValue: TDataValue; const AParent: TJSONObject; const AName: string);
function JsonToNode(const AJson: TJSONValue): IAstNode; function JsonToNode(const AJson: TJSONValue; const ExpectedType: String = ''): IAstNode;
function JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue; function JsonToDataValue(const AObj: TJSONObject; const AName: string): TDataValue;
function JsonToConstantNode(const AObj: TJSONObject): IConstantNode; function JsonToConstantNode(const AObj: TJSONObject): IConstantNode;
@@ -276,7 +276,6 @@ var
param: IIdentifierNode; param: IIdentifierNode;
i: Integer; i: Integer;
begin begin
// Added serialization for macro definitions.
Node.Name.Accept(Self); Node.Name.Accept(Self);
for param in Node.Parameters do for param in Node.Parameters do
param.Accept(Self); param.Accept(Self);
@@ -719,7 +718,7 @@ function TJsonAstConverter.JsonToMacroDefNode(const AObj: TJSONObject): IMacroDe
var var
name: IIdentifierNode; name: IIdentifierNode;
params: TArray<IIdentifierNode>; params: TArray<IIdentifierNode>;
body: IAstNode; body: IQuasiquoteNode;
paramArray: TJSONArray; paramArray: TJSONArray;
i: Integer; i: Integer;
begin begin
@@ -731,7 +730,7 @@ begin
for i := 0 to paramArray.Count - 1 do for i := 0 to paramArray.Count - 1 do
params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject); params[i] := JsonToIdentifierNode(paramArray.Items[i] as TJSONObject);
body := JsonToNode(AObj.GetValue('Body')); body := IQuasiquoteNode(JsonToNode(AObj.GetValue('Body'), 'Quasiquote'));
Result := TAst.MacroDef(name, params, body); Result := TAst.MacroDef(name, params, body);
end; end;
@@ -874,7 +873,7 @@ begin
Result := TAst.SeriesLength(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject)); Result := TAst.SeriesLength(JsonToIdentifierNode(AObj.GetValue('Series') as TJSONObject));
end; end;
function TJsonAstConverter.JsonToNode(const AJson: TJSONValue): IAstNode; function TJsonAstConverter.JsonToNode(const AJson: TJSONValue; const ExpectedType: String = ''): IAstNode;
var var
obj: TJSONObject; obj: TJSONObject;
nodeType: string; nodeType: string;
@@ -885,6 +884,9 @@ begin
obj := AJson as TJSONObject; obj := AJson as TJSONObject;
nodeType := obj.GetValue<string>('NodeType'); nodeType := obj.GetValue<string>('NodeType');
if (ExpectedType <> '') and (nodeType <> ExpectedType) then
raise EInvalidCast.CreateFmt('Expected a JSON object of type %s for deserialization, but got a %s.', [ExpectedType, nodeType]);
if nodeType = 'Constant' then if nodeType = 'Constant' then
Result := JsonToConstantNode(obj) Result := JsonToConstantNode(obj)
else if nodeType = 'Identifier' then else if nodeType = 'Identifier' then
+2 -2
View File
@@ -200,11 +200,11 @@ type
{$region 'private'} {$region 'private'}
function GetName: IIdentifierNode; function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode; function GetBody: IQuasiquoteNode;
{$endregion} {$endregion}
property Name: IIdentifierNode read GetName; property Name: IIdentifierNode read GetName;
property Parameters: TArray<IIdentifierNode> read GetParameters; property Parameters: TArray<IIdentifierNode> read GetParameters;
property Body: IAstNode read GetBody; property Body: IQuasiquoteNode read GetBody;
end; end;
// Represents a quasiquoted expression, e.g., `(a b) // Represents a quasiquoted expression, e.g., `(a b)
+5 -1
View File
@@ -403,7 +403,11 @@ begin
var macroName := IIdentifierNode(tailNodes[0]); var macroName := IIdentifierNode(tailNodes[0]);
var macroParams := elements[2].Params; var macroParams := elements[2].Params;
var macroBody := tailNodes[2];
if tailTokens[2].Kind <> tkQuote then
raise Exception.Create('Syntax Error: Expected a quasiquote as macro body.');
var macroBody := IQuasiQuoteNode(tailNodes[2]);
Result := TAst.MacroDef(macroName, macroParams, macroBody); Result := TAst.MacroDef(macroName, macroParams, macroBody);
end end
+1 -1
View File
@@ -262,7 +262,7 @@ function TAstTransformer.VisitMacroDefinition(const Node: IMacroDefinitionNode):
begin begin
var name := Accept(Node.Name).AsIntf<IIdentifierNode>; var name := Accept(Node.Name).AsIntf<IIdentifierNode>;
var parameters := TransformNodes<IIdentifierNode>(Node.Parameters); var parameters := TransformNodes<IIdentifierNode>(Node.Parameters);
var body := Accept(Node.Body).AsIntf<IAstNode>; var body := Accept(Node.Body).AsIntf<IQuasiquoteNode>;
if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then if (name = Node.Name) and (parameters = Node.Parameters) and (body = Node.Body) then
Result := TDataValue.FromIntf<IMacroDefinitionNode>(Node) Result := TDataValue.FromIntf<IMacroDefinitionNode>(Node)
else else
+11 -7
View File
@@ -39,7 +39,7 @@ type
class function MacroDef( class function MacroDef(
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: TArray<IIdentifierNode>;
const ABody: IAstNode const ABody: IQuasiquoteNode
): IMacroDefinitionNode; static; ): IMacroDefinitionNode; static;
class function Quasiquote(const AExpression: IAstNode): IQuasiquoteNode; static; class function Quasiquote(const AExpression: IAstNode): IQuasiquoteNode; static;
class function Unquote(const AExpression: IAstNode): IUnquoteNode; static; class function Unquote(const AExpression: IAstNode): IUnquoteNode; static;
@@ -158,12 +158,12 @@ type
private private
FName: IIdentifierNode; FName: IIdentifierNode;
FParameters: TArray<IIdentifierNode>; FParameters: TArray<IIdentifierNode>;
FBody: IAstNode; FBody: IQuasiquoteNode;
function GetName: IIdentifierNode; function GetName: IIdentifierNode;
function GetParameters: TArray<IIdentifierNode>; function GetParameters: TArray<IIdentifierNode>;
function GetBody: IAstNode; function GetBody: IQuasiquoteNode;
public public
constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode); constructor Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IQuasiquoteNode);
function Accept(const Visitor: IAstVisitor): TDataValue; override; function Accept(const Visitor: IAstVisitor): TDataValue; override;
property Name: IIdentifierNode read GetName; property Name: IIdentifierNode read GetName;
end; end;
@@ -494,7 +494,11 @@ end;
{ TMacroDefinitionNode } { TMacroDefinitionNode }
constructor TMacroDefinitionNode.Create(const AName: IIdentifierNode; const AParameters: TArray<IIdentifierNode>; const ABody: IAstNode); constructor TMacroDefinitionNode.Create(
const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>;
const ABody: IQuasiquoteNode
);
begin begin
inherited Create; inherited Create;
FName := AName; FName := AName;
@@ -507,7 +511,7 @@ begin
Result := Visitor.VisitMacroDefinition(Self); Result := Visitor.VisitMacroDefinition(Self);
end; end;
function TMacroDefinitionNode.GetBody: IAstNode; function TMacroDefinitionNode.GetBody: IQuasiquoteNode;
begin begin
Result := FBody; Result := FBody;
end; end;
@@ -927,7 +931,7 @@ end;
class function TAst.MacroDef( class function TAst.MacroDef(
const AName: IIdentifierNode; const AName: IIdentifierNode;
const AParameters: TArray<IIdentifierNode>; const AParameters: TArray<IIdentifierNode>;
const ABody: IAstNode const ABody: IQuasiquoteNode
): IMacroDefinitionNode; ): IMacroDefinitionNode;
begin begin
Result := TMacroDefinitionNode.Create(AName, AParameters, ABody); Result := TMacroDefinitionNode.Create(AName, AParameters, ABody);