AST list refactoring
This commit is contained in:
@@ -32,7 +32,7 @@ type
|
||||
class var
|
||||
FGensymCounter: Int64;
|
||||
|
||||
function TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
|
||||
function TransformAndSpliceNodes(const ANodes: ITupleNode): TArray<IAstNode>;
|
||||
function Gensym(const ABaseName: string): string;
|
||||
|
||||
// Custom Logic Handlers (IAstNode signature)
|
||||
@@ -186,17 +186,19 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: INodeList<IAstNode>): TArray<IAstNode>;
|
||||
function TExpansionVisitor.TransformAndSpliceNodes(const ANodes: ITupleNode): TArray<IAstNode>;
|
||||
var
|
||||
newList: TList<IAstNode>;
|
||||
nodeToSplice: IAstNode;
|
||||
transformedNode: IAstNode;
|
||||
node: IAstNode;
|
||||
i: Integer;
|
||||
begin
|
||||
newList := TList<IAstNode>.Create;
|
||||
try
|
||||
for node in ANodes do
|
||||
for i := 0 to ANodes.Count - 1 do
|
||||
begin
|
||||
node := ANodes.Items[i];
|
||||
if node.Kind = akUnquoteSplicing then
|
||||
begin
|
||||
var spliceExpr := node.AsUnquoteSplicing.Expression;
|
||||
@@ -213,17 +215,24 @@ begin
|
||||
if (not evaluatedSpliceValue.IsVoid) and (evaluatedSpliceValue.Kind = vkInterface) then
|
||||
begin
|
||||
nodeToSplice := evaluatedSpliceValue.AsIntf<IAstNode>;
|
||||
if nodeToSplice.Kind = akExpressionList then
|
||||
for var subItem in nodeToSplice.AsExpressionList do
|
||||
newList.Add(subItem)
|
||||
else if nodeToSplice.Kind = akArgumentList then
|
||||
for var subItem in nodeToSplice.AsArgumentList do
|
||||
newList.Add(subItem)
|
||||
// Unification: Lists are now Tuples.
|
||||
if nodeToSplice.Kind = akTuple then
|
||||
begin
|
||||
var tuple := nodeToSplice.AsTuple;
|
||||
for var k := 0 to tuple.Count - 1 do
|
||||
newList.Add(tuple.Items[k]);
|
||||
end
|
||||
else if nodeToSplice.Kind = akBlockExpression then
|
||||
for var subItem in nodeToSplice.AsBlockExpression.Expressions do
|
||||
newList.Add(subItem)
|
||||
begin
|
||||
var blkTuple := nodeToSplice.AsBlockExpression.Expressions;
|
||||
for var k := 0 to blkTuple.Count - 1 do
|
||||
newList.Add(blkTuple.Items[k]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Single node splicing
|
||||
newList.Add(nodeToSplice);
|
||||
end;
|
||||
end
|
||||
else if (not evaluatedSpliceValue.IsVoid) then
|
||||
newList.Add(TAst.Constant(evaluatedSpliceValue, node.Identity.Location));
|
||||
@@ -277,22 +286,26 @@ end;
|
||||
function TExpansionVisitor.VisitLambdaExpression(const Node: IAstNode): IAstNode;
|
||||
var
|
||||
L: ILambdaExpressionNode;
|
||||
newParams: TArray<IIdentifierNode>;
|
||||
newParams: TArray<IAstNode>;
|
||||
newBody: IAstNode;
|
||||
newName: string;
|
||||
i: Integer;
|
||||
paramsTuple: ITupleNode;
|
||||
begin
|
||||
L := Node.AsLambdaExpression;
|
||||
SetLength(newParams, L.Parameters.Count);
|
||||
for i := 0 to L.Parameters.Count - 1 do
|
||||
paramsTuple := L.Parameters;
|
||||
SetLength(newParams, paramsTuple.Count);
|
||||
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
begin
|
||||
var param := L.Parameters[i];
|
||||
var param := paramsTuple.Items[i].AsIdentifier; // Binder ensures params are Identifiers
|
||||
newName := Gensym(param.Name);
|
||||
newParams[i] := TAst.Identifier(newName, param.Identity.Location);
|
||||
end;
|
||||
|
||||
newBody := Accept(L.Body);
|
||||
Result := TAst.LambdaExpr(Node.Identity, TParameterList.Create(newParams, L.Parameters.Identity), newBody);
|
||||
|
||||
Result := TAst.LambdaExpr(Node.Identity, TAst.Tuple(L.Parameters.Identity, newParams), newBody);
|
||||
end;
|
||||
|
||||
function TExpansionVisitor.VisitUnquote(const Node: IAstNode): IAstNode;
|
||||
@@ -335,7 +348,7 @@ end;
|
||||
|
||||
function TExpansionVisitor.VisitUnquoteSplicing(const Node: IAstNode): IAstNode;
|
||||
begin
|
||||
raise EMacroException.Create('Unquote-splicing (`~@`) can only appear inside a list form.');
|
||||
raise EMacroException.Create('Unquote-splicing (`~@`) can only appear inside a list/tuple form.');
|
||||
end;
|
||||
|
||||
function TExpansionVisitor.VisitFunctionCall(const Node: IAstNode): IAstNode;
|
||||
@@ -343,27 +356,38 @@ var
|
||||
C: IFunctionCallNode;
|
||||
newArgs: TArray<IAstNode>;
|
||||
transformedCallee: IAstNode;
|
||||
argsTuple: ITupleNode;
|
||||
begin
|
||||
C := Node.AsFunctionCall;
|
||||
transformedCallee := Self.Accept(C.Callee);
|
||||
// Arguments is a Tuple, so we can splice into it
|
||||
newArgs := TransformAndSpliceNodes(C.Arguments);
|
||||
Result := TAst.FunctionCall(Node.Identity, transformedCallee, TArgumentList.Create(newArgs, C.Arguments.Identity));
|
||||
|
||||
// Wrap result array in a TupleNode before creating FunctionCall
|
||||
argsTuple := TAst.Tuple(C.Arguments.Identity, newArgs);
|
||||
|
||||
Result := TAst.FunctionCall(Node.Identity, transformedCallee, argsTuple);
|
||||
end;
|
||||
|
||||
function TExpansionVisitor.VisitBlockExpression(const Node: IAstNode): IAstNode;
|
||||
var
|
||||
B: IBlockExpressionNode;
|
||||
newExprs: TArray<IAstNode>;
|
||||
exprsTuple: ITupleNode;
|
||||
begin
|
||||
B := Node.AsBlockExpression;
|
||||
// Expressions is a Tuple
|
||||
newExprs := TransformAndSpliceNodes(B.Expressions);
|
||||
Result := TAst.Block(Node.Identity, TExpressionList.Create(newExprs, B.Expressions.Identity));
|
||||
|
||||
exprsTuple := TAst.Tuple(B.Expressions.Identity, newExprs);
|
||||
|
||||
Result := TAst.Block(Node.Identity, exprsTuple);
|
||||
end;
|
||||
|
||||
function TExpansionVisitor.VisitRecordLiteral(const Node: IAstNode): IAstNode;
|
||||
begin
|
||||
// Delegate to standard transformer to process fields recursively
|
||||
// This calls inherited VisitRecordLiteral(IAstNode)
|
||||
// This calls inherited VisitRecordLiteral(IAstNode) which visits the Fields Tuple
|
||||
Result := inherited VisitRecordLiteral(Node);
|
||||
end;
|
||||
|
||||
@@ -473,13 +497,17 @@ begin
|
||||
if macroDef <> nil then
|
||||
begin
|
||||
var expansionScope := TScope.CreateScope(FInitialScope, nil, nil);
|
||||
var params := macroDef.Parameters;
|
||||
var paramsTuple := macroDef.Parameters;
|
||||
var argsTuple := C.Arguments;
|
||||
|
||||
if C.Arguments.Count <> params.Count then
|
||||
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, params.Count]);
|
||||
if argsTuple.Count <> paramsTuple.Count then
|
||||
raise EMacroException.CreateFmt('Macro %s expects %d arguments.', [calleeIdentifier.Name, paramsTuple.Count]);
|
||||
|
||||
for i := 0 to params.Count - 1 do
|
||||
expansionScope.Define(params[i].Name, TDataValue.FromIntf<IAstNode>(C.Arguments[i]));
|
||||
for i := 0 to paramsTuple.Count - 1 do
|
||||
begin
|
||||
var paramName := paramsTuple.Items[i].AsIdentifier.Name;
|
||||
expansionScope.Define(paramName, TDataValue.FromIntf<IAstNode>(argsTuple.Items[i]));
|
||||
end;
|
||||
|
||||
var expandedBody := TExpansionVisitor.Expand(expansionScope, macroDef.Body.AsQuasiquote.Expression, FMacroEvaluator);
|
||||
var macroNode := TAst.MacroExpansionNode(Node.Identity, C, expandedBody);
|
||||
|
||||
Reference in New Issue
Block a user