LCOV - code coverage report
Current view: top level - src/lexicalAnalysis - lexer.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.9 % 122 95
Test Date: 2025-04-18 15:53:49 Functions: 100.0 % 4 4

            Line data    Source code
       1              : #include "../../inc/lexicalAnalysis/lexer.h"
       2              : 
       3              : #include <fstream>
       4              : #include <iostream>
       5              : 
       6              : namespace nicole {
       7              : 
       8           81 : const Category Lexer::concatCategories() const noexcept {
       9           81 :   std::string pattern{""};
      10         7209 :   for (const auto &category : categories_) {
      11         7209 :     pattern += category.rawPattern() + "|";
      12         7209 :   }
      13           81 :   pattern.pop_back();
      14           81 :   return Category{TokenType::ALL, pattern, false};
      15           81 : }
      16              : 
      17              : const std::expected<void, Error>
      18           81 : Lexer::checkUnmatched(const std::vector<Token> &tokens) const noexcept {
      19           81 :   bool unmatchedFlag{false};
      20           81 :   std::string everyUnmatched{"Unmatched tokens:\n"};
      21         7839 :   for (const auto &TOKEN : tokens) {
      22         7839 :     if (TOKEN.type() == TokenType::UNMATCHED) {
      23           18 :       everyUnmatched += TOKEN.raw() + "\n";
      24           18 :       unmatchedFlag = true;
      25           18 :     }
      26         7839 :   }
      27           81 :   if (unmatchedFlag) {
      28            9 :     return createError(ERROR_TYPE::CHECK_UNMATCHED, everyUnmatched);
      29            9 :   }
      30           72 :   return std::expected<void, Error>{};
      31           81 : }
      32              : 
      33              : const std::expected<std::string, Error>
      34           99 : Lexer::readFile(const std::filesystem::path &fileName) const noexcept {
      35           99 :   const std::regex fileNameFormat{"[a-zA-Z]+[a-zA-Z0-9]*\\." + extension_,
      36           99 :                                   std::regex_constants::optimize};
      37              :   // method fileName returns just the file
      38           99 :   if (!std::regex_match(fileName.filename().string(), fileNameFormat)) {
      39           18 :     return createError(ERROR_TYPE::FILE_EXTENSION,
      40           18 :                        "The file " + fileName.string() +
      41           18 :                            " does not have extension: " + extension_);
      42           18 :   }
      43           81 :   std::fstream file{fileName};
      44           81 :   if (!file.is_open()) {
      45            0 :     const std::string strErr{"The file " + fileName.string() + " is not open"};
      46            0 :     return createError(ERROR_TYPE::FILE_NOT_OPEN,
      47            0 :                        "The file " + fileName.string() + " is not open");
      48            0 :   }
      49           81 :   std::string text{""};
      50           81 :   std::string line{""};
      51         1935 :   while (getline(file, line)) {
      52         1854 :     text += line + "\n";
      53         1854 :   }
      54           81 :   file.close();
      55           81 :   return text;
      56           81 : }
      57              : 
      58              : const std::expected<TokenStream, Error>
      59              : Lexer::analyze(const std::filesystem::path &fileName,
      60           99 :                bool verbose) const noexcept {
      61           99 :   const std::expected<std::string, Error> TEXT{readFile(fileName)};
      62           99 :   if (!TEXT) {
      63           18 :     return createError(TEXT.error());
      64           18 :   }
      65           81 :   const Category expression{concatCategories()};
      66           81 :   std::vector<Token> result{};
      67           81 :   std::string::const_iterator start, end, lastMatchEnd;
      68           81 :   start = TEXT->begin();
      69           81 :   end = TEXT->end();
      70           81 :   lastMatchEnd = start;
      71           81 :   std::match_results<std::string::const_iterator> what;
      72           81 :   std::size_t row{1};
      73           81 :   std::size_t col{1};
      74        12231 :   while (std::regex_search(start, end, what, expression.pattern().pattern())) {
      75        12150 :     if (lastMatchEnd != what[0].first) {
      76           18 :       const std::string UNMATCHED{lastMatchEnd, what[0].first};
      77           18 :       if (verbose) {
      78            0 :         std::cout << "Unmatched: " << UNMATCHED << "\n";
      79            0 :       }
      80              : 
      81           36 :       for (auto it = lastMatchEnd; it != what[0].first; ++it) {
      82           18 :         if (*it == '\n') {
      83            0 :           ++row;
      84            0 :           col = 1;
      85           18 :         } else {
      86           18 :           ++col;
      87           18 :         }
      88           18 :       }
      89              : 
      90           18 :       result.push_back(
      91           18 :           Token{TokenType::UNMATCHED, UNMATCHED, Location{fileName, row, col}});
      92           18 :     }
      93       390042 :     for (const auto &category : categories_) {
      94       390042 :       if (std::regex_match(what[0].str(), category.pattern().pattern())) {
      95        12150 :         if (verbose) {
      96            0 :           std::cout << "Category: " << tokenTypeToString(category.type())
      97            0 :                     << ", Match: " << what[0].str() << " " << row << ":" << col
      98            0 :                     << "\n";
      99            0 :         }
     100        12150 :         if (!category.skip()) {
     101         7821 :           result.push_back(Token{category.type(), what[0].str(),
     102         7821 :                                  Location{fileName, row, col}});
     103         7821 :         }
     104        12150 :         break;
     105        12150 :       }
     106       390042 :     }
     107              : 
     108        47871 :     for (auto it = what[0].first; it != what[0].second; ++it) {
     109        35721 :       if (*it == '\n') {
     110         1854 :         ++row;
     111         1854 :         col = 1;
     112        33867 :       } else {
     113        33867 :         ++col;
     114        33867 :       }
     115        35721 :     }
     116              : 
     117        12150 :     lastMatchEnd = what[0].second; // Update last match end position
     118        12150 :     start = what[0].second;        // update search position
     119        12150 :   }
     120              :   // Check for unmatched tokens after the last match
     121           81 :   if (lastMatchEnd != end) {
     122            0 :     const std::string UNMATCHED{lastMatchEnd, end};
     123            0 :     if (verbose) {
     124            0 :       std::cout << "Unmatched: " << UNMATCHED << "\n";
     125            0 :     }
     126              : 
     127            0 :     for (auto it = lastMatchEnd; it != end; ++it) {
     128            0 :       if (*it == '\n') {
     129            0 :         ++row;
     130            0 :         col = 1;
     131            0 :       } else {
     132            0 :         ++col;
     133            0 :       }
     134            0 :     }
     135              : 
     136            0 :     result.push_back(
     137            0 :         Token{TokenType::UNMATCHED, UNMATCHED, Location{fileName, row, col}});
     138            0 :   }
     139           81 :   const std::expected<void, Error> check{checkUnmatched(result)};
     140           81 :   if (!check) {
     141            9 :     return createError(check.error());
     142            9 :   }
     143           72 :   return TokenStream{result};
     144           81 : }
     145              : 
     146              : } // namespace nicole
        

Generated by: LCOV version 2.0-1