HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
tokenizer.hpp
1// Copyright Take Vos 2019-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "strings.hpp"
8#include "small_vector.hpp"
9#include "utility.hpp"
10#include "decimal.hpp"
11#include "exception.hpp"
12#include "parse_location.hpp"
13#include "charconv.hpp"
14#include <chrono>
15#include <memory>
16#include <string>
17#include <string_view>
18#include <charconv>
19#include <array>
20
21namespace hi::inline v1 {
22
23enum class tokenizer_name_t : uint8_t {
24 NotAssigned,
25 ErrorInvalidCharacter,
26 ErrorEOTInBlockComment,
27 ErrorEOTInString,
28 ErrorLFInString,
29
30 Name,
31 StringLiteral,
32 IntegerLiteral,
33 DateLiteral,
34 TimeLiteral,
35 FloatLiteral,
36 Operator, // Operator, or bracket, or other literal text.
37 End
38};
39
40constexpr char const *to_const_string(tokenizer_name_t name) noexcept
41{
42 switch (name) {
43 case tokenizer_name_t::NotAssigned:
44 return "NotAssigned";
45 case tokenizer_name_t::ErrorInvalidCharacter:
46 return "ErrorInvalidCharacter";
47 case tokenizer_name_t::ErrorEOTInBlockComment:
48 return "ErrorEOTInBlockComment";
49 case tokenizer_name_t::ErrorEOTInString:
50 return "ErrorEOTInString";
51 case tokenizer_name_t::ErrorLFInString:
52 return "ErrorLFInString";
53 case tokenizer_name_t::Name:
54 return "Name";
55 case tokenizer_name_t::StringLiteral:
56 return "StringLiteral";
57 case tokenizer_name_t::IntegerLiteral:
58 return "IntegerLiteral";
59 case tokenizer_name_t::DateLiteral:
60 return "DateLiteral";
61 case tokenizer_name_t::TimeLiteral:
62 return "TimeLiteral";
63 case tokenizer_name_t::FloatLiteral:
64 return "FloatLiteral";
65 case tokenizer_name_t::Operator:
66 return "Operator";
67 case tokenizer_name_t::End:
68 return "End";
69 default:
70 hi_no_default();
71 }
72}
73
74inline std::ostream& operator<<(std::ostream& lhs, tokenizer_name_t rhs)
75{
76 return lhs << to_const_string(rhs);
77}
78
79struct token_t;
80} // namespace hi::inline v1
81
82template<typename CharT>
83struct std::formatter<hi::tokenizer_name_t, CharT> : std::formatter<char const *, CharT> {
84 auto format(hi::tokenizer_name_t const& t, auto& fc) const
85 {
86 return std::formatter<char const *, CharT>{}.format(hi::to_const_string(t), fc);
87 }
88};
89
90template<typename CharT>
91struct std::formatter<hi::token_t, CharT> : std::formatter<std::string_view, CharT> {
92 auto format(hi::token_t const& t, auto& fc) const -> decltype(std::formatter<char const *, CharT>{}.format("", fc));
93};
94
95namespace hi::inline v1 {
96
97struct token_t {
98 tokenizer_name_t name = tokenizer_name_t::NotAssigned;
99 std::string value;
100 parse_location location = {};
101 bool is_binary = false;
102 int precedence = 0;
103
104 constexpr ~token_t() = default;
105 constexpr token_t() noexcept = default;
106 constexpr token_t(token_t const& other) noexcept = default;
107 constexpr token_t(token_t&& other) noexcept = default;
108 constexpr token_t& operator=(token_t const& other) noexcept = default;
109 constexpr token_t& operator=(token_t&& other) noexcept = default;
110
111 token_t(tokenizer_name_t name, std::string value) noexcept :
112 name(name), value(std::move(value)), location(), is_binary(false), precedence(0)
113 {
114 }
115
116 operator bool() const noexcept
117 {
118 return name != tokenizer_name_t::NotAssigned;
119 }
120
121 explicit operator long double() const
122 {
123 try {
124 return std::stold(value);
125
126 } catch (...) {
127 throw parse_error(std::format("Could not convert token {} to long double", *this));
128 }
129 }
130
131 explicit operator double() const
132 {
133 try {
134 return std::stod(value);
135
136 } catch (...) {
137 throw parse_error(std::format("Could not convert token {} to double", *this));
138 }
139 }
140
141 explicit operator float() const
142 {
143 try {
144 return std::stof(value);
145
146 } catch (...) {
147 throw parse_error(std::format("Could not convert token {} to float", *this));
148 }
149 }
150
151 template<std::integral T>
152 explicit operator T() const
153 {
154 try {
155 return hi::from_string<T>(value);
156
157 } catch (...) {
158 throw parse_error(std::format("Could not convert token {} to {}", *this, typeid(T).name()));
159 }
160 }
161
162 explicit operator std::string() const noexcept
163 {
164 return value;
165 }
166
167 explicit operator decimal() const
168 {
169 return decimal{value};
170 }
171
172 explicit operator std::chrono::year_month_day() const
173 {
174 hilet parts = split(value, '-');
175 if (parts.size() != 3) {
176 throw parse_error("Expect date to be in the format YYYY-MM-DD");
177 }
178
179 hilet year = std::chrono::year{stoi(parts[0])};
180 hilet month = std::chrono::month{narrow_cast<unsigned int>(stoi(parts[1]))};
181 hilet day = std::chrono::day{narrow_cast<unsigned int>(stoi(parts[2]))};
182 return {year, month, day};
183 }
184
185 std::string repr() const noexcept
186 {
187 std::string r = to_const_string(name);
188 if (value.size() > 0) {
189 r += '\"';
190 r += value;
191 r += '\"';
192 }
193 return r;
194 }
195
196 friend inline std::ostream& operator<<(std::ostream& lhs, token_t const& rhs)
197 {
198 return lhs << rhs.repr();
199 }
200
201 [[nodiscard]] friend bool operator==(token_t const& lhs, token_t const& rhs) noexcept
202 {
203 return (lhs.name == rhs.name) && (lhs.value == rhs.value);
204 }
205
206 [[nodiscard]] friend bool operator==(token_t const& lhs, tokenizer_name_t const& rhs) noexcept
207 {
208 return lhs.name == rhs;
209 }
210
211 [[nodiscard]] friend bool operator==(token_t const& lhs, const char *rhs) noexcept
212 {
213 return lhs.value == rhs;
214 }
215};
216
218using token_iterator = typename token_vector::iterator;
219
220template<typename T>
222 bool found;
223 T value;
224 token_iterator next_token;
225
226 parse_result() noexcept : found(false), value(), next_token() {}
227
228 parse_result(T const& value, token_iterator next_token) : found(true), value(value), next_token(next_token) {}
229
230 operator bool() const noexcept
231 {
232 return found;
233 }
234
235 T const& operator*() const noexcept
236 {
237 return value;
238 }
239};
240
258[[nodiscard]] std::vector<token_t> parseTokens(std::string_view text) noexcept;
259
260[[nodiscard]] std::vector<token_t>
261parseTokens(std::string_view::const_iterator first, std::string_view::const_iterator last) noexcept;
262
263} // namespace hi::inline v1
264
265template<typename CharT>
266auto std::formatter<hi::token_t, CharT>::format(hi::token_t const& t, auto& fc) const
267 -> decltype(std::formatter<char const *, CharT>{}.format("", fc))
268{
269 return std::formatter<std::string_view, CharT>{}.format(t.repr(), fc);
270}
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:15
std::vector< token_t > parseTokens(std::string_view text) noexcept
The HikoGUI namespace.
Definition ascii.hpp:19
Definition decimal.hpp:20
A variant of text.
Definition label.hpp:36
Definition parse_location.hpp:18
Definition tokenizer.hpp:97
Definition tokenizer.hpp:221
T move(T... args)
T size(T... args)
T stold(T... args)