Ast list nodes

This commit is contained in:
Michael Schimmel
2025-11-29 18:59:16 +01:00
parent 250f950a68
commit 851f56c63f
24 changed files with 1819 additions and 863 deletions
+63 -17
View File
@@ -34,15 +34,20 @@ type
class var
FGensymCounter: Int64;
function TransformAndSpliceNodes(const ANodes: TArray<IAstNode>): TArray<IAstNode>;
// Helper to handle unquote-splicing (~@) within lists.
// Takes a source list (e.g., Arguments) and returns a flattened array for the new node.
function TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
function Gensym(const ABaseName: string): string;
protected
function VisitUnquote(const Node: IUnquoteNode): IAstNode; override;
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): IAstNode; override;
// We override these container visits to handle Splicing manually,
// bypassing the standard 1:1 list visitor.
function VisitFunctionCall(const Node: IFunctionCallNode): IAstNode; override;
function VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override;
function VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode; override;
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): IAstNode; override;
function VisitLambdaExpression(const Node: ILambdaExpressionNode): IAstNode; override;
function VisitIdentifier(const Node: IIdentifierNode): IAstNode; override;
@@ -169,15 +174,16 @@ begin
end;
end;
function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: TArray<IAstNode>): TArray<IAstNode>;
function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
var
newList: TList<IAstNode>;
nodeToSplice: IAstNode;
transformedNode: IAstNode;
node: IAstNode;
begin
newList := TList<IAstNode>.Create;
try
for var node in ANodes do
for node in ANodes do
begin
if node.Kind = akUnquoteSplicing then
begin
@@ -196,10 +202,30 @@ begin
if (not evaluatedSpliceValue.IsVoid) and (evaluatedSpliceValue.Kind = vkInterface) then
begin
nodeToSplice := evaluatedSpliceValue.AsIntf<IAstNode>;
if nodeToSplice.Kind = akBlockExpression then
newList.AddRange(nodeToSplice.AsBlockExpression.Expressions)
// Splicing implies the value must be a list-like AST structure (Block or just a List Node)
// If the evaluated value is an IArgumentList, IExpressionList etc., we flatten it.
if nodeToSplice.Kind = akExpressionList then
begin
for var subItem in nodeToSplice.AsExpressionList do
newList.Add(subItem);
end
else if nodeToSplice.Kind = akArgumentList then
begin
for var subItem in nodeToSplice.AsArgumentList do
newList.Add(subItem);
end
else if nodeToSplice.Kind = akBlockExpression then
begin
// Splice content of block
for var subItem in nodeToSplice.AsBlockExpression.Expressions do
newList.Add(subItem);
end
else
begin
// Treat as single item
newList.Add(nodeToSplice);
end;
end
else if (not evaluatedSpliceValue.IsVoid) then
begin
@@ -261,19 +287,24 @@ var
newBody: IAstNode;
newName: string;
i: Integer;
paramList: IParameterList;
begin
SetLength(newParams, Length(Node.Parameters));
for i := 0 to High(Node.Parameters) do
SetLength(newParams, Node.Parameters.Count);
for i := 0 to Node.Parameters.Count - 1 do
begin
newName := Gensym(Node.Parameters[i].Name);
var param := Node.Parameters[i];
newName := Gensym(param.Name);
// Use location from original param
newParams[i] := TAst.Identifier(newName, Node.Parameters[i].Identity.Location);
newParams[i] := TAst.Identifier(newName, param.Identity.Location);
end;
newBody := Accept(Node.Body);
// Rebuild structural lambda
Result := TAst.LambdaExpr(Node.Identity, newParams, newBody);
// Rebuild: Wrap array in TParameterList with original Identity
paramList := TParameterList.Create(newParams, Node.Parameters.Identity);
// Use transformation overload
Result := TAst.LambdaExpr(Node.Identity, paramList, newBody);
end;
function TExpansionVisitor.VisitUnquote(const Node: IUnquoteNode): IAstNode;
@@ -284,6 +315,7 @@ var
begin
expr := Node.Expression;
// Optimization: If unquote refers to a local macro variable directly, try to get it.
if expr.Kind = akIdentifier then
begin
addr := FMacroScope.Resolve(expr.AsIdentifier.Name);
@@ -329,22 +361,36 @@ function TExpansionVisitor.VisitFunctionCall(const Node: IFunctionCallNode): IAs
var
newArgs: TArray<IAstNode>;
transformedCallee: IAstNode;
argList: IArgumentList;
begin
transformedCallee := Self.Accept(Node.Callee);
// Use splicing aware transformation for arguments (returns TArray)
newArgs := TransformAndSpliceNodes(Node.Arguments);
Result := TAst.FunctionCall(Node.Identity, transformedCallee, newArgs);
// Wrap in List container to use Transformation overload
argList := TArgumentList.Create(newArgs, Node.Arguments.Identity);
Result := TAst.FunctionCall(Node.Identity, transformedCallee, argList);
end;
function TExpansionVisitor.VisitBlockExpression(const Node: IBlockExpressionNode): IAstNode;
var
newExprs: TArray<IAstNode>;
exprList: IExpressionList;
begin
// Use splicing aware transformation for block expressions
newExprs := TransformAndSpliceNodes(Node.Expressions);
Result := TAst.Block(Node.Identity, newExprs);
// Wrap in List
exprList := TExpressionList.Create(newExprs, Node.Expressions.Identity);
Result := TAst.Block(Node.Identity, exprList);
end;
function TExpansionVisitor.VisitRecordLiteral(const Node: IRecordLiteralNode): IAstNode;
begin
// For now, standard transformation for records (no splicing key-values yet)
Result := inherited VisitRecordLiteral(Node);
end;
@@ -438,10 +484,10 @@ begin
var expansionScope := TScope.CreateScope(FInitialScope, nil, nil);
var params := macroDef.Parameters;
if Length(Node.Arguments) <> Length(params) then
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, Length(params)]);
if Node.Arguments.Count <> params.Count then
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, params.Count]);
for i := 0 to High(params) do
for i := 0 to params.Count - 1 do
expansionScope.Define(params[i].Name, TDataValue.FromIntf<IAstNode>(Node.Arguments[i]));
var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator);