libfly  6.2.2
C++20 utility library for Linux, macOS, and Windows
lexer.hpp
1 #pragma once
2 
3 #include "fly/types/string/concepts.hpp"
4 #include "fly/types/string/detail/classifier.hpp"
5 #include "fly/types/string/detail/traits.hpp"
6 #include "fly/types/string/literals.hpp"
7 
8 #include <cstdint>
9 #include <optional>
10 
11 namespace fly {
12 
13 template <StandardCharacter CharType>
14 class BasicLexer;
15 
16 using Lexer = BasicLexer<char>;
17 using WLexer = BasicLexer<wchar_t>;
18 using Lexer8 = BasicLexer<char8_t>;
19 using Lexer16 = BasicLexer<char16_t>;
20 using Lexer32 = BasicLexer<char32_t>;
21 
29 template <StandardCharacter CharType>
31 {
34  using view_type = typename traits::view_type;
35 
36 public:
44  template <std::size_t N>
45  constexpr explicit BasicLexer(const CharType (&literals)[N]) noexcept;
46 
52  constexpr explicit BasicLexer(view_type view) noexcept;
53 
57  constexpr view_type view() const;
58 
62  constexpr std::size_t position() const;
63 
73  constexpr void set_position(std::size_t position);
74 
84  constexpr std::optional<CharType> peek(std::size_t offset = 0);
85 
92  constexpr std::optional<CharType> consume();
93 
103  constexpr bool consume_if(CharType ch);
104 
112  constexpr std::optional<std::uintmax_t> consume_number();
113 
121  constexpr std::optional<std::uintmax_t> consume_hex_number();
122 
123 private:
135  template <typename Condition>
136  constexpr std::optional<CharType> consume_if(Condition condition);
137 
138  static constexpr const auto s_zero = FLY_CHR(CharType, '0');
139  static constexpr const auto s_upper_a = FLY_CHR(CharType, 'A');
140  static constexpr const auto s_upper_f = FLY_CHR(CharType, 'F');
141  static constexpr const auto s_lower_a = FLY_CHR(CharType, 'a');
142  static constexpr const auto s_lower_f = FLY_CHR(CharType, 'f');
143 
144  const std::size_t m_size;
145  const view_type m_view;
146 
147  std::size_t m_index {0};
148 };
149 
150 //==================================================================================================
151 template <StandardCharacter CharType>
152 template <std::size_t N>
153 constexpr BasicLexer<CharType>::BasicLexer(const CharType (&literals)[N]) noexcept :
154  m_size(classifier::size(literals)),
155  m_view(literals, m_size)
156 {
157 }
158 
159 //==================================================================================================
160 template <StandardCharacter CharType>
161 constexpr BasicLexer<CharType>::BasicLexer(view_type view) noexcept :
162  m_size(view.size()),
163  m_view(std::move(view))
164 {
165 }
166 
167 //==================================================================================================
168 template <StandardCharacter CharType>
169 constexpr auto BasicLexer<CharType>::view() const -> view_type
170 {
171  return m_view;
172 }
173 
174 //==================================================================================================
175 template <StandardCharacter CharType>
176 constexpr std::size_t BasicLexer<CharType>::position() const
177 {
178  return m_index;
179 }
180 
181 //==================================================================================================
182 template <StandardCharacter CharType>
183 constexpr void BasicLexer<CharType>::set_position(std::size_t position)
184 {
185  m_index = position;
186 }
187 
188 //==================================================================================================
189 template <StandardCharacter CharType>
190 constexpr std::optional<CharType> BasicLexer<CharType>::peek(std::size_t offset)
191 {
192  if ((m_index + offset) >= m_size)
193  {
194  return std::nullopt;
195  }
196 
197  return *(m_view.data() + m_index + offset);
198 }
199 
200 //==================================================================================================
201 template <StandardCharacter CharType>
202 constexpr std::optional<CharType> BasicLexer<CharType>::consume()
203 {
204  if (m_index >= m_size)
205  {
206  return std::nullopt;
207  }
208 
209  return *(m_view.data() + m_index++);
210 }
211 
212 //==================================================================================================
213 template <StandardCharacter CharType>
214 constexpr bool BasicLexer<CharType>::consume_if(CharType ch)
215 {
216  if (auto next = peek(); next && (next.value() == ch))
217  {
218  ++m_index;
219  return true;
220  }
221 
222  return false;
223 }
224 
225 //==================================================================================================
226 template <StandardCharacter CharType>
227 constexpr std::optional<std::uintmax_t> BasicLexer<CharType>::consume_number()
228 {
229  bool parsed_number = false;
230  std::uintmax_t number = 0;
231 
232  while (auto ch = consume_if(classifier::is_digit))
233  {
234  parsed_number = true;
235 
236  number *= 10;
237  number += static_cast<std::uintmax_t>(ch.value() - s_zero);
238  }
239 
240  return parsed_number ? std::optional<std::uintmax_t>(number) : std::nullopt;
241 }
242 
243 //==================================================================================================
244 template <StandardCharacter CharType>
245 constexpr std::optional<std::uintmax_t> BasicLexer<CharType>::consume_hex_number()
246 {
247  bool parsed_number = false;
248  std::uintmax_t number = 0;
249 
250  while (auto ch = consume_if(classifier::is_x_digit))
251  {
252  parsed_number = true;
253  number *= 16;
254 
255  if ((ch.value() >= s_upper_a) && (ch.value() <= s_upper_f))
256  {
257  number += static_cast<std::uintmax_t>(ch.value()) - s_upper_a + 0xA;
258  }
259  else if ((ch.value() >= s_lower_a) && (ch.value() <= s_lower_f))
260  {
261  number += static_cast<std::uintmax_t>(ch.value()) - s_lower_a + 0xa;
262  }
263  else
264  {
265  number += static_cast<std::uintmax_t>(ch.value()) - s_zero;
266  }
267  }
268 
269  return parsed_number ? std::optional<std::uintmax_t>(number) : std::nullopt;
270 }
271 
272 //==================================================================================================
273 template <StandardCharacter CharType>
274 template <typename Condition>
275 constexpr std::optional<CharType> BasicLexer<CharType>::consume_if(Condition condition)
276 {
277  if (auto next = peek(); next && condition(next.value()))
278  {
279  return consume();
280  }
281 
282  return std::nullopt;
283 }
284 
285 } // namespace fly
Definition: lexer.hpp:31
constexpr view_type view() const
Definition: lexer.hpp:169
constexpr BasicLexer(const CharType(&literals)[N]) noexcept
Definition: lexer.hpp:153
constexpr std::optional< std::uintmax_t > consume_number()
Definition: lexer.hpp:227
constexpr void set_position(std::size_t position)
Definition: lexer.hpp:183
constexpr std::optional< std::uintmax_t > consume_hex_number()
Definition: lexer.hpp:245
constexpr std::size_t position() const
Definition: lexer.hpp:176
constexpr std::optional< CharType > consume()
Definition: lexer.hpp:202
constexpr bool consume_if(CharType ch)
Definition: lexer.hpp:214
constexpr std::optional< CharType > peek(std::size_t offset=0)
Definition: lexer.hpp:190
Definition: classifier.hpp:19
Definition: traits.hpp:18