#ifndef TOML11_PARSER #define TOML11_PARSER #include "value.hpp" #include "acceptor.hpp" #include #include #include #include namespace toml { namespace detail { // it is just an inferior vertion of boost/std::optional template struct result { result() : ok_(false){} ~result() = default; result(const result& rhs) = default; result(result&& rhs) = default; result& operator=(const result& rhs) = default; result& operator=(result&& rhs) = default; result(const T& v) : ok_(true), value_(v){} result(T&& v) : ok_(true), value_(std::move(v)){} result& operator=(const T& rhs){ok_ = true; value_ = rhs; return *this;} result& operator=(T&& rhs) {ok_ = true; value_ = rhs; return *this;} template result& operator=(const result& u) {ok_ = u.ok(); if(ok_)value_ = u.move(); return *this;} template result& operator=(result&& u) {ok_ = u.ok(); if(ok_)value_ = u.move(); return *this;} template result(const result& u): ok_(u.ok()){if(ok_)value_ = u.get();} template result(result&& u): ok_(u.ok()){if(ok_)value_ = u.move();} bool ok() const {return ok_;} operator bool() const {return ok_;} T& get() {if(!ok_) throw std::logic_error("result::get"); return value_;} T const& get() const {if(!ok_) throw std::logic_error("result::get"); return value_;} T&& move() {if(!ok_) throw std::logic_error("result::move"); ok_ = false; return std::move(value_);} private: bool ok_; T value_; }; }//detail struct parse_escape_sequence { typedef toml::charactor value_type; typedef toml::String string_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator end) { if(iter == end || *iter != '\\') return std::make_pair(result_type{}, iter); ++iter; switch(*iter) { case '\\': return std::make_pair(string_type("\\"), std::next(iter)); case '"' : return std::make_pair(string_type("\""), std::next(iter)); case 'b' : return std::make_pair(string_type("\b"), std::next(iter)); case 't' : return std::make_pair(string_type("\t"), std::next(iter)); case 'n' : return std::make_pair(string_type("\n"), std::next(iter)); case 'f' : return std::make_pair(string_type("\f"), std::next(iter)); case 'r' : return std::make_pair(string_type("\r"), std::next(iter)); case 'u' : { if(std::distance(iter, end) < 5) throw syntax_error("invalid escape sequence"); return std::make_pair(utf8_to_char(make_codepoint( string_type(iter+1, iter+5))), iter+5); } case 'U': { if(std::distance(iter, end) < 8) throw syntax_error("invalid escape sequence"); return std::make_pair(utf8_to_char(make_codepoint( string_type(iter+1, iter+9))), iter+9); } default: throw syntax_error("unkwnon escape sequence"); } } static unsigned int make_codepoint(string_type str) { unsigned int codepoint; std::basic_istringstream iss(str); iss >> std::hex >> codepoint; return codepoint; } static string_type utf8_to_char(const unsigned int codepoint) { string_type charactor; if(codepoint < 0x80) { charactor += static_cast(codepoint); } else if(codepoint < 0x800) { charactor += static_cast(0xC0| codepoint >> 6); charactor += static_cast(0x80|(codepoint & 0x3F)); } else if(codepoint < 0x10000) { charactor += static_cast(0xE0| codepoint >>12); charactor += static_cast(0x80|(codepoint >>6&0x3F)); charactor += static_cast(0x80|(codepoint & 0x3F)); } else { charactor += static_cast(0xF0| codepoint >>18); charactor += static_cast(0x80|(codepoint >>12&0x3F)); charactor += static_cast(0x80|(codepoint >>6 &0x3F)); charactor += static_cast(0x80|(codepoint & 0x3F)); } return charactor; } }; struct parse_basic_inline_string { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_basic_inline_string::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); if(std::distance(iter, end) < 2) throw internal_error("is_basic_inline_string"); toml::String result; result.reserve(std::distance(iter, end)-2); ++iter; const Iterator last = std::prev(end); // ignore '"' while(iter != last) { if(*iter == '\\') { auto r = parse_escape_sequence::invoke(iter, last); if(!r.first.ok()) throw internal_error("parse_basic_inline_string"); result += r.first.move(); iter = r.second; } else { result += *iter; ++iter; } } return std::make_pair(result, end); } }; struct parse_basic_multiline_string { typedef toml::charactor value_type; typedef toml::String string_type; typedef detail::result result_type; typedef is_chain_of, is_newline> is_line_ending_backslash; typedef is_repeat_of, is_newline>, repeat_infinite()> ws_nl_after_backslash_remover; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_basic_multiline_string::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); if(std::distance(iter, end) < 6) throw internal_error("is_basic_inline_string"); toml::String result; result.reserve(std::distance(iter, end)-6); std::advance(iter, 3); const Iterator last = end - 3; iter = is_newline::invoke(iter, last); while(iter != last) { if(*iter == '\\') { if(is_line_ending_backslash::invoke(iter, last) != iter) { iter = ws_nl_after_backslash_remover::invoke(std::next(iter), last); } else { auto r = parse_escape_sequence::invoke(iter, last); if(!r.first.ok()) throw internal_error("parse_basic_inline_string"); result += r.first.move(); iter = r.second; } } else { result.push_back(*iter); ++iter; } } return std::make_pair(result, end); } }; struct parse_literal_inline_string { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_literal_inline_string::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); if(std::distance(iter, end) < 2) throw internal_error("is_literal_inline_string"); toml::String result; result.reserve(std::distance(iter, end)-2); ++iter; const Iterator last = end - 1; while(iter != last) { result.push_back(*iter); ++iter; } return std::make_pair(result, end); } }; struct parse_literal_multiline_string { typedef toml::charactor value_type; typedef detail::result result_type; typedef is_chain_of, is_newline> is_line_ending_backslash; typedef is_repeat_of, is_newline>, repeat_infinite()> ws_nl_after_backslash_remover; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_literal_multiline_string::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); if(std::distance(iter, end) < 6) throw internal_error("is_literal_multiline_string"); toml::String result; result.reserve(std::distance(iter, end)-6); std::advance(iter, 3); const Iterator last = end - 3; iter = is_newline::invoke(iter, last); // trim first newline if exist while(iter != last) { result.push_back(*iter); ++iter; } return std::make_pair(result, end); } }; struct parse_string { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { std::pair result; if((result = parse_basic_inline_string::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_basic_multiline_string::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_literal_inline_string::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_literal_multiline_string::invoke(iter, range_end)).first.ok()) return result; else return std::make_pair(result_type{}, iter); } }; struct parse_integer { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_integer::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); string_type result; result.resize(std::distance(iter, end)); std::copy_if(iter, end, result.begin(), [](value_type c){return c != '_';}); return std::make_pair(std::stoll(result), end); } }; struct parse_float { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_float::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); string_type result; result.resize(std::distance(iter, end)); std::copy_if(iter, end, result.begin(), [](value_type c){return c != '_';}); try{ return std::make_pair(std::stod(result), end); } catch(std::out_of_range& oor) { std::cout << "extremely large Float value appeared: " << result << "; it is negrected" << std::endl; return std::make_pair(0, end); } } }; struct parse_boolean { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_boolean::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); return std::make_pair((std::distance(iter, end) == 4), end); } }; struct parse_local_time { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; typedef typename toml::Datetime::number_type number_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; typedef is_charactor fract; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_local_time::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); toml::Datetime result; result.hour = std::stoi(string_type(iter, nums<2>::invoke(iter, end))); iter = delim::invoke(nums<2>::invoke(iter, end), end); result.minute = std::stoi(string_type(iter, nums<2>::invoke(iter, end))); iter = delim::invoke(nums<2>::invoke(iter, end), end); result.second = std::stoi(string_type(iter, nums<2>::invoke(iter, end))); iter = fract::invoke(nums<2>::invoke(iter, end), end); if(iter == end) { result.millisecond = 0.0; result.microsecond = 0.0; } else if(std::distance(iter, end) <= 3) { result.millisecond = parse_number(iter, end); result.microsecond = 0.0; } else { result.millisecond = parse_number(iter, iter + 3); result.microsecond = parse_number(iter + 3, end); } result.offset_hour = toml::Datetime::nooffset; result.offset_minute = toml::Datetime::nooffset; result.year = toml::Datetime::undef; result.month = toml::Datetime::undef; result.day = toml::Datetime::undef; return std::make_pair(result, end); } template::value_type, value_type>::value>::type> static number_type parse_number(Iterator iter, Iterator end) { if(std::distance(iter, end) > 3) end = iter + 3; string_type str(iter, end); while(str.size() < 3){str += '0';} return std::stoi(str); } }; struct parse_local_date { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_local_date::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); toml::Datetime result; result.year = std::stoi(string_type(iter, nums<4>::invoke(iter, end))); iter = delim::invoke(nums<4>::invoke(iter, end), end); result.month = std::stoi(string_type(iter, nums<2>::invoke(iter, end))); iter = delim::invoke(nums<2>::invoke(iter, end), end); result.day = std::stoi(string_type(iter, nums<2>::invoke(iter, end))); result.offset_hour = toml::Datetime::nooffset; result.offset_minute = toml::Datetime::nooffset; result.hour = toml::Datetime::undef; result.minute = toml::Datetime::undef; result.second = toml::Datetime::undef; result.millisecond = toml::Datetime::undef; result.microsecond = toml::Datetime::undef; return std::make_pair(result, end); } }; struct parse_local_date_time { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_local_date_time::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); auto ld = parse_local_date::invoke(iter, end); if(!ld.first.ok()) throw syntax_error("invalid local datetime"); toml::Datetime result(ld.first.move()); iter = delim::invoke(ld.second, end);// 'T' const auto time = parse_local_time::invoke(iter, end); result.hour = time.first.get().hour; result.minute = time.first.get().minute; result.second = time.first.get().second; result.millisecond = time.first.get().millisecond; result.microsecond = time.first.get().microsecond; result.offset_hour = toml::Datetime::nooffset; result.offset_minute = toml::Datetime::nooffset; return std::make_pair(result, end); } }; struct parse_offset_date_time { typedef toml::charactor value_type; typedef std::basic_string string_type; typedef detail::result result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_offset_date_time::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); auto ldt = parse_local_date_time::invoke(iter, end); if(!ldt.first.ok()) throw syntax_error("invalid offset datetime"); toml::Datetime result(ldt.first.move()); iter = ldt.second; if(*iter == 'Z') { result.offset_hour = 0; result.offset_minute = 0; } else { if(*iter != '+' && *iter != '-') throw syntax_error("invalid offset-datetime"); const int sign = (*iter == '-') ? -1 : 1; ++iter; result.offset_hour = sign * std::stoi(string_type(iter, nums<2>::invoke(iter, end))); iter = delim::invoke(nums<2>::invoke(iter, end), end); result.offset_minute = sign * std::stoi(string_type(iter, nums<2>::invoke(iter, end))); } return std::make_pair(result, end); } }; struct parse_datetime { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { std::pair result; if((result = parse_offset_date_time::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_local_date_time::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_local_date::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_local_time::invoke(iter, range_end)).first.ok()) return result; else return std::make_pair(result_type{}, iter); } }; template struct parse_fixed_type_array { typedef toml::charactor value_type; typedef detail::result result_type; typedef acceptorT acceptor_type; typedef parserT parser_type; typedef is_skippable_in_array skippable; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_fixed_type_array::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); toml::Array result; const Iterator last = std::prev(end); iter = skippable::invoke(std::next(iter), last); while(iter != last) { const Iterator tmp = acceptor_type::invoke(iter, last); if(tmp == iter) throw syntax_error("parse_array"); auto next = parser_type::invoke(iter, last); if(!next.first.ok()) throw syntax_error("parse_array"); result.emplace_back(next.first.move()); iter = tmp; iter = skippable::invoke(iter, last); iter = is_charactor::invoke(iter, last); iter = skippable::invoke(iter, last); } return std::make_pair(result, end); } }; template struct parse_inline_table; template struct parse_array { typedef charT value_type; static_assert(std::is_same::value, ""); typedef detail::result result_type; typedef is_skippable_in_array skippable; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { if(iter == is_array::invoke(iter, range_end)) return std::make_pair(result_type{}, iter); std::pair result; if((result = parse_fixed_type_array, parse_boolean>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_string>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_datetime>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_float>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_integer>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_array>::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_fixed_type_array, parse_inline_table>::invoke(iter, range_end)).first.ok()) return result; else if(skippable::invoke(std::next(iter), range_end) == // empty std::prev(is_array::invoke(iter, range_end)) ) return std::make_pair( toml::Array{}, is_array::invoke(iter, range_end)); else throw syntax_error("no valid array here"); } }; template struct parse_value { typedef charT value_type; static_assert(std::is_same::value, ""); typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { std::pair result; if((result = parse_boolean::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_string::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_datetime::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_float::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_integer::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_array::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_inline_table::invoke(iter, range_end)).first.ok()) return result; else return std::make_pair(result_type{}, iter); } }; struct parse_barekey { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_barekey::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); return std::make_pair(toml::key(iter, end), end); } }; struct parse_key { typedef toml::charactor value_type; typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { std::pair result; if((result = parse_barekey::invoke(iter, range_end)).first.ok()) return result; else if((result = parse_string::invoke(iter, range_end)).first.ok()) return result; else return std::make_pair(result_type{}, iter); } }; template struct parse_key_value_pair { typedef charT value_type; static_assert(std::is_same::value, ""); typedef detail::result> result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { auto tmp_key = parse_key::invoke(iter, range_end); if(!tmp_key.first.ok()) return std::make_pair(result_type{}, iter); iter = is_any_num_of_ws::invoke(tmp_key.second, range_end); if(*iter != '=') throw syntax_error("invalid key value pair"); iter = is_any_num_of_ws::invoke(std::next(iter), range_end); auto tmp_value = parse_value::invoke(iter, range_end); if(!tmp_value.first.ok()) throw syntax_error("invalid key value pair"); iter = tmp_value.second; return std::make_pair(std::make_pair( tmp_key.first.move(), tmp_value.first.move()), is_any_num_of_ws::invoke(tmp_value.second, range_end)); } }; template struct parse_inline_table { typedef charT value_type; static_assert(std::is_same::value, ""); typedef detail::result result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_inline_table::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); iter = is_any_num_of_ws::invoke(std::next(iter), range_end); const Iterator last = std::prev(end); toml::Table result; while(iter != last) { auto tmp = parse_key_value_pair::invoke(iter, last); if(!tmp.first.ok()) throw syntax_error("parse_inline_table"); result.emplace(tmp.first.move()); iter = tmp.second; iter = is_any_num_of_ws::invoke(iter, last); iter = is_charactor::invoke(iter, last); iter = is_any_num_of_ws::invoke(iter, last); } return std::make_pair(result, end); } }; struct parse_table_definition { typedef toml::charactor value_type; typedef detail::result> result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_table_definition::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); std::vector result; result.reserve(std::count(iter, end, '.')+1); const Iterator last = std::prev(end); iter = is_any_num_of_ws::invoke(iter, last); iter = is_any_num_of_ws::invoke(std::next(iter), last); auto tmp = parse_key::invoke(iter, last); if(!tmp.first.ok()) throw syntax_error("table definition"); result.emplace_back(tmp.first.move()); iter = is_any_num_of_ws::invoke(tmp.second, last); while(iter != last) { iter = is_charactor::invoke(iter, last); iter = is_any_num_of_ws::invoke(iter, last); tmp = parse_key::invoke(iter, last); if(!tmp.first.ok()) throw syntax_error("table definition"); result.emplace_back(tmp.first.move()); iter = is_any_num_of_ws::invoke(tmp.second, last); } return std::make_pair(result, end); } }; struct parse_array_of_table_definition { typedef toml::charactor value_type; typedef detail::result> result_type; template::value_type, value_type>::value>::type> static std::pair invoke(Iterator iter, Iterator range_end) { const Iterator end = is_array_of_table_definition::invoke(iter, range_end); if(iter == end) return std::make_pair(result_type{}, iter); if(std::distance(iter, end) < 5) throw syntax_error("invalid array_of_table definition"); std::vector result; result.reserve(std::count(iter, end, '.')+1); const Iterator last = end - 2; iter = is_any_num_of_ws::invoke(iter, last) + 2; iter = is_any_num_of_ws::invoke(iter, last); auto tmp = parse_key::invoke(iter, last); if(!tmp.first.ok()) throw syntax_error("array of table definition"); result.emplace_back(tmp.first.move()); iter = is_any_num_of_ws::invoke(tmp.second, last); while(iter != last) { iter = is_charactor::invoke(iter, last); iter = is_any_num_of_ws::invoke(iter, last); tmp = parse_key::invoke(iter, last); if(!tmp.first.ok()) throw syntax_error("array of table definition"); result.emplace_back(tmp.first.move()); iter = is_any_num_of_ws::invoke(tmp.second, last); } return std::make_pair(result, end); } }; struct parse_data { typedef toml::charactor value_type; typedef toml::Table result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, const Iterator end) { toml::Table result; auto noname = parse_table_contents(iter, end); result = std::move(noname.first); iter = skip_empty(noname.second, end); while(iter != end) { iter = skip_empty(iter, end); std::pair>, Iterator> tabname; if((tabname = parse_table_definition::invoke(iter, end)).first.ok()) { auto contents = parse_table_contents(tabname.second, end); push_table(result, std::move(contents.first), tabname.first.get().begin(), tabname.first.get().end()); iter = contents.second; } else if((tabname = parse_array_of_table_definition::invoke(iter, end)).first.ok()) { auto contents = parse_table_contents(tabname.second, end); push_array_of_table(result, std::move(contents.first), tabname.first.get().begin(), tabname.first.get().end()); iter = contents.second; } else throw syntax_error("parse_data: unknown line"); } return result; } template::value_type, value_type>::value>::type> static Iterator skip_empty(Iterator iter, Iterator end) { while(iter != end) { if(*iter == '#') { while(iter != end && iter == is_newline::invoke(iter, end)){++iter;} } else if(iter == is_newline::invoke(iter, end) && iter == is_whitespace::invoke(iter, end)) { return iter; } else { ++iter; } } return iter; } template::value_type, value_type>::value>::type> static std::pair parse_table_contents(Iterator iter, Iterator end) { toml::Table table; iter = skip_empty(iter, end); while(iter != end) { auto kv = parse_key_value_pair::invoke(iter, end); if(!kv.first.ok()) return std::make_pair(table, iter); table.emplace(kv.first.move()); iter = kv.second; iter = skip_empty(iter, end); } return std::make_pair(table, iter); } template::value_type, toml::key>::value>::type> static void push_table(toml::Table& data, toml::Table&& v, Iterator iter, Iterator end) { if(iter == std::prev(end)) { if(data.count(*iter) == 1) throw syntax_error("duplicate key: " + *iter); data.emplace(*iter, std::move(v)); return; } if(data.count(*iter) == 0) { data.emplace(*iter, toml::Table()); return push_table(data[*iter].template cast(), std::move(v), std::next(iter), end); } else if(data[*iter].type() == value_t::Table) { return push_table(data[*iter].template cast(), std::move(v), std::next(iter), end); } else if(data[*iter].type() == value_t::Array) { auto& ar = data[*iter].template cast(); if(ar.empty()) ar.emplace_back(toml::Table{}); if(ar.back().type() != value_t::Table) throw syntax_error("assign table into array having non-table type: " + *iter); return push_table(ar.back().template cast(), std::move(v), std::next(iter), end); } else throw syntax_error("assign table into not table: " + *iter); } template::value_type, toml::key>::value>::type> static void push_array_of_table(toml::Table& data, toml::Table&& v, Iterator iter, Iterator end) { if(iter == std::prev(end)) { if(data.count(*iter) == 0) data.emplace(*iter, toml::Array()); else if(data.at(*iter).type() != value_t::Array) throw syntax_error("duplicate key: " + *iter); data[*iter].template cast().emplace_back(std::move(v)); return; } if(data.count(*iter) == 0) { data.emplace(*iter, toml::Table()); return push_array_of_table(data[*iter].template cast(), std::move(v), std::next(iter), end); } else if(data[*iter].type() == value_t::Table) { return push_array_of_table(data[*iter].template cast(), std::move(v), std::next(iter), end); } else if(data[*iter].type() == value_t::Array) { auto& ar = data[*iter].template cast(); if(ar.empty()) ar.emplace_back(toml::Table{}); if(ar.back().type() != value_t::Table) throw syntax_error("assign table into array having non-table type: " + *iter); return push_array_of_table(ar.back().template cast(), std::move(v), std::next(iter), end); } else throw syntax_error("assign array of table into not table: " + *iter); } }; template> toml::Table parse(std::basic_istream& is) { const auto initial = is.tellg(); is.seekg(0, std::ios::end); const auto eofpos = is.tellg(); const std::size_t size = eofpos - initial; is.seekg(initial); std::vector contents(size); is.read(contents.data(), size); return parse_data::invoke(contents.cbegin(), contents.cend()); } toml::Table parse(const std::string& filename) { std::ifstream ifs(filename); if(!ifs.good()) throw std::runtime_error("file open error: " + filename); return parse(ifs); } }// toml #endif// TOML11_PARSER