LCOV - code coverage report
Current view: top level - staxlib/frontend/src/parser - parser.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 81.2 % 138 112
Test Date: 1980-01-01 00:00:00 Functions: 93.3 % 15 14

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

Generated by: LCOV version 2.3.2-1