HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
tokenizer.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/strings.hpp"
7#include "TTauri/Foundation/small_vector.hpp"
8#include "TTauri/Foundation/required.hpp"
9#include "TTauri/Foundation/decimal.hpp"
10#include "TTauri/Foundation/exceptions.hpp"
11#include "TTauri/Foundation/parse_location.hpp"
12#include <date/date.h>
13#include <memory>
14#include <string>
15#include <string_view>
16#include <charconv>
17#include <array>
18
19namespace tt {
20
21enum class tokenizer_name_t : uint8_t {
22 NotAssigned,
23 ErrorInvalidCharacter,
24 ErrorEOTInBlockComment,
25 ErrorEOTInString,
26 ErrorLFInString,
27
28 Name,
29 StringLiteral,
30 IntegerLiteral,
31 DateLiteral,
32 TimeLiteral,
33 FloatLiteral,
34 Operator, // Operator, or bracket, or other literal text.
35 End
36};
37
38constexpr char const *to_string(tokenizer_name_t name) noexcept {
39 switch (name) {
40 case tokenizer_name_t::NotAssigned: return "NotAssigned";
41 case tokenizer_name_t::ErrorInvalidCharacter: return "ErrorInvalidCharacter";
42 case tokenizer_name_t::ErrorEOTInBlockComment: return "ErrorEOTInBlockComment";
43 case tokenizer_name_t::ErrorEOTInString: return "ErrorEOTInString";
44 case tokenizer_name_t::ErrorLFInString: return "ErrorLFInString";
45 case tokenizer_name_t::Name: return "Name";
46 case tokenizer_name_t::StringLiteral: return "StringLiteral";
47 case tokenizer_name_t::IntegerLiteral: return "IntegerLiteral";
48 case tokenizer_name_t::DateLiteral: return "DateLiteral";
49 case tokenizer_name_t::TimeLiteral: return "TimeLiteral";
50 case tokenizer_name_t::FloatLiteral: return "FloatLiteral";
51 case tokenizer_name_t::Operator: return "Operator";
52 case tokenizer_name_t::End: return "End";
53 default: tt_no_default;
54 }
55}
56
57inline std::ostream &operator<<(std::ostream &lhs, tokenizer_name_t rhs)
58{
59 return lhs << to_string(rhs);
60}
61
62struct token_t {
63 tokenizer_name_t name;
64 std::string value;
65 parse_location location;
66 bool is_binary;
67 int precedence;
68
69 token_t() noexcept :
70 name(tokenizer_name_t::NotAssigned), value(), location(), is_binary(false), precedence(0) {}
71
72 token_t(tokenizer_name_t name, std::string value) noexcept :
73 name(name), value(std::move(value)), location(), is_binary(false), precedence(0) {}
74
75 token_t(token_t const &other) noexcept :
76 name(other.name), value(other.value), location(other.location), is_binary(other.is_binary), precedence(other.precedence) {}
77
78 token_t(token_t &&other) noexcept :
79 name(other.name), value(std::move(other.value)), location(std::move(other.location)), is_binary(other.is_binary), precedence(other.precedence) {}
80
81 token_t &operator=(token_t const &other) noexcept {
82 if (this != &other) {
83 name = other.name;
84 value = other.value;
85 location = other.location;
86 is_binary = other.is_binary;
87 precedence = other.precedence;
88 }
89 return *this;
90 }
91
92 token_t &operator=(token_t &&other) noexcept {
93 using std::move;
94 name = move(other.name);
95 value = move(other.value);
96 location = move(other.location);
97 is_binary = move(other.is_binary);
98 precedence = move(other.precedence);
99 return *this;
100 }
101
102 operator bool () const noexcept {
103 return name != tokenizer_name_t::NotAssigned;
104 }
105
106 explicit operator long double () const {
107 try {
108 return std::stold(value);
109 } catch(...) {
110 TTAURI_THROW(parse_error("Could not convert token {} to long double", *this));
111 }
112 }
113
114 explicit operator double () const {
115 try {
116 return std::stod(value);
117 } catch(...) {
118 TTAURI_THROW(parse_error("Could not convert token {} to double", *this));
119 }
120 }
121
122 explicit operator float () const {
123 try {
124 return std::stof(value);
125 } catch(...) {
126 TTAURI_THROW(parse_error("Could not convert token {} to float", *this));
127 }
128 }
129
130 explicit operator signed long long () const {
131 try {
132 return std::stoll(value);
133 } catch(...) {
134 TTAURI_THROW(parse_error("Could not convert token {} to signed long long", *this));
135 }
136 }
137
138 explicit operator signed long () const {
139 auto v = static_cast<signed long long>(*this);
141 TTAURI_THROW(parse_error("Could not convert token {} to signed long", *this))
142 }
143 return static_cast<signed long>(v);
144 }
145
146 explicit operator signed int () const {
147 auto v = static_cast<signed long long>(*this);
149 TTAURI_THROW(parse_error("Could not convert token {} to signed int", *this))
150 }
151 return static_cast<signed int>(v);
152 }
153
154 explicit operator signed short () const {
155 auto v = static_cast<signed long long>(*this);
157 TTAURI_THROW(parse_error("Could not convert token {} to signed short", *this))
158 }
159 return static_cast<signed short>(v);
160 }
161
162 explicit operator signed char () const {
163 auto v = static_cast<signed long long>(*this);
165 TTAURI_THROW(parse_error("Could not convert token {} to signed char", *this))
166 }
167 return static_cast<signed char>(v);
168 }
169
170 explicit operator unsigned long long () const {
171 auto v = static_cast<signed long long>(*this);
172 if (v < 0) {
173 TTAURI_THROW(parse_error("Could not convert token {} to unsigned long long", *this))
174 }
175 return static_cast<unsigned long long>(v);
176 }
177
178 explicit operator unsigned long () const {
179 auto v = static_cast<signed long long>(*this);
180 if (v < 0 || v > std::numeric_limits<unsigned long>::max()) {
181 TTAURI_THROW(parse_error("Could not convert token {} to unsigned long", *this))
182 }
183 return static_cast<unsigned long>(v);
184 }
185
186 explicit operator unsigned int () const {
187 auto v = static_cast<signed long long>(*this);
188 if (v < 0 || v > std::numeric_limits<unsigned int>::max()) {
189 TTAURI_THROW(parse_error("Could not convert token {} to unsigned int", *this))
190 }
191 return static_cast<unsigned int>(v);
192 }
193
194 explicit operator unsigned short () const {
195 auto v = static_cast<signed long long>(*this);
196 if (v < 0 || v > std::numeric_limits<unsigned short>::max()) {
197 TTAURI_THROW(parse_error("Could not convert token {} to unsigned short", *this))
198 }
199 return static_cast<unsigned short>(v);
200 }
201
202 explicit operator unsigned char () const {
203 auto v = static_cast<signed long long>(*this);
204 if (v < 0 || v > std::numeric_limits<unsigned char>::max()) {
205 TTAURI_THROW(parse_error("Could not convert token {} to unsigned char", *this))
206 }
207 return static_cast<unsigned char>(v);
208 }
209
210 explicit operator std::string () const noexcept {
211 return value;
212 }
213
214 explicit operator decimal () const {
215 return decimal{value};
216 }
217
218 explicit operator date::year_month_day () const {
219 ttlet parts = split(value, "-");
220 if (parts.size() != 3) {
221 TTAURI_THROW(parse_error("Expect date to be in the format YYYY-MM-DD"));
222 }
223
224 ttlet year = date::year{stoi(parts[0])};
225 ttlet month = date::month{numeric_cast<unsigned int>(stoi(parts[1]))};
226 ttlet day = date::day{numeric_cast<unsigned int>(stoi(parts[2]))};
227 return {year, month, day};
228 }
229
230 std::string repr() const noexcept {
231 std::string r = to_string(name);
232 if (value.size() > 0) {
233 r += '\"';
234 r += value;
235 r += '\"';
236 }
237 return r;
238 }
239
240 friend inline std::ostream &operator<<(std::ostream &lhs, token_t const &rhs)
241 {
242 return lhs << rhs.repr();
243 }
244
245 [[nodiscard]] friend tt_force_inline bool operator==(token_t const &lhs, token_t const &rhs) noexcept {
246 return (lhs.name == rhs.name) && (lhs.value == rhs.value);
247 }
248
249 [[nodiscard]] friend tt_force_inline bool operator==(token_t const &lhs, tokenizer_name_t const &rhs) noexcept {
250 return lhs.name == rhs;
251 }
252
253 [[nodiscard]] friend tt_force_inline bool operator!=(token_t const &lhs, tokenizer_name_t const &rhs) noexcept {
254 return !(lhs == rhs);
255 }
256
257 [[nodiscard]] friend tt_force_inline bool operator==(token_t const &lhs, const char *rhs) noexcept {
258 return lhs.value == rhs;
259 }
260
261 [[nodiscard]] friend tt_force_inline bool operator!=(token_t const &lhs, const char *rhs) noexcept {
262 return !(lhs == rhs);
263 }
264
265};
266
268using token_iterator = typename token_vector::iterator;
269
270template<typename T>
272 bool found;
273 T value;
274 token_iterator next_token;
275
276 parse_result() noexcept :
277 found(false), value(), next_token() {}
278
279 parse_result(T const &value, token_iterator next_token) :
280 found(true), value(value), next_token(next_token) {}
281
282 operator bool () const noexcept {
283 return found;
284 }
285
286 T const &operator*() const noexcept {
287 return value;
288 }
289};
290
291
292
310[[nodiscard]] std::vector<token_t> parseTokens(std::string_view text) noexcept;
311
312[[nodiscard]] std::vector<token_t> parseTokens(std::string_view::const_iterator first, std::string_view::const_iterator last) noexcept;
313
314
315
316}
317
Definition decimal.hpp:18
Definition exceptions.hpp:154
Definition parse_location.hpp:15
Definition tokenizer.hpp:62
Definition tokenizer.hpp:271
T move(T... args)
T size(T... args)
T stold(T... args)
T stoll(T... args)
T to_string(T... args)