#ifndef TOML11_PARSER #define TOML11_PARSER #include "value.hpp" #include "acceptor.hpp" #include namespace toml { template struct parse_escape_sequence { typedef charT value_type; typedef toml::String string_type; typedef string_type result_type; static_assert(std::is_same::value, "char type is different from default String type"); //XXX this changes iterator position! template::value_type, value_type>::value>::type> static result_type invoke(Iterator& iter) { assert(*iter == '\\'); ++iter; switch(*iter) { case '\\': ++iter; return "\\"; case '"' : ++iter; return "\""; case 'b' : ++iter; return "\b"; case 't' : ++iter; return "\t"; case 'n' : ++iter; return "\n"; case 'f' : ++iter; return "\f"; case 'r' : ++iter; return "\r"; case 'u' : { string_type tmp(iter+1, iter+5); std::advance(iter, 5); return utf8_to_char(make_codepoint(tmp)); } case 'U': { string_type tmp(iter+1, iter+9); std::advance(iter, 9); return utf8_to_char(make_codepoint(tmp)); } 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 result_type utf8_to_char(const unsigned int codepoint) { result_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; } }; template struct parse_basic_inline_string { typedef charT value_type; typedef toml::String result_type; static_assert(std::is_same::value, "char type is different from default String type"); template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { if(std::distance(iter, end) < 2) throw internal_error("no basic inline string here"); result_type result; result.reserve(std::distance(iter, end)-2); ++iter; --end; // ignore '"' while(iter != end) { if(*iter == '\\') { result += parse_escape_sequence::invoke(iter); } else { result.push_back(*iter); ++iter; } } return result; } }; template struct parse_basic_multiline_string { typedef charT value_type; typedef toml::String result_type; static_assert(std::is_same::value, "char type is different from default String 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 result_type invoke(Iterator iter, Iterator end) { if(std::distance(iter, end) < 6) throw internal_error("no basic multiline string here"); result_type result; result.reserve(std::distance(iter, end)-6); std::advance(iter, 3); std::advance(end, -3); iter = is_newline::invoke(iter); // the first newline will be trimmed while(iter != end) { if(*iter == '\\') { if(is_line_ending_backslash::invoke(iter) != iter) { iter = ws_nl_after_backslash_remover::invoke(std::next(iter)); } else { result += parse_escape_sequence::invoke(iter); } } else { result.push_back(*iter); ++iter; } } return result; } }; template struct parse_literal_inline_string { typedef charT value_type; typedef toml::String result_type; static_assert(std::is_same::value, "char type is different from default String type"); template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { if(std::distance(iter, end) < 2) throw internal_error("no literal multiline string here"); result_type result; result.reserve(std::distance(iter, end)-2); std::advance(iter, 1); std::advance(end, -1); while(iter != end) { result.push_back(*iter); ++iter; } return result; } }; template struct parse_literal_multiline_string { typedef charT value_type; typedef toml::String result_type; static_assert(std::is_same::value, "char type is different from default String 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 result_type invoke(Iterator iter, Iterator end) { if(std::distance(iter, end) < 6) throw internal_error("no literal multiline string here"); result_type result; result.reserve(std::distance(iter, end)-6); std::advance(iter, 3); std::advance(end, -3); iter = is_newline::invoke(iter); // the first newline will be trimmed while(iter != end) { result.push_back(*iter); ++iter; } return result; } }; template struct parse_string { typedef charT value_type; typedef toml::String result_type; static_assert(std::is_same::value, "char type is different from default String type"); template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { Iterator tmp = is_basic_inline_string::invoke(iter); if(iter != tmp) return parse_basic_inline_string::invoke(iter, tmp); tmp = is_basic_multiline_string::invoke(iter); if(iter != tmp) return parse_basic_multiline_string::invoke(iter, tmp); tmp = is_literal_inline_string::invoke(iter); if(iter != tmp) return parse_literal_inline_string::invoke(iter, tmp); tmp = is_literal_multiline_string::invoke(iter); if(iter != tmp) return parse_literal_multiline_string::invoke(iter, tmp); throw internal_error("no string here"); } }; template struct parse_integer { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Integer result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { string_type result; result.resize(std::distance(iter, end)); std::copy_if(iter, end, result.begin(), [](charT c){return c != '_';}); return std::stoi(result); } }; template struct parse_float { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Float result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { string_type result; result.resize(std::distance(iter, end)); std::copy_if(iter, end, result.begin(), [](charT c){return c != '_';}); return std::stod(result); } }; template struct parse_boolean { typedef charT value_type; typedef toml::Boolean result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { return (std::distance(iter, end) == 4); } }; template struct parse_local_time { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Datetime result_type; typedef typename result_type::number_type number_type; typedef is_repeat_of, 2> nums; typedef is_charactor delim; typedef is_charactor fract; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { result_type result; result.hour = std::stoi(string_type(iter, nums::invoke(iter))); iter = delim::invoke(nums::invoke(iter)); result.minute = std::stoi(string_type(iter, nums::invoke(iter))); iter = delim::invoke(nums::invoke(iter)); result.second = std::stoi(string_type(iter, nums::invoke(iter))); iter = fract::invoke(nums::invoke(iter)); 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 = result_type::nooffset; result.offset_minute = result_type::nooffset; result.year = result_type::undef; result.month = result_type::undef; result.day = result_type::undef; return result; } 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); } }; template struct parse_local_date { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Datetime result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { result_type result; result.year = std::stoi(string_type(iter, nums<4>::invoke(iter))); iter = delim::invoke(nums<4>::invoke(iter)); result.month = std::stoi(string_type(iter, nums<2>::invoke(iter))); iter = delim::invoke(nums<2>::invoke(iter)); result.day = std::stoi(string_type(iter, nums<2>::invoke(iter))); result.offset_hour = result_type::nooffset; result.offset_minute = result_type::nooffset; result.hour = result_type::undef; result.minute = result_type::undef; result.second = result_type::undef; result.millisecond = result_type::undef; result.microsecond = result_type::undef; return result; } }; template struct parse_local_date_time { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Datetime result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { const Iterator date = is_local_date::invoke(iter); result_type result = parse_local_date::invoke(iter, date); iter = delim::invoke(date);// 'T' const result_type time = parse_local_time::invoke(iter, end); result.hour = time.hour; result.minute = time.minute; result.second = time.second; result.millisecond = time.millisecond; result.microsecond = time.microsecond; result.offset_hour = result_type::nooffset; result.offset_minute = result_type::nooffset; return result; } }; template struct parse_offset_date_time { typedef charT value_type; typedef std::basic_string string_type; typedef toml::Datetime result_type; template using nums = is_repeat_of, N>; typedef is_charactor delim; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { const Iterator datetime = is_local_date_time::invoke(iter); result_type result = parse_local_date_time::invoke(iter, datetime); iter = datetime; 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))); iter = delim::invoke(nums<2>::invoke(iter)); result.offset_minute = sign * std::stoi(string_type(iter, nums<2>::invoke(iter))); } return result; } }; template struct parse_datetime { typedef charT value_type; typedef toml::Datetime result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { Iterator tmp = is_offset_date_time::invoke(iter); if(tmp != iter) return parse_offset_date_time::invoke(iter); tmp = is_local_date_time::invoke(iter); if(tmp != iter) return parse_local_date_time::invoke(iter); tmp = is_local_date::invoke(iter); if(tmp != iter) return parse_local_date::invoke(iter); tmp = is_local_time::invoke(iter); if(tmp != iter) return parse_local_time::invoke(iter); throw internal_error("no datetime here"); } }; template struct parse_fixed_type_array { typedef charT value_type; typedef toml::Array result_type; typedef acceptorT acceptor_type; typedef parserT parser_type; typedef is_skippable_in_array skippable; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { result_type result; --end; assert(*iter == '[' && *end == ']'); ++iter; iter = skippable::invoke(iter); while(iter != end) { const Iterator tmp = acceptor_type::invoke(iter); result.emplace_back(parser_type::invoke(iter, tmp)); iter = tmp; iter = skippable::invoke(iter); iter = is_charactor::invoke(iter); iter = skippable::invoke(iter); } return result; } }; template struct parse_inline_table; template struct parse_array { typedef charT value_type; typedef toml::Array result_type; typedef is_skippable_in_array skippable; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { const Iterator init = skippable::invoke(std::next(iter)); if(is_boolean::invoke(init) != init) return parse_fixed_type_array, parse_boolean>::invoke(iter, end); if(is_integer::invoke(init) != init) return parse_fixed_type_array, parse_integer>::invoke(iter, end); if(is_float::invoke(init) != init) return parse_fixed_type_array, parse_float>::invoke(iter, end); if(is_string::invoke(init) != init) return parse_fixed_type_array, parse_string>::invoke(iter, end); if(is_datetime::invoke(init) != init) return parse_fixed_type_array, parse_datetime>::invoke(iter, end); if(is_array::invoke(init) != init) return parse_fixed_type_array, parse_array>::invoke(iter, end); if(is_inline_table::invoke(init) != init) return parse_fixed_type_array, parse_inline_table>::invoke(iter, end); if(is_skippable_in_array::invoke(init) == std::prev(end)) return result_type{}; // empty throw internal_error("no valid array here"); } }; template struct parse_value { typedef charT value_type; typedef toml::value result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { if(iter != is_string::invoke(iter)) return result_type(parse_string::invoke(iter, end)); else if(iter != is_float::invoke(iter)) return result_type(parse_float::invoke(iter, end)); else if(iter != is_integer::invoke(iter)) return result_type(parse_integer::invoke(iter, end)); else if(iter != is_boolean::invoke(iter)) return result_type(parse_boolean::invoke(iter, end)); else if(iter != is_datetime::invoke(iter)) return result_type(parse_datetime::invoke(iter, end)); else if(iter != is_array::invoke(iter)) return result_type(parse_array::invoke(iter, end)); else if(iter != is_inline_table::invoke(iter)) return result_type(parse_inline_table::invoke(iter, end)); throw internal_error("no valid value here"); } }; template struct parse_barekey { typedef charT value_type; typedef toml::key result_type; static_assert(std::is_same::value, "char type is different from default key type"); template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { return result_type(iter, end); } }; template struct parse_key { typedef charT value_type; typedef toml::key result_type; static_assert(std::is_same::value, "char type is different from default key type"); template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { if(iter != is_barekey::invoke(iter)) return parse_barekey(iter, end); else if(iter != is_string::invoke(iter)) return parse_string(iter, end); throw internal_error("no valid key here"); } }; template struct parse_key_value_pair { typedef charT value_type; typedef std::pair result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { Iterator tmp = is_key::invoke(iter); const toml::key k = parse_key::invoke(iter, tmp); iter = tmp; iter = is_any_num_of_ws::invoke(iter); assert(*iter == '='); ++iter; iter = is_any_num_of_ws::invoke(iter); tmp = is_value::invoke(iter); const toml::value v = parse_value::invoke(iter, tmp); return std::make_pair(k, v); } }; template struct parse_inline_table { typedef charT value_type; typedef toml::Table result_type; template::value_type, value_type>::value>::type> static result_type invoke(Iterator iter, Iterator end) { assert(*iter == '{' && *end == '}'); ++iter; --end; iter = is_any_num_of_ws::invoke(iter); result_type result; while(iter != end) { Iterator tmp = is_key_value_pair::invoke(iter); result.emplace(parse_key_value_pair::invoke(iter, tmp)); iter = tmp; iter = is_any_num_of_ws::invoke(iter); iter = is_charactor::invoke(iter); iter = is_any_num_of_ws::invoke(iter); } return result; } }; }// toml #endif// TOML11_PARSER