diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-21 05:43:35 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-21 05:43:35 +0000 |
| commit | dd5bbae055fd34ce2e12ef63f8a261c6b15dc83e (patch) | |
| tree | 757e367daacf92c50148eb42d7bda97ba33ed3fb /lib/Parser/ParserExpression.cc | |
| parent | c682f983b0dce3acba76d1f08719a26b9c52c5ec (diff) | |
feat(parser): parse TEMPLATE declarations, template ids and parameter packs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/Parser/ParserExpression.cc')
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index be22b4e..ef8e1d3 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -3,6 +3,7 @@ #include "cps/FunctionAST.h" #include <cstdio> #include <limits> +#include <functional> using namespace cps; @@ -40,6 +41,39 @@ std::unique_ptr<ExprAST> Parser::ParseNumberExpr() { return std::make_unique<IntegerExprAST>(Value); } +// Grammar lookahead distinguishes a template call from a comparison without +// consuming tokens. Like C#, A < B, C > (D) selects the template-call grammar. +bool Parser::isTemplateCall() { + if (CurTok != '<') return false; + unsigned Offset = 0; + auto IsTypeToken = [](int Tok) { + return Tok == tok_identifier || Tok == tok_integer_kw || Tok == tok_real_kw || + Tok == tok_boolean_kw || Tok == tok_string_kw || Tok == tok_char_kw || + Tok == tok_c_int || Tok == tok_c_char || Tok == tok_c_string || Tok == tok_c_double; + }; + std::function<bool()> Type = [&] { + if (!IsTypeToken(Lex.peekToken(Offset))) return false; + ++Offset; + if (Lex.peekToken(Offset) == '<') { + ++Offset; + if (!Type()) return false; + while (Lex.peekToken(Offset) == ',') { + ++Offset; + if (!Type()) return false; + } + if (Lex.peekToken(Offset++) != '>') return false; + } + if (Lex.peekToken(Offset) == tok_ellipsis) ++Offset; + return true; + }; + if (!Type()) return false; + while (Lex.peekToken(Offset) == ',') { + ++Offset; + if (!Type()) return false; + } + return Lex.peekToken(Offset) == '>' && Lex.peekToken(Offset + 1) == '('; +} + std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { int Line = Lex.getLine(); std::string IdName; @@ -52,6 +86,25 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { getNextToken(); } + if (PackNames.count(IdName)) { + if (CurTok != tok_ellipsis) { + sourceDiagnostic(Line, "error: A parameter pack must be expanded with '...' at line %d\n", Line); + return nullptr; + } + getNextToken(); + return std::make_unique<PackExpansionExprAST>(IdName, Line); + } + if (CurTok == tok_ellipsis) { + sourceDiagnostic(Line, "error: Only a parameter pack may be expanded at line %d\n", Line); + getNextToken(); + return nullptr; + } + std::vector<std::string> TemplateArgs; + if (isTemplateCall()) { + auto Parsed = ParseTemplateArgs(); + if (!Parsed) return nullptr; + TemplateArgs = std::move(*Parsed); + } if (CurTok == '(' && !atCaseBoundary()) { getNextToken(); auto Args = ParseExprList(')', true); @@ -61,7 +114,7 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { Lex.getLine()); return nullptr; } - return ParseResultMethods(std::make_unique<CallExprAST>(IdName, std::move(*Args), Line), Line); + return ParseResultMethods(std::make_unique<CallExprAST>(IdName, std::move(*Args), Line, std::move(TemplateArgs)), Line); } std::vector<DesignatorAccess> Accesses; |
