added macro quoting nodes
This commit is contained in:
+93
-16
@@ -34,6 +34,9 @@ type
|
||||
tkRightParen, // )
|
||||
tkLeftBracket, // [
|
||||
tkRightBracket, // ]
|
||||
tkQuote, // '
|
||||
tkBacktick, // `
|
||||
tkTilde, // ~
|
||||
tkIdentifier,
|
||||
tkNumber,
|
||||
tkString,
|
||||
@@ -109,6 +112,9 @@ type
|
||||
function VisitTernaryExpression(const Node: ITernaryExpressionNode): TDataValue;
|
||||
function VisitLambdaExpression(const Node: ILambdaExpressionNode): TDataValue;
|
||||
function VisitMacroDefinition(const Node: IMacroDefinitionNode): TDataValue;
|
||||
function VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
||||
function VisitUnquote(const Node: IUnquoteNode): TDataValue;
|
||||
function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
|
||||
function VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
function VisitBlockExpression(const Node: IBlockExpressionNode): TDataValue;
|
||||
function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TDataValue;
|
||||
@@ -148,8 +154,8 @@ var
|
||||
startPos: Integer;
|
||||
begin
|
||||
startPos := FCurrentPos;
|
||||
// Corrected W1050: Use CharInSet for robust unicode support.
|
||||
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']']))) do
|
||||
// Reader macro characters are now also delimiters for identifiers.
|
||||
while (Peek <> #0) and (not (Peek.IsWhiteSpace or CharInSet(Peek, ['(', ')', '[', ']', '''', '`', '~']))) do
|
||||
Advance;
|
||||
Result := Copy(FSource, startPos, FCurrentPos - startPos);
|
||||
end;
|
||||
@@ -228,6 +234,21 @@ begin
|
||||
Result.Kind := tkRightBracket;
|
||||
Advance;
|
||||
end;
|
||||
'''':
|
||||
begin
|
||||
Result.Kind := tkQuote;
|
||||
Advance;
|
||||
end;
|
||||
'`':
|
||||
begin
|
||||
Result.Kind := tkBacktick;
|
||||
Advance;
|
||||
end;
|
||||
'~':
|
||||
begin
|
||||
Result.Kind := tkTilde;
|
||||
Advance;
|
||||
end;
|
||||
'"':
|
||||
begin
|
||||
Result.Kind := tkString;
|
||||
@@ -382,7 +403,6 @@ begin
|
||||
end
|
||||
else if SameText(head.Token.Text, 'fn') then
|
||||
begin
|
||||
// Corrected handling for lambda expressions
|
||||
if Length(tailNodes) <> 2 then
|
||||
raise Exception.Create('Syntax Error: ''fn'' requires a parameter list and a body.');
|
||||
if elements[1].Node <> nil then
|
||||
@@ -438,19 +458,43 @@ function TParser.ParseExpression: TExpr;
|
||||
var
|
||||
i64: Int64;
|
||||
dbl: Double;
|
||||
expr: TExpr;
|
||||
begin
|
||||
// TODO: Implement reader macros for quasiquoting here.
|
||||
// The current lexer will tokenize `, ~, and ~@ as identifiers.
|
||||
// Check for them here and wrap the subsequent expression accordingly.
|
||||
// Example:
|
||||
// if FCurrentToken.Text = '`' then
|
||||
// begin
|
||||
// NextToken;
|
||||
// var exprToQuote := ParseExpression;
|
||||
// Result.Node := TAst.Quasiquote(exprToQuote.Node);
|
||||
// exit;
|
||||
// end;
|
||||
// (This requires IQuasiquoteNode and TAst.Quasiquote to be defined first).
|
||||
// Handle reader macros.
|
||||
case FCurrentToken.Kind of
|
||||
tkBacktick:
|
||||
begin
|
||||
NextToken;
|
||||
expr := ParseExpression;
|
||||
Result.Node := TAst.Quasiquote(expr.Node);
|
||||
exit;
|
||||
end;
|
||||
tkTilde:
|
||||
begin
|
||||
NextToken;
|
||||
// Check for unquote-splicing ('~@')
|
||||
if (FCurrentToken.Kind = tkIdentifier) and (FCurrentToken.Text = '@') then
|
||||
begin
|
||||
NextToken;
|
||||
expr := ParseExpression;
|
||||
Result.Node := TAst.UnquoteSplicing(expr.Node);
|
||||
end
|
||||
else // It's a regular unquote ('~')
|
||||
begin
|
||||
expr := ParseExpression;
|
||||
Result.Node := TAst.Unquote(expr.Node);
|
||||
end;
|
||||
exit;
|
||||
end;
|
||||
tkQuote:
|
||||
begin
|
||||
NextToken;
|
||||
expr := ParseExpression;
|
||||
// A regular quote '(...) can be desugared into (quote (...))
|
||||
Result.Node := TAst.FunctionCall(TAst.Identifier('quote'), [expr.Node]);
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
Result.Token := FCurrentToken;
|
||||
case FCurrentToken.Kind of
|
||||
@@ -639,7 +683,6 @@ var
|
||||
param: IIdentifierNode;
|
||||
sb: TStringBuilder;
|
||||
begin
|
||||
// Added visitor for pretty printing macro definitions.
|
||||
sb := TStringBuilder.Create;
|
||||
try
|
||||
for param in Node.Parameters do
|
||||
@@ -661,10 +704,41 @@ begin
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitQuasiquote(const Node: IQuasiquoteNode): TDataValue;
|
||||
begin
|
||||
Append('`');
|
||||
Node.Expression.Accept(Self);
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitUnquote(const Node: IUnquoteNode): TDataValue;
|
||||
begin
|
||||
Append('~');
|
||||
Node.Expression.Accept(Self);
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TDataValue;
|
||||
begin
|
||||
// To handle '~@', we need to check if the expression is an identifier '@'.
|
||||
// However, the parser logic now handles this, so we just print '~@'.
|
||||
Append('~@');
|
||||
Node.Expression.Accept(Self);
|
||||
Result := TDataValue.Void;
|
||||
end;
|
||||
|
||||
function TPrettyPrintVisitor.VisitFunctionCall(const Node: IFunctionCallNode): TDataValue;
|
||||
var
|
||||
arg: IAstNode;
|
||||
begin
|
||||
// Special case for (quote ...) to print it as '...
|
||||
if (Node.Callee is TIdentifierNode) and (TIdentifierNode(Node.Callee).Name = 'quote') and (Length(Node.Arguments) = 1) then
|
||||
begin
|
||||
Append('''');
|
||||
Node.Arguments[0].Accept(Self);
|
||||
exit(TDataValue.Void);
|
||||
end;
|
||||
|
||||
Append('(');
|
||||
Node.Callee.Accept(Self);
|
||||
|
||||
@@ -828,6 +902,9 @@ begin
|
||||
tkRightParen: Result := ')';
|
||||
tkLeftBracket: Result := '[';
|
||||
tkRightBracket: Result := ']';
|
||||
tkQuote: Result := '''';
|
||||
tkBacktick: Result := '`';
|
||||
tkTilde: Result := '~';
|
||||
tkIdentifier: Result := '<identifier>';
|
||||
tkNumber: Result := '<number>';
|
||||
tkString: Result := '<string>';
|
||||
|
||||
Reference in New Issue
Block a user