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/module.hpp"
10#include "decimal.hpp"
11#include "parse_location.hpp"
12#include <chrono>
13#include <memory>
14#include <string>
15#include <string_view>
16#include <charconv>
17#include <array>
18
19namespace hi::inline v1 {
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_const_string(tokenizer_name_t name) noexcept
39{
40 switch (name) {
41 case tokenizer_name_t::NotAssigned:
42 return "NotAssigned";
43 case tokenizer_name_t::ErrorInvalidCharacter:
44 return "ErrorInvalidCharacter";
45 case tokenizer_name_t::ErrorEOTInBlockComment:
46 return "ErrorEOTInBlockComment";
47 case tokenizer_name_t::ErrorEOTInString:
48 return "ErrorEOTInString";
49 case tokenizer_name_t::ErrorLFInString:
50 return "ErrorLFInString";
51 case tokenizer_name_t::Name:
52 return "Name";
53 case tokenizer_name_t::StringLiteral:
54 return "StringLiteral";
55 case tokenizer_name_t::IntegerLiteral:
56 return "IntegerLiteral";
57 case tokenizer_name_t::DateLiteral:
58 return "DateLiteral";
59 case tokenizer_name_t::TimeLiteral:
60 return "TimeLiteral";
61 case tokenizer_name_t::FloatLiteral:
62 return "FloatLiteral";
63 case tokenizer_name_t::Operator:
64 return "Operator";
65 case tokenizer_name_t::End:
66 return "End";
67 default:
69 }
70}
71
72inline std::ostream& operator<<(std::ostream& lhs, tokenizer_name_t rhs)
73{
74 return lhs << to_const_string(rhs);
75}
76
77struct token_t;
78} // namespace hi::inline v1
79
80template<typename CharT>
81struct std::formatter<hi::tokenizer_name_t, CharT> : std::formatter<char const *, CharT> {
82 auto format(hi::tokenizer_name_t const& t, auto& fc) const
83 {
84 return std::formatter<char const *, CharT>{}.format(hi::to_const_string(t), fc);
85 }
86};
87
88template<typename CharT>
89struct std::formatter<hi::token_t, CharT> : std::formatter<std::string_view, CharT> {
90 auto format(hi::token_t const& t, auto& fc) const -> decltype(std::formatter<char const *, CharT>{}.format("", fc));
91};
92
93namespace hi::inline v1 {
94
95struct token_t {
96 tokenizer_name_t name = tokenizer_name_t::NotAssigned;
97 std::string value;
98 parse_location location = {};
99 bool is_binary = false;
100 int precedence = 0;
101
102 constexpr ~token_t() = default;
103 constexpr token_t() noexcept = default;
104 constexpr token_t(token_t const& other) noexcept = default;
105 constexpr token_t(token_t&& other) noexcept = default;
106 constexpr token_t& operator=(token_t const& other) noexcept = default;
107 constexpr token_t& operator=(token_t&& other) noexcept = default;
108
109 token_t(tokenizer_name_t name, std::string value) noexcept :
110 name(name), value(std::move(value)), location(), is_binary(false), precedence(0)
111 {
112 }
113
114 operator bool() const noexcept
115 {
116 return name != tokenizer_name_t::NotAssigned;
117 }
118
119 explicit operator long double() const
120 {
121 try {
122 return std::stold(value);
123
124 } catch (...) {
125 throw parse_error(std::format("Could not convert token {} to long double", *this));
126 }
127 }
128
129 explicit operator double() const
130 {
131 try {
132 return std::stod(value);
133
134 } catch (...) {
135 throw parse_error(std::format("Could not convert token {} to double", *this));
136 }
137 }
138
139 explicit operator float() const
140 {
141 try {
142 return std::stof(value);
143
144 } catch (...) {
145 throw parse_error(std::format("Could not convert token {} to float", *this));
146 }
147 }
148
149 template<std::integral T>
150 explicit operator T() const
151 {
152 try {
153 return hi::from_string<T>(value);
154
155 } catch (...) {
156 throw parse_error(std::format("Could not convert token {} to {}", *this, typeid(T).name()));
157 }
158 }
159
160 explicit operator std::string() const noexcept
161 {
162 return value;
163 }
164
165 explicit operator decimal() const
166 {
167 return decimal{value};
168 }
169
170 explicit operator std::chrono::year_month_day() const
171 {
172 hilet parts = split(value, '-');
173 if (parts.size() != 3) {
174 throw parse_error("Expect date to be in the format YYYY-MM-DD");
175 }
176
177 hilet year = std::chrono::year{stoi(parts[0])};
178 hilet month = std::chrono::month{narrow_cast<unsigned int>(stoi(parts[1]))};
179 hilet day = std::chrono::day{narrow_cast<unsigned int>(stoi(parts[2]))};
180 return {year, month, day};
181 }
182
183 std::string repr() const noexcept
184 {
185 std::string r = to_const_string(name);
186 if (value.size() > 0) {
187 r += '\"';
188 r += value;
189 r += '\"';
190 }
191 return r;
192 }
193
194 friend inline std::ostream& operator<<(std::ostream& lhs, token_t const& rhs)
195 {
196 return lhs << rhs.repr();
197 }
198
199 [[nodiscard]] friend bool operator==(token_t const& lhs, token_t const& rhs) noexcept
200 {
201 return (lhs.name == rhs.name) && (lhs.value == rhs.value);
202 }
203
204 [[nodiscard]] friend bool operator==(token_t const& lhs, tokenizer_name_t const& rhs) noexcept
205 {
206 return lhs.name == rhs;
207 }
208
209 [[nodiscard]] friend bool operator==(token_t const& lhs, const char *rhs) noexcept
210 {
211 return lhs.value == rhs;
212 }
213};
214
216using token_iterator = typename token_vector::iterator;
217
218template<typename T>
220 bool found;
221 T value;
222 token_iterator next_token;
223
224 parse_result() noexcept : found(false), value(), next_token() {}
225
226 parse_result(T const& value, token_iterator next_token) : found(true), value(value), next_token(next_token) {}
227
228 operator bool() const noexcept
229 {
230 return found;
231 }
232
233 T const& operator*() const noexcept
234 {
235 return value;
236 }
237};
238
256[[nodiscard]] std::vector<token_t> parseTokens(std::string_view text) noexcept;
257
258[[nodiscard]] std::vector<token_t>
259parseTokens(std::string_view::const_iterator first, std::string_view::const_iterator last) noexcept;
260
261} // namespace hi::inline v1
262
263template<typename CharT>
264auto std::formatter<hi::token_t, CharT>::format(hi::token_t const& t, auto& fc) const
265 -> decltype(std::formatter<char const *, CharT>{}.format("", fc))
266{
267 return std::formatter<std::string_view, CharT>{}.format(t.repr(), fc);
268}
#define hi_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:279
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
std::vector< token_t > parseTokens(std::string_view text) noexcept
geometry/margins.hpp
Definition cache.hpp:11
Definition decimal.hpp:18
Definition parse_location.hpp:18
Definition tokenizer.hpp:95
Definition tokenizer.hpp:219
T move(T... args)
T stold(T... args)