12#include <fmt/format.h>
14#include <libassert/assert.hpp>
15#include <range/v3/algorithm/any_of.hpp>
16#include <range/v3/algorithm/contains.hpp>
17#include <range/v3/algorithm/copy.hpp>
18#include <range/v3/algorithm/count.hpp>
19#include <range/v3/algorithm/count_if.hpp>
20#include <range/v3/algorithm/equal.hpp>
21#include <range/v3/algorithm/find.hpp>
22#include <range/v3/algorithm/find_if.hpp>
23#include <range/v3/algorithm/find_if_not.hpp>
24#include <range/v3/algorithm/sort.hpp>
25#include <range/v3/range/access.hpp>
26#include <range/v3/range/concepts.hpp>
27#include <range/v3/view/any_view.hpp>
28#include <range/v3/view/enumerate.hpp>
29#include <range/v3/view/take.hpp>
30#include <range/v3/view/take_while.hpp>
31#include <range/v3/view/transform.hpp>
234 switch (token_kind) {
238 return "StringLiteral";
239 case RawStringLiteral:
240 return "RawStringLiteral";
242 return "CharLiteral";
244 return "IntBinLiteral";
246 return "IntOctLiteral";
248 return "IntDecLiteral";
250 return "IntHexLiteral";
252 return "FloatLiteral";
253 case FloatHexLiteral:
254 return "FloatHexLiteral";
262 return "EndDelimiter";
264 UNREACHABLE(token_kind);
292 const char*
what() const noexcept
override {
return get_pretty().c_str(); }
294 constexpr const std::string&
msg() const noexcept {
return msg_; }
296 constexpr const std::optional<std::string>&
stream_state() const noexcept {
return stream_state_; }
298 constexpr const std::optional<Token::Kind>&
token_kind() const noexcept {
return token_kind_; }
301 std::string
pretty()
const {
return get_pretty(); }
304 std::string& get_pretty()
const {
305 static std::string pretty_cache;
307 if (pretty_cache.empty()) {
308 std::string_view stream_state_str = stream_state_ ? std::string_view{*stream_state_} :
"<unknown>";
309 std::string_view token_kind_str = token_kind_ ?
format_as(*token_kind_) :
"<unknown>";
311 pretty_cache = fmt::format(
"{} : state={:?}, token={}", msg_, stream_state_str, token_kind_str);
320 std::optional<std::string> stream_state_;
322 std::optional<Token::Kind> token_kind_;
346[[nodiscard]]
constexpr std::string_view
substr_to(std::string_view str,
auto token) {
347 auto pos = str.find(token);
348 return str.substr(0, pos);
351static_assert(
substr_to(
"abcd",
'c') ==
"ab");
352static_assert(
substr_to(
"abc ef ab",
"ef") ==
"abc ");
358[[nodiscard]]
constexpr std::string_view
substr_to(std::string_view str, std::invocable<char>
auto pred) {
359 auto iter = ranges::find_if(str, pred);
361 if (iter == str.end()) {
365 return str.substr(0,
static_cast<std::size_t
>(iter - str.begin()));
368static_assert(
substr_to(
"abc0123 ab", isdigit) ==
"abc");
369static_assert(
substr_to(
"0123 ab", std::not_fn(isdigit)) ==
"0123");
373[[nodiscard]]
constexpr std::string_view
substr_past(std::string_view str,
auto what) {
374 std::size_t skip_len{};
375 if constexpr (std::invocable<
decltype(what),
char>) {
376 skip_len =
substr_to(str, std::not_fn(what)).size();
378 skip_len = str.find(what) + 1;
381 return str.substr(skip_len);
384static_assert(
substr_past(
"abc0123 ab", isalpha) ==
"0123 ab");
385static_assert(
substr_past(
"abc0123 ab", isalnum) ==
" ab");
386static_assert(
substr_past(
"abc0123 ab", isdigit) ==
"abc0123 ab");
409 return prevs.back().kind;
416 constexpr explicit(
false)
Stream(
const char*
string)
419 constexpr explicit(
false)
Stream(std::string_view
string)
427 constexpr std::size_t
size()
const {
return str().size(); }
429 constexpr bool empty()
const {
return str().empty(); }
441 constexpr std::string_view
peek(std::size_t n)
const {
443 throw ParsingError(fmt::format(
"called peek(n) where n > size() ({} > {})", n,
size()));
445 return str().substr(0, n);
453 constexpr std::string_view
peek_while(std::invocable<char>
auto pred)
const {
459 return str().substr(0,
str().
size() - past_sz);
466 constexpr std::string_view
consume(std::size_t n) {
476 template <
typename StrLike>
477 requires std::convertible_to<StrLike, std::string_view> || std::same_as<StrLike, char>
483 if constexpr (std::same_as<char,
decltype(
str)>) {
486 idx_ += std::string_view{
str}.size();
497 if constexpr (std::same_as<char,
decltype(what)>) {
500 idx_ += std::string_view{what}.size();
531 return !
str().empty() && tolower(
str().front()) == tolower(chr);
535 return size() >=
string.size() &&
536 ranges::equal(
string,
str().substr(0,
string.
size()), std::equal_to{}, tolower, tolower);
539 constexpr std::string_view
str()
const {
return str_.substr(idx_); }
542 std::string_view str_;
543 std::size_t idx_ = 0;
546template <std::
size_t N>
548 std::array<std::string_view, N> array = std::to_array(arr);
550 ranges::sort(array, std::greater{}, &std::string_view::size);
559 "+",
"-",
"*",
"/",
"%",
560 "<<",
">>",
"^",
"|",
"&",
562 "==",
"!=",
"<=>",
"<",
"<=",
">",
">=",
563 "=",
"+=",
"-=",
"*=",
"/=",
"%=",
"<<=",
">>=",
"&=",
"^=",
"|="
572 "throw",
"sizeof",
"alignof",
"new",
"delete",
574 "const_cast",
"static_cast",
"dynamic_cast",
"reinterpret_cast",
592 if (str.empty() || str.size() > 2) {
596 if (str.size() == 1 && str.starts_with(
'L')) {
600 if (tolower(str.at(0)) ==
'u') {
601 return str.size() == 1 || str.at(1) ==
'8';
613 if (str.empty() || str.size() > 3) {
618 if (tolower(str.front()) ==
'u') {
619 str.remove_prefix(1);
627 if (tolower(str.front()) ==
'l') {
628 str.remove_prefix(1);
635 return str.size() == 1 && tolower(str.front()) ==
'l';
649 return [first =
true](
char c)
mutable {
650 if (std::exchange(first,
false) && !isalpha(c) && c !=
'_') {
654 return isalnum(c) || c ==
'_';
660 return isdigit(c) || c ==
'\'';
665 return isxdigit(c) || c ==
'\'';
676template <Token::Kind Kind>
686 std::string_view potential_strlike_prefix = stream.
peek_until(
'"');
689 if (potential_strlike_prefix.empty()) {
706 std::string_view potential_strlike_prefix = stream.
peek_until(
"R\"");
709 if (potential_strlike_prefix.empty()) {
726 std::string_view potential_strlike_prefix = stream.
peek_until(
'\'');
729 if (potential_strlike_prefix.empty()) {
747 return leading ==
"true" || leading ==
"false";
764 return stream.
size() > 2 && isdigit(stream.
str().at(2));
776 std::string_view after_prefix = stream.
str().substr(2);
778 if (!isxdigit(after_prefix.front())) {
813 if (stream.
empty() || !isdigit(stream.
peek())) {
882 if (!isdigit(stream.
peek())) {
931 if (full_token.empty()) {
953 char tok = stream.
peek();
960 if (tok ==
'{' || tok ==
'}') {
971 auto last_grouping_opening = ranges::find(stream.
ctx.
prevs,
Token{.kind = Grouping, .str =
"("});
973 if (last_grouping_opening == ranges::end(stream.
ctx.
prevs)) {
977 auto num_operator_opening = ranges::count(stream.
ctx.
prevs,
Token{.kind = Operator, .str =
"("});
978 auto num_operator_closing = ranges::count(stream.
ctx.
prevs,
Token{.kind = Operator, .str =
")"});
981 if (num_operator_closing > num_operator_opening) {
982 throw ParsingError(
"closing ')' ops > opening '(' ops", stream.
str(), Grouping);
986 if (num_operator_opening == num_operator_closing) {
990 auto last_operator_opening = ranges::find(stream.
ctx.
prevs,
Token{.kind = Operator, .str =
"("});
992 return last_grouping_opening > last_operator_opening;
1009 auto full_token = stream.
peek_until([](
char c) {
return isalnum(c) || isblank(c) || c ==
'_'; });
1010 if (full_token.size() > 1 &&
1015 auto first_logical_op = std::min(stream.
str().find(
"&&"), stream.
str().find(
"||"));
1016 auto first_opening_paren = stream.
str().find(
'(');
1017 auto next_closing_angled = stream.
str().find(
'>');
1019 if (next_closing_angled > first_logical_op || next_closing_angled > first_opening_paren) {
1023 auto next_opening_angled = stream.
str().substr(1).find(
'<');
1025 return next_opening_angled > next_closing_angled;
1029 auto num_angled_opening = ranges::count(stream.
ctx.
prevs,
Token{.kind = Grouping, .str =
"<"});
1030 auto num_angled_closing = ranges::count(stream.
ctx.
prevs,
Token{.kind = Grouping, .str =
">"});
1036 if (!std::is_constant_evaluated() && num_angled_closing > num_angled_opening) {
1037 LOG_WARN(
"Parsing error for '<' '>' grouping tokens (# opening < # closing). Context: (o={},c={}) "
1038 "stream={:?}, prevs={}",
1039 num_angled_opening, num_angled_closing, stream.
str(), stream.
ctx.
prevs);
1042 return num_angled_opening > num_angled_closing;
1045 UNREACHABLE(tok, stream, stream.
ctx.
prevs);
1064 ranges::sort(max_munch_tokens, std::greater{}, &std::string_view::size);
1067 auto iter = ranges::find_if(max_munch_tokens, check_stream_starts);
1069 if (iter == ranges::end(max_munch_tokens)) {
1086 if (
Token::Kind kind = stream.
ctx.
prevs.back().kind; kind == Operator || kind == BinaryOperator) {
1107 ranges::sort(max_munch_tokens, std::greater{}, &std::string_view::size);
1111 auto iter = ranges::find_if(max_munch_tokens, check_stream_starts);
1113 if (iter == ranges::end(max_munch_tokens)) {
1138template <Token::Kind Kind>
1152template <Token::Kind Kind>
1162 throw ParsingError(
"matches precondition failed in parse", stream.
str(), StringLiteral);
1165 auto get_res = [init = stream.
str(), &stream] {
return init.substr(0, init.size() - stream.
str().size()); };
1170 auto is_str_end = [prev_backslash =
false](
char c)
mutable {
1171 if (prev_backslash) {
1172 prev_backslash =
false;
1177 prev_backslash =
true;
1204 throw ParsingError(
"matches precondition failed in parse", stream.str(), RawStringLiteral);
1207 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1210 stream.consume_until(
'"');
1214 std::string_view d_char_seq = stream.consume_until(
'(');
1220 while (!stream.consume_through(
')').empty() && !(stream.consume(d_char_seq) && stream.consume(
'"'))) {
1239 throw ParsingError(
"matches precondition failed in parse", stream.str(), CharLiteral);
1242 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1247 stream.consume_through(
'\'');
1249 auto is_chr_end = [prev_backslash =
false](
char c)
mutable {
1250 if (prev_backslash) {
1251 prev_backslash =
false;
1256 prev_backslash =
true;
1262 stream.consume_until(is_chr_end);
1277constexpr bool consume_int_suffix(Stream& stream) {
1279 for (std::size_t len = 3; len >= 1; --len) {
1280 if (len <= stream.size() &&
is_int_suffix(stream.peek(len))) {
1281 stream.consume(len);
1294 throw ParsingError(
"matches precondition failed in parse", stream.str(), IntBinLiteral);
1297 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1301 throw ParsingError(
"0b literal prefix missing", stream.str(), IntBinLiteral);
1306 consume_int_suffix(stream);
1316 throw ParsingError(
"matches precondition failed in parse", stream.str(), IntOctLiteral);
1319 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1322 if (!stream.consume(
'0')) {
1323 throw ParsingError(
"0 literal prefix missing", stream.str(), IntOctLiteral);
1328 consume_int_suffix(stream);
1338 throw ParsingError(
"matches precondition failed in parse", stream.str(), IntDecLiteral);
1341 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1345 consume_int_suffix(stream);
1355 throw ParsingError(
"matches precondition failed in parse", stream.str(), IntHexLiteral);
1358 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1362 throw ParsingError(
"0x literal prefix missing", stream.str(), IntHexLiteral);
1367 consume_int_suffix(stream);
1396 throw ParsingError(
"matches precondition failed in parse", stream.str(), FloatLiteral);
1399 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1403 if (stream.consume(
'.')) {
1407 if (
tolower(stream.peek()) !=
'e') {
1408 throw ParsingError(
"exponent char 'e'/'E' missing", stream.str(), FloatLiteral);
1414 stream.consume(
'+') || stream.consume(
'-');
1420 std::string_view suffix = stream.peek_through(
is_ident_like());
1422 if (suffix.size() == 1) {
1434 throw ParsingError(
"matches precondition failed in parse", stream.str(), FloatHexLiteral);
1437 auto get_res = [init = stream.str(), &stream] {
return init.substr(0, init.size() - stream.str().size()); };
1445 throw ParsingError(
"bad start of hex float literal", stream.str(), FloatHexLiteral);
1451 stream.consume(
'.');
1460 throw ParsingError(
"exponent char 'p'/'P' missing", stream.str(), FloatHexLiteral);
1463 stream.consume(
'+') || stream.consume(
'-');
1470 std::string_view suffix = stream.peek_through(
is_ident_like());
1472 if (suffix.size() == 1) {
1536 throw ParsingError(
"matches precondition failed in parse", stream.str(), BoolLiteral);
1547 throw ParsingError(
"matches precondition failed in parse", stream.str(), Identifier);
1567 throw ParsingError(
"matches precondition failed in parse", stream.str(), Grouping);
1571 static_assert(std::same_as<
decltype(
grouping_tokens)::value_type,
char>);
1573 return stream.consume(1);
1581 throw ParsingError(
"matches precondition failed in parse", stream.str(), BinaryOperator);
1589 ranges::sort(max_munch_tokens, std::greater{}, &std::string_view::size);
1592 const auto* iter = ranges::find_if(max_munch_tokens, check_stream_starts);
1594 if (iter == ranges::end(max_munch_tokens)) {
1595 throw ParsingError(
"no match found in binary operator token list", stream.str(), BinaryOperator);
1598 return stream.consume(iter->size());
1606 throw ParsingError(
"matches precondition failed in parse", stream.str(), Operator);
1615 ranges::sort(max_munch_tokens, std::greater{}, &std::string_view::size);
1618 const auto* iter = ranges::find_if(max_munch_tokens, check_stream_starts);
1620 if (iter == ranges::end(max_munch_tokens)) {
1621 throw ParsingError(
"no match found in operator token list", stream.str(), Operator);
1624 return stream.consume(iter->size());
1628template <std::size_t MaxNumTokens,
Token::Kind... ParsableTokenKinds>
1629constexpr auto parse_all(Stream input_stream) {
1630 std::array<Token, MaxNumTokens> tokens{};
1632 for (std::size_t i = 0;
auto& tok : tokens) {
1634 input_stream.consume_through(isblank);
1636 if (input_stream.empty()) {
1637 tok.kind = EndDelimiter;
1643 ((tok.kind = ParsableTokenKinds,
1647 input_stream.ctx.prevs = std::span(tokens.begin(), ++i);
1650 if (!input_stream.empty()) {
1651 throw ParsingError(
"input stream non-empty after full parse", input_stream.str());
1659template <std::
size_t MaxNumTokens>
1663 return tokenize::parse_all<MaxNumTokens, BoolLiteral, StringLiteral, RawStringLiteral, CharLiteral, IntBinLiteral,
1664 IntOctLiteral, IntDecLiteral, IntHexLiteral, FloatLiteral, FloatHexLiteral, Identifier,
1665 Grouping, BinaryOperator, Operator>(str);
1668template <std::
size_t MaxNumTokens = 1'024>
1677 , num_tokens_{find_end_delim_idx()} {}
1686 ranges::copy(tokens_.begin() +
start, tokens_.begin() +
start + len, result.tokens_.begin());
1687 result.num_tokens_ = len;
1689 auto str_start = result.tokens_.front().str.data() - original_.data();
1690 auto str_len = (result[len - 1].str.data() + result[len - 1].str.size()) - result.tokens_.front().str.data();
1691 result.original_ = original_.substr(str_start, str_len);
1698 constexpr auto size()
const {
return num_tokens_; }
1700 constexpr auto empty()
const {
return num_tokens_ == 0; }
1702 constexpr auto begin()
const {
return tokens_.begin(); }
1704 constexpr auto end()
const {
return tokens_.begin() + num_tokens_; }
1706 constexpr bool operator==(
const ranges::forward_range
auto& other)
const {
return ranges::equal(*
this, other); }
1709 ASSERT(idx < num_tokens_);
1710 return tokens_[idx];
1714 constexpr std::size_t find_end_delim_idx()
const {
1717 if (iter == ranges::end(tokens_)) {
1718 throw ParsingError(
"EndDelimiter missing from token stream");
1721 return gsl::narrow_cast<std::size_t>(iter - ranges::begin(tokens_));
1724 std::string_view original_;
1725 std::array<Token, MaxNumTokens> tokens_;
1726 std::size_t num_tokens_{};
constexpr capable functions from c-style headers
Bad or invalid parse exception type. May indicate an implementation bug, or just an invalid expressio...
Definition expression_inspection.hpp:275
ParsingError(std::string msg, std::string_view stream_state, Token::Kind token_kind)
Definition expression_inspection.hpp:287
constexpr const std::optional< std::string > & stream_state() const noexcept
Definition expression_inspection.hpp:296
constexpr const std::string & msg() const noexcept
Definition expression_inspection.hpp:294
ParsingError(std::string msg, std::string_view stream_state)
Definition expression_inspection.hpp:283
std::string pretty() const
Return a human-readable "pretty" stringified version of the exception.
Definition expression_inspection.hpp:301
ParsingError(std::string msg)
Definition expression_inspection.hpp:280
constexpr const std::optional< Token::Kind > & token_kind() const noexcept
Definition expression_inspection.hpp:298
const char * what() const noexcept override
Definition expression_inspection.hpp:292
Definition expression_inspection.hpp:1670
constexpr Tokenizer subseq(std::size_t start, std::size_t len) const
Definition expression_inspection.hpp:1679
constexpr Tokenizer()=default
constexpr auto empty() const
Definition expression_inspection.hpp:1700
constexpr const Token & operator[](std::size_t idx) const
Definition expression_inspection.hpp:1708
constexpr auto begin() const
Definition expression_inspection.hpp:1702
constexpr std::string_view get_original() const
Definition expression_inspection.hpp:1696
constexpr auto size() const
Definition expression_inspection.hpp:1698
constexpr bool operator==(const ranges::forward_range auto &other) const
Definition expression_inspection.hpp:1706
constexpr auto end() const
Definition expression_inspection.hpp:1704
Definition expression_inspection.hpp:398
constexpr bool consume(StrLike str)
Attempt to consume str at the beginning of the stream, iff it actually exists at the beginning.
Definition expression_inspection.hpp:478
constexpr std::string_view consume(std::size_t n)
Same as peek, except it also mutates the stream.
Definition expression_inspection.hpp:466
constexpr std::string_view peek_through(auto what) const
Definition expression_inspection.hpp:457
constexpr std::size_t size() const
Definition expression_inspection.hpp:427
constexpr std::string_view consume_until(auto what)
Same as peek_until, except it also mutates the stream.
Definition expression_inspection.hpp:507
constexpr std::string_view peek_past(auto what) const
substr_past
Definition expression_inspection.hpp:463
constexpr bool starts_with(auto what) const
Whether the stream starts with what (accepts same as std::string_view::starts_with)
Definition expression_inspection.hpp:528
constexpr std::string_view consume_while(std::invocable< char > auto pred)
Same as peek_while, except it also mutates the stream.
Definition expression_inspection.hpp:521
constexpr Stream(std::string_view string, StreamContext context)
This overload is just used for writing tests.
Definition expression_inspection.hpp:423
constexpr std::string_view peek_while(std::invocable< char > auto pred) const
Definition expression_inspection.hpp:453
constexpr std::string_view str() const
Definition expression_inspection.hpp:539
StreamContext ctx
Definition expression_inspection.hpp:414
constexpr bool starts_with(char chr, CaseInsensitiveTag) const
Definition expression_inspection.hpp:530
constexpr bool consume(auto what, CaseInsensitiveTag)
Definition expression_inspection.hpp:492
constexpr std::string_view peek(std::size_t n) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:441
constexpr bool starts_with(std::string_view string, CaseInsensitiveTag) const
Definition expression_inspection.hpp:534
constexpr bool empty() const
Definition expression_inspection.hpp:429
constexpr char peek() const
Peek at the first character of the stream.
Definition expression_inspection.hpp:432
constexpr std::string_view consume_through(auto what)
Same as peek_through, except it also mutates the stream.
Definition expression_inspection.hpp:514
constexpr std::string_view peek_until(auto what) const
substr_to
Definition expression_inspection.hpp:451
#define LOG_WARN(...)
Definition logging.hpp:43
constexpr char tolower(char c)
Definition cconstexpr.hpp:54
constexpr struct asmgrader::inspection::tokenize::CaseInsensitiveTag case_insensitive
constexpr auto digit_or_sep(char c)
Exactly as named. Sep = '.
Definition expression_inspection.hpp:659
constexpr bool matches< BoolLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:744
constexpr auto xdigit_or_sep(char c)
Exactly as named. Sep = '.
Definition expression_inspection.hpp:664
constexpr bool matches< CharLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:725
constexpr bool matches< BinaryOperator >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:1054
constexpr bool matches< RawStringLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:705
constexpr std::string_view parse(Stream &stream)
Parse the token of Kind from the start of the stream. Assumes that the stream actually starts with a ...
Definition expression_inspection.hpp:1153
constexpr std::string_view test_parse(std::string_view str)
Definition expression_inspection.hpp:1139
constexpr bool is_strlike_prefix(std::string_view str)
Whether the entirety of str is a strlike-prefix See Token::Kind::StringLiteral for details.
Definition expression_inspection.hpp:591
constexpr auto make_rev_size_sorted(const std::string_view(&arr)[N])
Definition expression_inspection.hpp:547
constexpr bool matches< Operator >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:1097
constexpr bool matches< IntOctLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:793
constexpr bool matches< FloatLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:873
constexpr bool matches< FloatHexLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:860
constexpr bool is_int_suffix(std::string_view str)
Whether the entirety of str is an integer-suffix See Token::Kind::IntLiteral for details.
Definition expression_inspection.hpp:612
constexpr bool matches< Identifier >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:927
constexpr auto operator_tokens
Definition expression_inspection.hpp:566
constexpr auto is_ident_like()
Returns a functor to check for an identifier for a stream of characters Does not verify whether the i...
Definition expression_inspection.hpp:648
constexpr auto grouping_tokens
Definition expression_inspection.hpp:581
constexpr auto binary_operator_tokens
Definition expression_inspection.hpp:555
constexpr std::string_view parse< StringLiteral >(Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:1160
constexpr std::string_view substr_past(std::string_view str, auto what)
A substr of str past all characters satisfying pred In essence, performs 'drop while'.
Definition expression_inspection.hpp:373
constexpr bool matches< IntHexLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:771
constexpr bool matches< IntDecLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:812
constexpr std::string_view substr_to(std::string_view str, auto token)
A substr of str up to the first occurrence of token, or the entirety of str if token is not found.
Definition expression_inspection.hpp:346
constexpr bool matches< IntBinLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:759
constexpr bool matches< Grouping >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:952
constexpr bool matches< StringLiteral >(const Stream &stream)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition expression_inspection.hpp:685
constexpr bool matches(const Stream &stream)
Check whether the start of stream matches a token kind Assumes that there is no leading whitespace in...
Definition expression_inspection.hpp:677
Definition expression_inspection.hpp:46
constexpr auto parse_tokens(std::string_view str)
Definition expression_inspection.hpp:1660
constexpr std::string_view format_as(const Token::Kind token_kind)
Definition expression_inspection.hpp:232
Definition byte_array.hpp:94
Token of a very basic C++ expression. The primary use case is for rudemtary console syntax coloring.
Definition expression_inspection.hpp:57
Kind
The kind of token.
Definition expression_inspection.hpp:73
@ Grouping
Imperatively defined as: '{', '}' '(', ')' - when not as a function call '<', '>' - in template conte...
@ EndDelimiter
Deliminates the end of the token sequence. Also serves to obtain a count of the number of token types...
@ Identifier
https://en.cppreference.com/w/cpp/language/identifiers.html
@ BoolLiteral
'true' or 'false'. That's it.
@ BinaryOperator
https://en.cppreference.com/w/cpp/language/operator_precedence.html (Note that, contrary to the title...
@ CharLiteral
https://en.cppreference.com/w/cpp/language/character_literal.html
@ StringLiteral
https://en.cppreference.com/w/cpp/language/string_literal.html
@ IntHexLiteral
https://en.cppreference.com/w/cpp/language/integer_literal.html See IntDecLiteral
@ IntBinLiteral
https://en.cppreference.com/w/cpp/language/integer_literal.html See IntDecLiteral
@ IntDecLiteral
https://en.cppreference.com/w/cpp/language/integer_literal.html
@ Unknown
Under normal cases, this should be impossible. It's a saner option for a default, though,...
@ FloatHexLiteral
https://en.cppreference.com/w/cpp/language/floating_literal.html
@ RawStringLiteral
https://en.cppreference.com/w/cpp/language/string_literal.html
@ FloatLiteral
https://en.cppreference.com/w/cpp/language/floating_literal.html
@ IntOctLiteral
https://en.cppreference.com/w/cpp/language/integer_literal.html See IntDecLiteral This includes '0'
@ Operator
https://en.cppreference.com/w/cpp/language/operator_precedence.html (Note that, contrary to the title...
constexpr bool operator==(const Token &) const =default
std::string_view str
Definition expression_inspection.hpp:227
Kind kind
Definition expression_inspection.hpp:226
Definition expression_inspection.hpp:394
Primarily used to support Token::Kind::Grouping.
Definition expression_inspection.hpp:402
constexpr Token::Kind last_kind() const
Definition expression_inspection.hpp:405
std::span< Token > prevs
Definition expression_inspection.hpp:403
std::size_t start
Start of the block, inclusive i.e. position after the starting delimiter and style spec.
Definition syntax_highlighter.cpp:149
#define N
Definition test_macros.hpp:147