1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4 
5 #pragma once
6 
7 #include <cstdint>
8 #include <type_traits>
9 
10 #include "caf/config.hpp"
11 #include "caf/detail/parser/add_ascii.hpp"
12 #include "caf/detail/parser/chars.hpp"
13 #include "caf/detail/parser/is_char.hpp"
14 #include "caf/detail/parser/is_digit.hpp"
15 #include "caf/detail/parser/sub_ascii.hpp"
16 #include "caf/detail/scope_guard.hpp"
17 #include "caf/pec.hpp"
18 
19 CAF_PUSH_UNUSED_LABEL_WARNING
20 
21 #include "caf/detail/parser/fsm.hpp"
22 
23 namespace caf::detail::parser {
24 
25 /// Reads a number, i.e., on success produces either an `int64_t` or a
26 /// `double`.
27 template <class State, class Consumer>
read_unsigned_integer(State & ps,Consumer && consumer)28 void read_unsigned_integer(State& ps, Consumer&& consumer) {
29   using consumer_type = typename std::decay<Consumer>::type;
30   using value_type = typename consumer_type::value_type;
31   static_assert(std::is_integral<value_type>::value
32                   && std::is_unsigned<value_type>::value,
33                 "expected an unsigned integer type");
34   value_type result = 0;
35   // Computes the result on success.
36   auto g = caf::detail::make_scope_guard([&] {
37     if (ps.code <= pec::trailing_character) {
38       consumer.value(std::move(result));
39     }
40   });
41   // clang-format off
42   // Definition of our parser FSM.
43   start();
44   state(init) {
45     transition(init, " \t")
46     transition(has_plus, '+')
47     epsilon(has_plus)
48   }
49   // "+" or "-" alone aren't numbers.
50   state(has_plus) {
51     transition(zero, '0')
52     epsilon(dec, decimal_chars)
53   }
54   // Disambiguate base.
55   term_state(zero) {
56     transition(start_bin, "bB")
57     transition(start_hex, "xX")
58     epsilon(oct)
59   }
60   // Binary integers.
61   state(start_bin) {
62     epsilon(bin, "01")
63   }
64   term_state(bin) {
65     transition(bin, "01", add_ascii<2>(result, ch), pec::integer_overflow)
66   }
67   // Octal integers.
68   state(start_oct) {
69     epsilon(oct, octal_chars)
70   }
71   term_state(oct) {
72     transition(oct, octal_chars, add_ascii<8>(result, ch),
73                pec::integer_overflow)
74   }
75   // Hexal integers.
76   state(start_hex) {
77     epsilon(hex, hexadecimal_chars)
78   }
79   term_state(hex) {
80     transition(hex, hexadecimal_chars, add_ascii<16>(result, ch),
81                pec::integer_overflow)
82   }
83   // Reads the integer part of the mantissa or a positive decimal integer.
84   term_state(dec) {
85     transition(dec, decimal_chars, add_ascii<10>(result, ch),
86                pec::integer_overflow)
87   }
88   fin();
89   // clang-format on
90 }
91 
92 } // namespace caf::detail::parser
93 
94 #include "caf/detail/parser/fsm_undef.hpp"
95 
96 CAF_POP_WARNINGS
97