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
|