LCOV - code coverage report
Current view: top level - staxlib/frontend/src/parser - parser.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.8 % 167 150
Test Date: 1980-01-01 00:00:00 Functions: 93.8 % 16 15

            Line data    Source code
       1              : #include "stax/parser/parser.hpp"
       2              : 
       3              : #include <set>
       4              : 
       5              : #include "stax/utils/format.hpp"
       6              : #include "stax/utils/result.hpp"
       7              : 
       8              : namespace stax::parser {
       9              : 
      10           13 : Parser::Parser(const std::string& input) : input_(input), lexer_(input_) {
      11              :   // TODO deal with error handling
      12           13 :   NextToken().value();
      13           13 :   NextToken().value();
      14           13 : }
      15              : 
      16           13 : auto Parser::ParseProgram() -> result_t<Program> {
      17           13 :   Program prog{};
      18              : 
      19           26 :   while (curr_.type != token::Type::kEOF) {
      20           13 :     TRY_RESULT(const auto stmt, ParseStatement());
      21           13 :     prog.statements.push_back(stmt);
      22           13 :   }
      23              : 
      24           13 :   return prog;
      25           13 : }
      26              : 
      27           15 : auto Parser::ParseStatement() -> result_t<ast_t> {
      28           15 :   switch (curr_.type) {
      29           13 :     case token::Type::kIdent: {
      30           13 :       if (peek_.type == token::Type::kLParen) return ParseExpressionStatement();
      31           12 :       return ParseDeclaration();
      32              :     }
      33            2 :     case token::Type::kReturn: return ParseReturn(); break;
      34            0 :     default:
      35            0 :       return stax::result::Err(Error::InvalidToken, std::format("{}", curr_));
      36              :   }
      37              : }
      38              : 
      39            2 : auto Parser::ParseReturn() -> result_t<ast_t> {
      40            2 :   TRY_RESULT(NextToken());
      41            2 :   TRY_RESULT(const auto& expression, ParseExpressionStatement());
      42              : 
      43            2 :   return ReturnStatement{.expression = expression};
      44            2 : }
      45              : 
      46           12 : auto Parser::ParseDeclaration() -> result_t<ast_t> {
      47           12 :   TRY_RESULT(Expect(token::Type::kIdent));
      48           36 :   const auto& data_type = DataType{curr_, std::string{curr_.view}};
      49           12 :   TRY_RESULT(NextToken());
      50              : 
      51           12 :   TRY_RESULT(Expect(token::Type::kIdent));
      52           36 :   const auto& ident = Identifier{curr_, std::string{curr_.view}};
      53           12 :   TRY_RESULT(NextToken());
      54              : 
      55           12 :   if (curr_.type == token::Type::kLParen) {
      56            2 :     return ParseFunctionDeclaration(data_type, ident);
      57              :   } else {
      58           10 :     return ParseVariableDeclaration(data_type, ident);
      59              :   }
      60           36 : }
      61              : 
      62            2 : auto Parser::ParseFunctionDeclaration(const DataType& return_type,
      63              :                                       const Identifier& ident)
      64              :     -> result_t<ast_t> {
      65            2 :   if (curr_.type == token::Type::kLParen) {
      66            2 :     TRY_RESULT(NextToken());
      67            2 :   }
      68              : 
      69            2 :   std::vector<VariableDeclaration> args;
      70            4 :   while (curr_.type != token::Type::kRParen) {
      71            2 :     TRY_RESULT(Expect(token::Type::kIdent));
      72            4 :     const auto& data_type = DataType{curr_, std::string{curr_.view}};
      73            2 :     TRY_RESULT(NextToken());
      74              : 
      75            2 :     TRY_RESULT(Expect(token::Type::kIdent));
      76            4 :     const auto& ident = Identifier{curr_, std::string{curr_.view}};
      77            2 :     TRY_RESULT(NextToken());
      78              : 
      79            2 :     if (curr_.type == token::Type::kComma) {
      80            1 :       TRY_RESULT(NextToken());
      81            1 :     }
      82              : 
      83            2 :     args.emplace_back(data_type, ident);
      84            2 :   }
      85              : 
      86            2 :   if (curr_.type == token::Type::kRParen) {
      87            2 :     TRY_RESULT(NextToken());
      88            2 :   }
      89              : 
      90            2 :   TRY_RESULT(Expect(token::Type::kLBrace));
      91            2 :   TRY_RESULT(NextToken());
      92              : 
      93            2 :   std::vector<ast_t> statements;
      94            4 :   while (curr_.type != token::Type::kRBrace) {
      95            2 :     TRY_RESULT(const auto& stmt, ParseStatement());
      96            2 :     statements.emplace_back(stmt);
      97            2 :   }
      98              : 
      99            2 :   TRY_RESULT(Expect(token::Type::kRBrace));
     100            2 :   TRY_RESULT(NextToken());
     101              : 
     102            2 :   std::optional<utils::Box<BlockStatement>> block;
     103            2 :   if (!statements.empty())
     104            2 :     block = utils::Box(BlockStatement{.statements = statements});
     105            2 :   return FunctionDeclaration(return_type, ident, args, block);
     106            2 : }
     107              : 
     108           10 : auto Parser::ParseVariableDeclaration(const DataType& var_type,
     109              :                                       const Identifier& ident)
     110              :     -> result_t<ast_t> {
     111           10 :   std::optional<ExpressionStatement> expression;
     112           10 :   if (curr_.type == token::Type::kAssign) {
     113           10 :     TRY_RESULT(NextToken());
     114           10 :     TRY_RESULT(expression, ParseExpressionStatement());
     115           10 :   }
     116              : 
     117           10 :   return VariableDeclaration(var_type, ident, expression);
     118           10 : }
     119              : 
     120           13 : auto Parser::ParseExpressionStatement() -> result_t<ExpressionStatement> {
     121           13 :   if (curr_.type == token::Type::kIdent && peek_.type == token::Type::kLParen) {
     122            1 :     const auto func_name = std::string(curr_.view);
     123            1 :     TRY_RESULT(NextToken());  // Move past identifier to '('
     124            1 :     TRY_RESULT(const auto func_call, ParseFunctionCall(func_name));
     125            1 :     TRY_RESULT(Expect(token::Type::kSemicolon));
     126            1 :     TRY_RESULT(NextToken());  // Skip semicolon
     127            1 :     return ExpressionStatement{.expression = func_call};
     128            1 :   }
     129              : 
     130           12 :   TRY_RESULT(const auto expression, ParseExpression());
     131              : 
     132           12 :   TRY_RESULT(Expect(token::Type::kSemicolon));
     133           12 :   TRY_RESULT(NextToken());  // Skip semicolon
     134              : 
     135           12 :   return ExpressionStatement{.expression = expression};
     136           12 : }
     137              : 
     138           22 : auto Parser::ParseExpression() -> result_t<expression_t> {
     139              :   const auto generic_parser =
     140           19 :       [this](const token::Token& tok,
     141              :              const token::Token& next) -> result_t<expression_t> {
     142           19 :     switch (tok.type) {
     143           13 :       case token::Type::kInt:
     144           26 :         return IntegerLiteral{.value = std::stoi(std::string(tok.view))};
     145            6 :       case token::Type::kIdent:
     146            6 :         if (next.type == token::Type::kLParen) {
     147            0 :           const auto func_name = std::string(tok.view);
     148            0 :           return ParseFunctionCall(func_name);
     149            0 :         }
     150           12 :         return IdentifierExpression{.ident = std::string(tok.view)};
     151            0 :       default: {
     152            0 :         return stax::result::Err(Error::InvalidToken,
     153            0 :                                  std::format("Not an expression {}", tok));
     154              :       }
     155              :     }
     156           22 :   };
     157              : 
     158              :   const auto& parse_prefix =
     159           22 :       [this, generic_parser](const token::Token& op) -> result_t<expression_t> {
     160              :     const std::set<token::Type> prefix_ops = {
     161              :         token::Type::kPlus, token::Type::kMinus, token::Type::kTilde,
     162           44 :         token::Type::kBang};
     163              : 
     164           22 :     if (prefix_ops.contains(op.type)) {
     165            3 :       TRY_RESULT(const auto operand, ParseExpression());
     166            6 :       return PrefixExpression{.op = op,
     167            3 :                               .operand = utils::Box<expression_t>(operand)};
     168            3 :     }
     169              : 
     170           19 :     return generic_parser(op, peek_);
     171           22 :   };
     172              : 
     173              :   const auto& parse_infix =
     174            6 :       [this](const expression_t& left,
     175              :              const token::Token& op) -> result_t<std::optional<expression_t>> {
     176              :     const std::set<token::Type> infix_ops = {
     177              :         token::Type::kPlus, token::Type::kMinus, token::Type::kGreater,
     178           12 :         token::kLess};
     179              : 
     180            6 :     if (infix_ops.contains(op.type)) {
     181            5 :       TRY_RESULT(const auto operand, ParseExpression());
     182           10 :       return InfixExpression{
     183              :           .lhs = utils::Box<expression_t>(left),
     184              :           .op = op,
     185              :           .rhs = utils::Box<expression_t>(operand),
     186            5 :       };
     187            5 :     }
     188              : 
     189            1 :     return std::nullopt;
     190            6 :   };
     191              : 
     192           22 :   const auto prefix_op = curr_;
     193           22 :   TRY_RESULT(NextToken());
     194           22 :   TRY_RESULT(const auto left, parse_prefix(prefix_op));
     195              : 
     196           22 :   const auto infix_op = curr_;
     197           22 :   if (curr_.type != token::Type::kSemicolon && curr_.type != token::Type::kRParen) {
     198            6 :     TRY_RESULT(NextToken());
     199            6 :     TRY_RESULT(const auto infix, parse_infix(left, infix_op));
     200            6 :     if (infix.has_value()) {
     201            5 :       return infix.value();
     202              :     }
     203           16 :   }
     204              : 
     205           17 :   return left;
     206           22 : }
     207              : 
     208            1 : auto Parser::ParseFunctionCall(const std::string& func_name) -> result_t<expression_t> {
     209            1 :   TRY_RESULT(Expect(token::Type::kLParen));
     210            1 :   TRY_RESULT(NextToken());
     211              : 
     212            1 :   std::vector<utils::Box<expression_t>> args;
     213            3 :   while (curr_.type != token::Type::kRParen) {
     214            2 :     TRY_RESULT(const auto exp, ParseExpression());
     215              : 
     216            2 :     if (curr_.type == token::Type::kComma) {
     217            0 :       TRY_RESULT(NextToken());
     218            0 :     }
     219              : 
     220            2 :     args.emplace_back(utils::Box{exp});
     221            2 :   }
     222              : 
     223            1 :   TRY_RESULT(Expect(token::Type::kRParen));
     224            1 :   TRY_RESULT(NextToken());  // Skip closing paren
     225              : 
     226            1 :   return FunctionCallExpression{.name = func_name, .args = args};
     227            1 : }
     228              : 
     229          119 : auto Parser::NextToken() -> result_t<void> {
     230          119 :   curr_ = peek_;
     231          119 :   TRY_RESULT(peek_, lexer_.NextToken());
     232          119 :   return {};
     233          119 : }
     234              : 
     235            0 : auto Parser::ExpectPeek(token::Type tok_type) -> result_t<void> {
     236            0 :   if (peek_.type != tok_type) {
     237            0 :     return result::Err(
     238              :         Error::ExpectedToken,
     239            0 :         std::format("Expected {}, but got: {}", tok_type, peek_.type));
     240              :   }
     241              : 
     242            0 :   return {};
     243              : }
     244              : 
     245           47 : auto Parser::Expect(token::Type tok_type, const std::source_location& loc)
     246              :     -> result_t<void> {
     247           47 :   if (curr_.type != tok_type) {
     248            0 :     return result::Err(
     249              :         Error::ExpectedToken,
     250            0 :         std::format("Expected {}, but got: {}", tok_type, curr_.type), loc);
     251              :   }
     252              : 
     253           47 :   return {};
     254              : }
     255              : 
     256              : }  // namespace stax::parser
        

Generated by: LCOV version 2.3.2-1