1882 parser(std::istream& stream) : input_(stream)
1895 std::shared_ptr<table> root = make_table();
1899 while (detail::getline(input_, line_))
1902 auto it = line_.begin();
1903 auto end = line_.end();
1904 consume_whitespace(it, end);
1905 if (it == end || *it ==
'#')
1909 curr_table = root.
get();
1910 parse_table(it, end, curr_table);
1914 parse_key_value(it, end, curr_table);
1915 consume_whitespace(it, end);
1916 eol_or_comment(it, end);
1924 __declspec(noreturn)
1925#elif defined __GNUC__
1926 __attribute__((noreturn))
1928 void throw_parse_exception(
const std::string& err)
1933 void parse_table(std::string::iterator& it,
1934 const std::string::iterator& end, table*& curr_table)
1939 throw_parse_exception(
"Unexpected end of table");
1941 parse_table_array(it, end, curr_table);
1943 parse_single_table(it, end, curr_table);
1946 void parse_single_table(std::string::iterator& it,
1947 const std::string::iterator& end,
1950 if (it == end || *it ==
']')
1951 throw_parse_exception(
"Table name cannot be empty");
1953 std::string full_table_name;
1954 bool inserted =
false;
1956 auto key_end = [](
char c) {
return c ==
']'; };
1958 auto key_part_handler = [&](
const std::string& part) {
1960 throw_parse_exception(
"Empty component of table name");
1962 if (!full_table_name.empty())
1963 full_table_name +=
'.';
1964 full_table_name += part;
1966 if (curr_table->contains(part))
1969 auto b = curr_table->get(part);
1972 std::shared_ptr<base> b = curr_table->get(part);
1975 curr_table =
static_cast<table*
>(b.get());
1976 else if (b->is_table_array())
1977 curr_table = std::static_pointer_cast<table_array>(b)
1982 throw_parse_exception(
"Key " + full_table_name
1983 +
"already exists as a value");
1988 curr_table->insert(part, make_table());
1989 curr_table =
static_cast<table*
>(curr_table->get(part).get());
1993 key_part_handler(parse_key(it, end, key_end, key_part_handler));
1996 throw_parse_exception(
1997 "Unterminated table declaration; did you forget a ']'?");
2001 std::string errmsg{
"Unexpected character in table definition: "};
2005 throw_parse_exception(errmsg);
2012 = [](
const std::pair<
const std::string&,
2013 const std::shared_ptr<base>&>& p) {
2014 return p.second->is_value();
2021 if (curr_table->empty()
2022 || std::any_of(curr_table->begin(), curr_table->end(),
2025 throw_parse_exception(
"Redefinition of table "
2031 consume_whitespace(it, end);
2032 eol_or_comment(it, end);
2035 void parse_table_array(std::string::iterator& it,
2036 const std::string::iterator& end, table*& curr_table)
2039 if (it == end || *it ==
']')
2040 throw_parse_exception(
"Table array name cannot be empty");
2042 auto key_end = [](
char c) {
return c ==
']'; };
2044 std::string full_ta_name;
2045 auto key_part_handler = [&](
const std::string& part) {
2047 throw_parse_exception(
"Empty component of table array name");
2049 if (!full_ta_name.empty())
2050 full_ta_name +=
'.';
2051 full_ta_name += part;
2053 if (curr_table->contains(part))
2056 auto b = curr_table->get(part);
2059 std::shared_ptr<base> b = curr_table->get(part);
2065 if (it != end && *it ==
']')
2067 if (!b->is_table_array())
2069 throw_parse_exception(
"Key " + full_ta_name
2070 +
" is not a table array");
2073 auto v = b->as_table_array();
2077 throw_parse_exception(
"Static array " + full_ta_name
2078 +
" cannot be appended to");
2081 v->get().push_back(make_table());
2082 curr_table = v->get().back().get();
2088 curr_table =
static_cast<table*
>(b.get());
2089 else if (b->is_table_array())
2090 curr_table = std::static_pointer_cast<table_array>(b)
2095 throw_parse_exception(
"Key " + full_ta_name
2096 +
" already exists as a value");
2104 if (it != end && *it ==
']')
2106 curr_table->insert(part, make_table_array());
2107 auto arr = std::static_pointer_cast<table_array>(
2108 curr_table->get(part));
2109 arr->get().push_back(make_table());
2110 curr_table = arr->get().back().get();
2116 curr_table->insert(part, make_table());
2118 =
static_cast<table*
>(curr_table->get(part).get());
2123 key_part_handler(parse_key(it, end, key_end, key_part_handler));
2126 auto eat = make_consumer(it, end, [
this]() {
2127 throw_parse_exception(
"Unterminated table array name");
2132 consume_whitespace(it, end);
2133 eol_or_comment(it, end);
2136 void parse_key_value(std::string::iterator& it, std::string::iterator& end,
2139 auto key_end = [](
char c) {
return c ==
'='; };
2141 auto key_part_handler = [&](
const std::string& part) {
2145 if (curr_table->contains(part))
2147 auto val = curr_table->get(part);
2148 if (val->is_table())
2150 curr_table =
static_cast<table*
>(val.get());
2154 throw_parse_exception(
"Key " + part
2155 +
" already exists as a value");
2160 auto newtable = make_table();
2161 curr_table->insert(part, newtable);
2162 curr_table = newtable.get();
2166 auto key = parse_key(it, end, key_end, key_part_handler);
2168 if (curr_table->contains(key))
2169 throw_parse_exception(
"Key " + key +
" already present");
2170 if (it == end || *it !=
'=')
2171 throw_parse_exception(
"Value must follow after a '='");
2173 consume_whitespace(it, end);
2174 curr_table->insert(key, parse_value(it, end));
2175 consume_whitespace(it, end);
2178 template <
class KeyEndFinder,
class KeyPartHandler>
2180 parse_key(std::string::iterator& it,
const std::string::iterator& end,
2181 KeyEndFinder&& key_end, KeyPartHandler&& key_part_handler)
2184 while (it != end && !key_end(*it))
2186 auto part = parse_simple_key(it, end);
2187 consume_whitespace(it, end);
2189 if (it == end || key_end(*it))
2196 std::string errmsg{
"Unexpected character in key: "};
2200 throw_parse_exception(errmsg);
2203 key_part_handler(part);
2209 throw_parse_exception(
"Unexpected end of key");
2212 std::string parse_simple_key(std::string::iterator& it,
2213 const std::string::iterator& end)
2215 consume_whitespace(it, end);
2218 throw_parse_exception(
"Unexpected end of key (blank key?)");
2220 if (*it ==
'"' || *it ==
'\'')
2222 return string_literal(it, end, *it);
2226 auto bke = std::find_if(it, end, [](
char c) {
2227 return c ==
'.' || c ==
'=' || c ==
']';
2229 return parse_bare_key(it, bke);
2233 std::string parse_bare_key(std::string::iterator& it,
2234 const std::string::iterator& end)
2238 throw_parse_exception(
"Bare key missing name");
2243 consume_backwards_whitespace(key_end, it);
2245 std::string key{it, key_end};
2247 if (std::find(it, key_end,
'#') != key_end)
2249 throw_parse_exception(
"Bare key " + key +
" cannot contain #");
2252 if (std::find_if(it, key_end,
2253 [](
char c) {
return c ==
' ' || c ==
'\t'; })
2256 throw_parse_exception(
"Bare key " + key
2257 +
" cannot contain whitespace");
2260 if (std::find_if(it, key_end,
2261 [](
char c) {
return c ==
'[' || c ==
']'; })
2264 throw_parse_exception(
"Bare key " + key
2265 +
" cannot contain '[' or ']'");
2272 enum class parse_type
2286 std::shared_ptr<base> parse_value(std::string::iterator& it,
2287 std::string::iterator& end)
2289 parse_type type = determine_value_type(it, end);
2292 case parse_type::STRING:
2293 return parse_string(it, end);
2294 case parse_type::LOCAL_TIME:
2295 return parse_time(it, end);
2296 case parse_type::LOCAL_DATE:
2297 case parse_type::LOCAL_DATETIME:
2298 case parse_type::OFFSET_DATETIME:
2299 return parse_date(it, end);
2300 case parse_type::INT:
2301 case parse_type::FLOAT:
2302 return parse_number(it, end);
2303 case parse_type::BOOL:
2304 return parse_bool(it, end);
2305 case parse_type::ARRAY:
2306 return parse_array(it, end);
2307 case parse_type::INLINE_TABLE:
2308 return parse_inline_table(it, end);
2310 throw_parse_exception(
"Failed to parse value");
2314 parse_type determine_value_type(
const std::string::iterator& it,
2315 const std::string::iterator& end)
2319 throw_parse_exception(
"Failed to parse value type");
2321 if (*it ==
'"' || *it ==
'\'')
2323 return parse_type::STRING;
2325 else if (is_time(it, end))
2327 return parse_type::LOCAL_TIME;
2329 else if (
auto dtype = date_type(it, end))
2333 else if (is_number(*it) || *it ==
'-' || *it ==
'+'
2334 || (*it ==
'i' && it + 1 != end && it[1] ==
'n'
2335 && it + 2 != end && it[2] ==
'f')
2336 || (*it ==
'n' && it + 1 != end && it[1] ==
'a'
2337 && it + 2 != end && it[2] ==
'n'))
2339 return determine_number_type(it, end);
2341 else if (*it ==
't' || *it ==
'f')
2343 return parse_type::BOOL;
2345 else if (*it ==
'[')
2347 return parse_type::ARRAY;
2349 else if (*it ==
'{')
2351 return parse_type::INLINE_TABLE;
2353 throw_parse_exception(
"Failed to parse value type");
2356 parse_type determine_number_type(
const std::string::iterator& it,
2357 const std::string::iterator& end)
2361 if (*check_it ==
'-' || *check_it ==
'+')
2364 if (check_it == end)
2365 throw_parse_exception(
"Malformed number");
2367 if (*check_it ==
'i' || *check_it ==
'n')
2368 return parse_type::FLOAT;
2370 while (check_it != end && is_number(*check_it))
2372 if (check_it != end && *check_it ==
'.')
2375 while (check_it != end && is_number(*check_it))
2377 return parse_type::FLOAT;
2381 return parse_type::INT;
2385 std::shared_ptr<value<std::string>> parse_string(std::string::iterator& it,
2386 std::string::iterator& end)
2389 assert(delim ==
'"' || delim ==
'\'');
2395 if (check_it != end && *check_it == delim)
2398 if (check_it != end && *check_it == delim)
2401 return parse_multiline_string(it, end, delim);
2404 return make_value<std::string>(string_literal(it, end, delim));
2407 std::shared_ptr<value<std::string>>
2408 parse_multiline_string(std::string::iterator& it,
2409 std::string::iterator& end,
char delim)
2411 std::stringstream ss;
2413 auto is_ws = [](
char c) {
return c ==
' ' || c ==
'\t'; };
2415 bool consuming =
false;
2416 std::shared_ptr<value<std::string>> ret;
2418 auto handle_line = [&](std::string::iterator& local_it,
2419 std::string::iterator& local_end) {
2422 local_it = std::find_if_not(local_it, local_end, is_ws);
2425 if (local_it == local_end)
2431 while (local_it != local_end)
2434 if (delim ==
'"' && *local_it ==
'\\')
2436 auto check = local_it;
2440 consume_whitespace(check, local_end);
2441 if (check == local_end)
2447 ss << parse_escape_code(local_it, local_end);
2452 if (std::distance(local_it, local_end) >= 3)
2454 auto check = local_it;
2456 if (*check++ == delim && *check++ == delim
2457 && *check++ == delim)
2460 ret = make_value<std::string>(ss.str());
2470 handle_line(it, end);
2475 while (detail::getline(input_, line_))
2482 handle_line(it, end);
2491 throw_parse_exception(
"Unterminated multi-line basic string");
2494 std::string string_literal(std::string::iterator& it,
2495 const std::string::iterator& end,
char delim)
2502 if (delim ==
'"' && *it ==
'\\')
2504 val += parse_escape_code(it, end);
2506 else if (*it == delim)
2509 consume_whitespace(it, end);
2517 throw_parse_exception(
"Unterminated string literal");
2520 std::string parse_escape_code(std::string::iterator& it,
2521 const std::string::iterator& end)
2525 throw_parse_exception(
"Invalid escape sequence");
2531 else if (*it ==
't')
2535 else if (*it ==
'n')
2539 else if (*it ==
'f')
2543 else if (*it ==
'r')
2547 else if (*it ==
'"')
2551 else if (*it ==
'\\')
2555 else if (*it ==
'u' || *it ==
'U')
2557 return parse_unicode(it, end);
2561 throw_parse_exception(
"Invalid escape sequence");
2564 return std::string(1, value);
2567 std::string parse_unicode(std::string::iterator& it,
2568 const std::string::iterator& end)
2570 bool large = *it++ ==
'U';
2571 auto codepoint = parse_hex(it, end, large ? 0x10000000 : 0x1000);
2573 if ((codepoint > 0xd7ff && codepoint < 0xe000) || codepoint > 0x10ffff)
2575 throw_parse_exception(
2576 "Unicode escape sequence is not a Unicode scalar value");
2581 if (codepoint <= 0x7f)
2585 result +=
static_cast<char>(codepoint & 0x7f);
2587 else if (codepoint <= 0x7ff)
2595 result +=
static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f));
2600 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2602 else if (codepoint <= 0xffff)
2610 result +=
static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f));
2611 result +=
static_cast<char>(0x80 | ((codepoint >> 6) & 0x1f));
2612 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2622 result +=
static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07));
2623 result +=
static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f));
2624 result +=
static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f));
2625 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2630 uint32_t parse_hex(std::string::iterator& it,
2631 const std::string::iterator& end, uint32_t place)
2637 throw_parse_exception(
"Unexpected end of unicode sequence");
2640 throw_parse_exception(
"Invalid unicode escape sequence");
2642 value += place * hex_to_digit(*it++);
2648 uint32_t hex_to_digit(
char c)
2651 return static_cast<uint32_t
>(c -
'0');
2653 +
static_cast<uint32_t
>(c
2654 - ((c >=
'a' && c <=
'f') ?
'a' :
'A'));
2657 std::shared_ptr<base> parse_number(std::string::iterator& it,
2658 const std::string::iterator& end)
2661 auto check_end = find_end_of_number(it, end);
2663 auto eat_sign = [&]() {
2664 if (check_it != end && (*check_it ==
'-' || *check_it ==
'+'))
2668 auto check_no_leading_zero = [&]() {
2669 if (check_it != end && *check_it ==
'0' && check_it + 1 != check_end
2670 && check_it[1] !=
'.')
2672 throw_parse_exception(
"Numbers may not have leading zeros");
2676 auto eat_digits = [&](bool (*check_char)(char)) {
2677 auto beg = check_it;
2678 while (check_it != end && check_char(*check_it))
2681 if (check_it != end && *check_it ==
'_')
2684 if (check_it == end || !check_char(*check_it))
2685 throw_parse_exception(
"Malformed number");
2689 if (check_it == beg)
2690 throw_parse_exception(
"Malformed number");
2693 auto eat_hex = [&]() { eat_digits(&is_hex); };
2695 auto eat_numbers = [&]() { eat_digits(&is_number); };
2697 if (check_it != end && *check_it ==
'0' && check_it + 1 != check_end
2698 && (check_it[1] ==
'x' || check_it[1] ==
'o' || check_it[1] ==
'b'))
2701 char base = *check_it;
2706 return parse_int(it, check_it, 16);
2708 else if (base ==
'o')
2710 auto start = check_it;
2712 auto val = parse_int(start, check_it, 8,
"0");
2718 auto start = check_it;
2720 auto val = parse_int(start, check_it, 2);
2727 check_no_leading_zero();
2729 if (check_it != end && check_it + 1 != end && check_it + 2 != end)
2731 if (check_it[0] ==
'i' && check_it[1] ==
'n' && check_it[2] ==
'f')
2733 auto val = std::numeric_limits<double>::infinity();
2737 return make_value(val);
2739 else if (check_it[0] ==
'n' && check_it[1] ==
'a'
2740 && check_it[2] ==
'n')
2742 auto val = std::numeric_limits<double>::quiet_NaN();
2746 return make_value(val);
2753 && (*check_it ==
'.' || *check_it ==
'e' || *check_it ==
'E'))
2755 bool is_exp = *check_it ==
'e' || *check_it ==
'E';
2758 if (check_it == end)
2759 throw_parse_exception(
"Floats must have trailing digits");
2761 auto eat_exp = [&]() {
2763 check_no_leading_zero();
2772 if (!is_exp && check_it != end
2773 && (*check_it ==
'e' || *check_it ==
'E'))
2779 return parse_float(it, check_it);
2783 return parse_int(it, check_it);
2787 std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it,
2788 const std::string::iterator& end,
2790 const char* prefix =
"")
2792 std::string v{it, end};
2794 v.erase(std::remove(v.begin(), v.end(),
'_'), v.end());
2798 return make_value<int64_t>(std::stoll(v,
nullptr, base));
2800 catch (
const std::invalid_argument& ex)
2802 throw_parse_exception(
"Malformed number (invalid argument: "
2803 + std::string{ex.what()} +
")");
2805 catch (
const std::out_of_range& ex)
2807 throw_parse_exception(
"Malformed number (out of range: "
2808 + std::string{ex.what()} +
")");
2812 std::shared_ptr<value<double>> parse_float(std::string::iterator& it,
2813 const std::string::iterator& end)
2815 std::string v{it, end};
2816 v.erase(std::remove(v.begin(), v.end(),
'_'), v.end());
2818 char decimal_point = std::localeconv()->decimal_point[0];
2819 std::replace(v.begin(), v.end(),
'.', decimal_point);
2822 return make_value<double>(std::stod(v));
2824 catch (
const std::invalid_argument& ex)
2826 throw_parse_exception(
"Malformed number (invalid argument: "
2827 + std::string{ex.what()} +
")");
2829 catch (
const std::out_of_range& ex)
2831 throw_parse_exception(
"Malformed number (out of range: "
2832 + std::string{ex.what()} +
")");
2836 std::shared_ptr<value<bool>> parse_bool(std::string::iterator& it,
2837 const std::string::iterator& end)
2839 auto eat = make_consumer(it, end, [
this]() {
2840 throw_parse_exception(
"Attempted to parse invalid boolean value");
2846 return make_value<bool>(
true);
2848 else if (*it ==
'f')
2851 return make_value<bool>(
false);
2858 std::string::iterator find_end_of_number(std::string::iterator it,
2859 std::string::iterator end)
2861 auto ret = std::find_if(it, end, [](
char c) {
2862 return !is_number(c) && c !=
'_' && c !=
'.' && c !=
'e' && c !=
'E'
2863 && c !=
'-' && c !=
'+' && c !=
'x' && c !=
'o' && c !=
'b';
2865 if (ret != end && ret + 1 != end && ret + 2 != end)
2867 if ((ret[0] ==
'i' && ret[1] ==
'n' && ret[2] ==
'f')
2868 || (ret[0] ==
'n' && ret[1] ==
'a' && ret[2] ==
'n'))
2876 std::string::iterator find_end_of_date(std::string::iterator it,
2877 std::string::iterator end)
2879 auto end_of_date = std::find_if(it, end, [](
char c) {
2880 return !is_number(c) && c !=
'-';
2882 if (end_of_date != end && *end_of_date ==
' ' && end_of_date + 1 != end
2883 && is_number(end_of_date[1]))
2885 return std::find_if(end_of_date, end, [](
char c) {
2886 return !is_number(c) && c !=
'T' && c !=
'Z' && c !=
':'
2887 && c !=
'-' && c !=
'+' && c !=
'.';
2891 std::string::iterator find_end_of_time(std::string::iterator it,
2892 std::string::iterator end)
2894 return std::find_if(it, end, [](
char c) {
2895 return !is_number(c) && c !=
':' && c !=
'.';
2899 local_time read_time(std::string::iterator& it,
2900 const std::string::iterator& end)
2902 auto time_end = find_end_of_time(it, end);
2904 auto eat = make_consumer(
2905 it, time_end, [&]() { throw_parse_exception(
"Malformed time"); });
2909 ltime.hour = eat.eat_digits(2);
2911 ltime.minute = eat.eat_digits(2);
2913 ltime.second = eat.eat_digits(2);
2916 if (it != time_end && *it ==
'.')
2919 while (it != time_end && is_number(*it))
2921 ltime.microsecond += power * (*it++ -
'0');
2927 throw_parse_exception(
"Malformed time");
2932 std::shared_ptr<value<local_time>>
2933 parse_time(std::string::iterator& it,
const std::string::iterator& end)
2935 return make_value(read_time(it, end));
2938 std::shared_ptr<base> parse_date(std::string::iterator& it,
2939 const std::string::iterator& end)
2941 auto date_end = find_end_of_date(it, end);
2943 auto eat = make_consumer(
2944 it, date_end, [&]() { throw_parse_exception(
"Malformed date"); });
2947 ldate.year = eat.eat_digits(4);
2949 ldate.month = eat.eat_digits(2);
2951 ldate.day = eat.eat_digits(2);
2954 return make_value(ldate);
2956 eat.eat_or(
'T',
' ');
2959 static_cast<local_date&
>(ldt) = ldate;
2960 static_cast<local_time&
>(ldt) = read_time(it, date_end);
2963 return make_value(ldt);
2966 static_cast<local_datetime&
>(dt) = ldt;
2970 if (*it ==
'+' || *it ==
'-')
2972 auto plus = *it ==
'+';
2975 hoff = eat.eat_digits(2);
2976 dt.hour_offset = (plus) ? hoff : -hoff;
2978 moff = eat.eat_digits(2);
2979 dt.minute_offset = (plus) ? moff : -moff;
2981 else if (*it ==
'Z')
2987 throw_parse_exception(
"Malformed date");
2989 return make_value(dt);
2992 std::shared_ptr<base> parse_array(std::string::iterator& it,
2993 std::string::iterator& end)
3004 skip_whitespace_and_comments(it, end);
3010 return make_array();
3013 auto val_end = std::find_if(
3014 it, end, [](
char c) {
return c ==
',' || c ==
']' || c ==
'#'; });
3015 parse_type type = determine_value_type(it, val_end);
3018 case parse_type::STRING:
3019 return parse_value_array<std::string>(it, end);
3020 case parse_type::LOCAL_TIME:
3021 return parse_value_array<local_time>(it, end);
3022 case parse_type::LOCAL_DATE:
3023 return parse_value_array<local_date>(it, end);
3024 case parse_type::LOCAL_DATETIME:
3025 return parse_value_array<local_datetime>(it, end);
3026 case parse_type::OFFSET_DATETIME:
3027 return parse_value_array<offset_datetime>(it, end);
3028 case parse_type::INT:
3029 return parse_value_array<int64_t>(it, end);
3030 case parse_type::FLOAT:
3031 return parse_value_array<double>(it, end);
3032 case parse_type::BOOL:
3033 return parse_value_array<bool>(it, end);
3034 case parse_type::ARRAY:
3035 return parse_object_array<array>(&parser::parse_array,
'[', it,
3037 case parse_type::INLINE_TABLE:
3038 return parse_object_array<table_array>(
3039 &parser::parse_inline_table,
'{', it, end);
3041 throw_parse_exception(
"Unable to parse array");
3045 template <
class Value>
3046 std::shared_ptr<array> parse_value_array(std::string::iterator& it,
3047 std::string::iterator& end)
3049 auto arr = make_array();
3050 while (it != end && *it !=
']')
3052 auto val = parse_value(it, end);
3053 if (
auto v = val->as<Value>())
3054 arr->get().push_back(val);
3056 throw_parse_exception(
"Arrays must be homogeneous");
3057 skip_whitespace_and_comments(it, end);
3061 skip_whitespace_and_comments(it, end);
3068 template <
class Object,
class Function>
3069 std::shared_ptr<Object> parse_object_array(Function&& fun,
char delim,
3070 std::string::iterator& it,
3071 std::string::iterator& end)
3073 auto arr = detail::make_element<Object>();
3075 while (it != end && *it !=
']')
3078 throw_parse_exception(
"Unexpected character in array");
3080 arr->get().push_back(((*this).*fun)(it, end));
3081 skip_whitespace_and_comments(it, end);
3083 if (it == end || *it !=
',')
3087 skip_whitespace_and_comments(it, end);
3090 if (it == end || *it !=
']')
3091 throw_parse_exception(
"Unterminated array");
3097 std::shared_ptr<table> parse_inline_table(std::string::iterator& it,
3098 std::string::iterator& end)
3100 auto tbl = make_table();
3105 throw_parse_exception(
"Unterminated inline table");
3107 consume_whitespace(it, end);
3108 if (it != end && *it !=
'}')
3110 parse_key_value(it, end, tbl.get());
3111 consume_whitespace(it, end);
3113 }
while (*it ==
',');
3115 if (it == end || *it !=
'}')
3116 throw_parse_exception(
"Unterminated inline table");
3119 consume_whitespace(it, end);
3124 void skip_whitespace_and_comments(std::string::iterator& start,
3125 std::string::iterator& end)
3127 consume_whitespace(start, end);
3128 while (start == end || *start ==
'#')
3130 if (!detail::getline(input_, line_))
3131 throw_parse_exception(
"Unclosed array");
3133 start = line_.begin();
3135 consume_whitespace(start, end);
3139 void consume_whitespace(std::string::iterator& it,
3140 const std::string::iterator& end)
3142 while (it != end && (*it ==
' ' || *it ==
'\t'))
3146 void consume_backwards_whitespace(std::string::iterator& back,
3147 const std::string::iterator& front)
3149 while (back != front && (*back ==
' ' || *back ==
'\t'))
3153 void eol_or_comment(
const std::string::iterator& it,
3154 const std::string::iterator& end)
3156 if (it != end && *it !=
'#')
3157 throw_parse_exception(
"Unidentified trailing character '"
3159 +
"'---did you forget a '#'?");
3162 bool is_time(
const std::string::iterator& it,
3163 const std::string::iterator& end)
3165 auto time_end = find_end_of_time(it, end);
3166 auto len = std::distance(it, time_end);
3171 if (it[2] !=
':' || it[5] !=
':')
3175 return it[8] ==
'.' && len > 9;
3180 option<parse_type> date_type(
const std::string::iterator& it,
3181 const std::string::iterator& end)
3183 auto date_end = find_end_of_date(it, end);
3184 auto len = std::distance(it, date_end);
3189 if (it[4] !=
'-' || it[7] !=
'-')
3192 if (len >= 19 && (it[10] ==
'T' || it[10] ==
' ')
3193 && is_time(it + 11, date_end))
3196 auto time_end = find_end_of_time(it + 11, date_end);
3197 if (time_end == date_end)
3198 return {parse_type::LOCAL_DATETIME};
3200 return {parse_type::OFFSET_DATETIME};
3205 return {parse_type::LOCAL_DATE};
3211 std::istream& input_;
3213 std::size_t line_number_ = 0;