Macro expander integrated in binder

This commit is contained in:
Michael Schimmel
2025-10-05 02:45:13 +02:00
parent 54bf350c70
commit 0d73a13051
6 changed files with 373 additions and 218 deletions
+10 -32
View File
@@ -38,6 +38,7 @@ type
tkQuote, // '
tkBacktick, // `
tkTilde, // ~
tkAt, // @
tkIdentifier,
tkNumber,
tkString,
@@ -251,6 +252,11 @@ begin
Result.Kind := tkTilde;
Advance;
end;
'@':
begin
Result.Kind := tkAt;
Advance;
end;
'"':
begin
Result.Kind := tkString;
@@ -351,7 +357,6 @@ begin
head := elements[0];
// Convert the rest of the list to an array for the factory functions
SetLength(tailTokens, elements.Count - 1);
SetLength(tailNodes, elements.Count - 1);
for var i := 0 to High(tailNodes) do
@@ -391,7 +396,6 @@ begin
end
else if SameText(head.Token.Text, 'defmacro') then
begin
// (defmacro name [params] body)
if (Length(tailNodes) <> 3) or (tailTokens[0].Kind <> tkIdentifier) then
raise Exception.Create('Syntax Error: ''defmacro'' requires a name, a parameter list, and a body.');
if elements[2].Params = nil then
@@ -424,34 +428,10 @@ begin
else if SameText(head.Token.Text, 'get') then
Result := TAst.Indexer(tailNodes[0], tailNodes[1])
else if (Length(head.Token.Text) > 1) and (head.Token.Text.StartsWith('.')) then
Result := TAst.MemberAccess(tailNodes[0], TAst.Identifier(head.Token.Text.Substring(1)))
else
begin
if Length(tailNodes) = 1 then
begin
for var op := Low(TScalar.TUnaryOp) to High(TScalar.TUnaryOp) do
begin
if head.Token.Text = op.ToString then
begin
Result := TAst.UnaryExpr(op, tailNodes[0]);
break
end;
end;
end
else if Length(tailNodes) = 2 then
begin
for var op := Low(TScalar.TBinaryOp) to High(TScalar.TBinaryOp) do
begin
if head.Token.Text = op.ToString then
begin
Result := TAst.BinaryExpr(tailNodes[0], op, tailNodes[1]);
break
end;
end;
end;
end;
Result := TAst.MemberAccess(tailNodes[0], TAst.Identifier(head.Token.Text.Substring(1)));
end;
// If no special form matched, treat it as a generic function call.
if Result = nil then
Result := TAst.FunctionCall(head.Node, tailNodes);
@@ -480,14 +460,13 @@ begin
tkTilde:
begin
NextToken;
// Check for unquote-splicing ('~@')
if (FCurrentToken.Kind = tkIdentifier) and (FCurrentToken.Text = '@') then
if FCurrentToken.Kind = tkAt then
begin
NextToken;
expr := ParseExpression;
Result.Node := TAst.UnquoteSplicing(expr.Node);
end
else // It's a regular unquote ('~')
else
begin
expr := ParseExpression;
Result.Node := TAst.Unquote(expr.Node);
@@ -498,7 +477,6 @@ begin
begin
NextToken;
expr := ParseExpression;
// A regular quote '(...) can be desugared into (quote (...))
Result.Node := TAst.FunctionCall(TAst.Identifier('quote'), [expr.Node]);
exit;
end;