feat: 💥 update types and retval of parser

- change return value from toml::table to toml::value
- enable to change container types and comment policy by template
This commit is contained in:
ToruNiina
2019-06-02 21:47:57 +09:00
parent 7d34436535
commit 2e34035e7a

View File

@@ -869,13 +869,16 @@ parse_key(location<Container>& loc)
} }
// forward-decl to implement parse_array and parse_table // forward-decl to implement parse_array and parse_table
template<typename Container> template<typename Value, typename Container>
result<value, std::string> parse_value(location<Container>&); result<Value, std::string> parse_value(location<Container>&);
template<typename Container> template<typename Value, typename Container>
result<std::pair<array, region<Container>>, std::string> result<std::pair<typename Value::array_type, region<Container>>, std::string>
parse_array(location<Container>& loc) parse_array(location<Container>& loc)
{ {
using value_type = Value;
using array_type = typename value_type::array_type;
const auto first = loc.iter(); const auto first = loc.iter();
if(loc.iter() == loc.end()) if(loc.iter() == loc.end())
{ {
@@ -890,7 +893,7 @@ parse_array(location<Container>& loc)
using lex_ws_comment_newline = repeat< using lex_ws_comment_newline = repeat<
either<lex_wschar, lex_newline, lex_comment>, unlimited>; either<lex_wschar, lex_newline, lex_comment>, unlimited>;
array retval; array_type retval;
while(loc.iter() != loc.end()) while(loc.iter() != loc.end())
{ {
lex_ws_comment_newline::invoke(loc); // skip lex_ws_comment_newline::invoke(loc); // skip
@@ -902,7 +905,7 @@ parse_array(location<Container>& loc)
region<Container>(loc, first, loc.iter()))); region<Container>(loc, first, loc.iter())));
} }
if(auto val = parse_value(loc)) if(auto val = parse_value<value_type>(loc))
{ {
if(!retval.empty() && retval.front().type() != val.as_ok().type()) if(!retval.empty() && retval.front().type() != val.as_ok().type())
{ {
@@ -966,10 +969,12 @@ parse_array(location<Container>& loc)
{{std::addressof(loc), "should be closed"}})); {{std::addressof(loc), "should be closed"}}));
} }
template<typename Container> template<typename Value, typename Container>
result<std::pair<std::pair<std::vector<key>, region<Container>>, value>, std::string> result<std::pair<std::pair<std::vector<key>, region<Container>>, Value>, std::string>
parse_key_value_pair(location<Container>& loc) parse_key_value_pair(location<Container>& loc)
{ {
using value_type = Value;
const auto first = loc.iter(); const auto first = loc.iter();
auto key_reg = parse_key(loc); auto key_reg = parse_key(loc);
if(!key_reg) if(!key_reg)
@@ -1013,7 +1018,7 @@ parse_key_value_pair(location<Container>& loc)
} }
const auto after_kvsp = loc.iter(); // err msg const auto after_kvsp = loc.iter(); // err msg
auto val = parse_value(loc); auto val = parse_value<value_type>(loc);
if(!val) if(!val)
{ {
std::string msg; std::string msg;
@@ -1123,9 +1128,9 @@ bool is_valid_forward_table_definition(const value& fwd,
return false; return false;
} }
template<typename InputIterator, typename Container> template<typename Value, typename InputIterator, typename Container>
result<bool, std::string> result<bool, std::string>
insert_nested_key(table& root, const toml::value& v, insert_nested_key(typename Value::table_type& root, const Value& v,
InputIterator iter, const InputIterator last, InputIterator iter, const InputIterator last,
region<Container> key_reg, region<Container> key_reg,
const bool is_array_of_table = false) const bool is_array_of_table = false)
@@ -1133,10 +1138,14 @@ insert_nested_key(table& root, const toml::value& v,
static_assert(std::is_same<key, static_assert(std::is_same<key,
typename std::iterator_traits<InputIterator>::value_type>::value,""); typename std::iterator_traits<InputIterator>::value_type>::value,"");
using value_type = Value;
using table_type = typename value_type::table_type;
using array_type = typename value_type::array_type;
const auto first = iter; const auto first = iter;
assert(iter != last); assert(iter != last);
table* tab = std::addressof(root); table_type* tab = std::addressof(root);
for(; iter != last; ++iter) // search recursively for(; iter != last; ++iter) // search recursively
{ {
const key& k = *iter; const key& k = *iter;
@@ -1176,7 +1185,7 @@ insert_nested_key(table& root, const toml::value& v,
})); }));
} }
// the above if-else-if checks tab->at(k) is an array // the above if-else-if checks tab->at(k) is an array
array& a = tab->at(k).as_array(); auto& a = tab->at(k).as_array();
if(!(a.front().is_table())) if(!(a.front().is_table()))
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
@@ -1223,7 +1232,7 @@ insert_nested_key(table& root, const toml::value& v,
} }
else // if not, we need to create the array of table else // if not, we need to create the array of table
{ {
toml::value aot(toml::array(1, v), key_reg); value_type aot(array_type(1, v), key_reg);
tab->insert(std::make_pair(k, aot)); tab->insert(std::make_pair(k, aot));
return ok(true); return ok(true);
} }
@@ -1298,7 +1307,7 @@ insert_nested_key(table& root, const toml::value& v,
// [x.y.z] // [x.y.z]
if(tab->count(k) == 0) if(tab->count(k) == 0)
{ {
(*tab)[k] = toml::value(toml::table{}, key_reg); (*tab)[k] = value_type(table_type{}, key_reg);
} }
// type checking... // type checking...
@@ -1308,7 +1317,7 @@ insert_nested_key(table& root, const toml::value& v,
} }
else if(tab->at(k).is_array()) // inserting to array-of-tables? else if(tab->at(k).is_array()) // inserting to array-of-tables?
{ {
array& a = (*tab)[k].as_array(); auto& a = (*tab)[k].as_array();
if(!a.back().is_table()) if(!a.back().is_table())
{ {
throw syntax_error(format_underline(concat_to_string( throw syntax_error(format_underline(concat_to_string(
@@ -1338,12 +1347,15 @@ insert_nested_key(table& root, const toml::value& v,
return err(std::string("toml::detail::insert_nested_key: never reach here")); return err(std::string("toml::detail::insert_nested_key: never reach here"));
} }
template<typename Container> template<typename Value, typename Container>
result<std::pair<table, region<Container>>, std::string> result<std::pair<typename Value::table_type, region<Container>>, std::string>
parse_inline_table(location<Container>& loc) parse_inline_table(location<Container>& loc)
{ {
using value_type = Value;
using table_type = typename value_type::table_type;
const auto first = loc.iter(); const auto first = loc.iter();
table retval; table_type retval;
if(!(loc.iter() != loc.end() && *loc.iter() == '{')) if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
{ {
return err(format_underline("[error] toml::parse_inline_table: ", return err(format_underline("[error] toml::parse_inline_table: ",
@@ -1361,14 +1373,14 @@ parse_inline_table(location<Container>& loc)
retval, region<Container>(loc, first, loc.iter()))); retval, region<Container>(loc, first, loc.iter())));
} }
const auto kv_r = parse_key_value_pair(loc); const auto kv_r = parse_key_value_pair<value_type>(loc);
if(!kv_r) if(!kv_r)
{ {
return err(kv_r.unwrap_err()); return err(kv_r.unwrap_err());
} }
const std::vector<key>& keys = kv_r.unwrap().first.first; const std::vector<key>& keys = kv_r.unwrap().first.first;
const region<Container>& key_reg = kv_r.unwrap().first.second; const region<Container>& key_reg = kv_r.unwrap().first.second;
const value& val = kv_r.unwrap().second; const value_type& val = kv_r.unwrap().second;
const auto inserted = const auto inserted =
insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg); insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg);
@@ -1414,22 +1426,22 @@ value_t guess_number_type(const location<Container>& l)
{ {
location<Container> loc = l; location<Container> loc = l;
if(lex_offset_date_time::invoke(loc)) {return value_t::OffsetDatetime;} if(lex_offset_date_time::invoke(loc)) {return value_t::offset_datetime;}
loc.reset(l.iter()); loc.reset(l.iter());
if(lex_local_date_time::invoke(loc)) {return value_t::LocalDatetime;} if(lex_local_date_time::invoke(loc)) {return value_t::local_datetime;}
loc.reset(l.iter()); loc.reset(l.iter());
if(lex_local_date::invoke(loc)) {return value_t::LocalDate;} if(lex_local_date::invoke(loc)) {return value_t::local_date;}
loc.reset(l.iter()); loc.reset(l.iter());
if(lex_local_time::invoke(loc)) {return value_t::LocalTime;} if(lex_local_time::invoke(loc)) {return value_t::local_time;}
loc.reset(l.iter()); loc.reset(l.iter());
if(lex_float::invoke(loc)) {return value_t::Float;} if(lex_float::invoke(loc)) {return value_t::floating;}
loc.reset(l.iter()); loc.reset(l.iter());
return value_t::Integer; return value_t::integer;
} }
template<typename Container> template<typename Container>
@@ -1437,21 +1449,23 @@ value_t guess_value_type(const location<Container>& loc)
{ {
switch(*loc.iter()) switch(*loc.iter())
{ {
case '"' : {return value_t::String; } case '"' : {return value_t::string; }
case '\'': {return value_t::String; } case '\'': {return value_t::string; }
case 't' : {return value_t::Boolean;} case 't' : {return value_t::boolean; }
case 'f' : {return value_t::Boolean;} case 'f' : {return value_t::boolean; }
case '[' : {return value_t::Array; } case '[' : {return value_t::array; }
case '{' : {return value_t::Table; } case '{' : {return value_t::table; }
case 'i' : {return value_t::Float; } // inf. case 'i' : {return value_t::floating;} // inf.
case 'n' : {return value_t::Float; } // nan. case 'n' : {return value_t::floating;} // nan.
default : {return guess_number_type(loc);} default : {return guess_number_type(loc);}
} }
} }
template<typename Container> template<typename Value, typename Container>
result<value, std::string> parse_value(location<Container>& loc) result<Value, std::string> parse_value(location<Container>& loc)
{ {
using value_type = Value;
const auto first = loc.iter(); const auto first = loc.iter();
if(first == loc.end()) if(first == loc.end())
{ {
@@ -1461,16 +1475,16 @@ result<value, std::string> parse_value(location<Container>& loc)
switch(guess_value_type(loc)) switch(guess_value_type(loc))
{ {
case value_t::Boolean : {return parse_boolean(loc); } case value_t::boolean : {return parse_boolean(loc); }
case value_t::Integer : {return parse_integer(loc); } case value_t::integer : {return parse_integer(loc); }
case value_t::Float : {return parse_floating(loc); } case value_t::floating : {return parse_floating(loc); }
case value_t::String : {return parse_string(loc); } case value_t::string : {return parse_string(loc); }
case value_t::OffsetDatetime : {return parse_offset_datetime(loc);} case value_t::offset_datetime: {return parse_offset_datetime(loc);}
case value_t::LocalDatetime : {return parse_local_datetime(loc); } case value_t::local_datetime : {return parse_local_datetime(loc); }
case value_t::LocalDate : {return parse_local_date(loc); } case value_t::local_date : {return parse_local_date(loc); }
case value_t::LocalTime : {return parse_local_time(loc); } case value_t::local_time : {return parse_local_time(loc); }
case value_t::Array : {return parse_array(loc); } case value_t::array : {return parse_array<value_type>(loc); }
case value_t::Table : {return parse_inline_table(loc); } case value_t::table : {return parse_inline_table<value_type>(loc);}
default: default:
{ {
const auto msg = format_underline("[error] toml::parse_value: " const auto msg = format_underline("[error] toml::parse_value: "
@@ -1594,13 +1608,17 @@ parse_array_table_key(location<Container>& loc)
} }
// parse table body (key-value pairs until the iter hits the next [tablekey]) // parse table body (key-value pairs until the iter hits the next [tablekey])
template<typename Container> template<typename Value, typename Container>
result<table, std::string> parse_ml_table(location<Container>& loc) result<typename Value::table_type, std::string>
parse_ml_table(location<Container>& loc)
{ {
using value_type = Value;
using table_type = typename value_type::table_type;
const auto first = loc.iter(); const auto first = loc.iter();
if(first == loc.end()) if(first == loc.end())
{ {
return ok(toml::table{}); return ok(table_type{});
} }
// XXX at lest one newline is needed. // XXX at lest one newline is needed.
@@ -1608,7 +1626,7 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>; sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>;
skip_line::invoke(loc); skip_line::invoke(loc);
table tab; table_type tab;
while(loc.iter() != loc.end()) while(loc.iter() != loc.end())
{ {
lex_ws::invoke(loc); lex_ws::invoke(loc);
@@ -1624,11 +1642,11 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
return ok(tab); return ok(tab);
} }
if(const auto kv = parse_key_value_pair(loc)) if(const auto kv = parse_key_value_pair<value_type>(loc))
{ {
const std::vector<key>& keys = kv.unwrap().first.first; const std::vector<key>& keys = kv.unwrap().first.first;
const region<Container>& key_reg = kv.unwrap().first.second; const region<Container>& key_reg = kv.unwrap().first.second;
const value& val = kv.unwrap().second; const value_type& val = kv.unwrap().second;
const auto inserted = const auto inserted =
insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg); insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg);
if(!inserted) if(!inserted)
@@ -1673,18 +1691,21 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
return ok(tab); return ok(tab);
} }
template<typename Container> template<typename Value, typename Container>
result<table, std::string> parse_toml_file(location<Container>& loc) result<Value, std::string> parse_toml_file(location<Container>& loc)
{ {
using value_type = Value;
using table_type = typename value_type::table_type;
const auto first = loc.iter(); const auto first = loc.iter();
if(first == loc.end()) if(first == loc.end())
{ {
return ok(toml::table{}); return ok(value_type(table_type{}));
} }
table data; table_type data;
// root object is also a table, but without [tablename] // root object is also a table, but without [tablename]
if(auto tab = parse_ml_table(loc)) if(auto tab = parse_ml_table<value_type>(loc))
{ {
data = std::move(tab.unwrap()); data = std::move(tab.unwrap());
} }
@@ -1700,14 +1721,14 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
// message. // message.
if(const auto tabkey = parse_array_table_key(loc)) if(const auto tabkey = parse_array_table_key(loc))
{ {
const auto tab = parse_ml_table(loc); const auto tab = parse_ml_table<value_type>(loc);
if(!tab){return err(tab.unwrap_err());} if(!tab){return err(tab.unwrap_err());}
const auto& keys = tabkey.unwrap().first; const auto& keys = tabkey.unwrap().first;
const auto& reg = tabkey.unwrap().second; const auto& reg = tabkey.unwrap().second;
const auto inserted = insert_nested_key(data, const auto inserted = insert_nested_key(data,
toml::value(tab.unwrap(), reg), value_type(tab.unwrap(), reg),
keys.begin(), keys.end(), reg, keys.begin(), keys.end(), reg,
/*is_array_of_table=*/ true); /*is_array_of_table=*/ true);
if(!inserted) {return err(inserted.unwrap_err());} if(!inserted) {return err(inserted.unwrap_err());}
@@ -1716,14 +1737,14 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
} }
if(const auto tabkey = parse_table_key(loc)) if(const auto tabkey = parse_table_key(loc))
{ {
const auto tab = parse_ml_table(loc); const auto tab = parse_ml_table<value_type>(loc);
if(!tab){return err(tab.unwrap_err());} if(!tab){return err(tab.unwrap_err());}
const auto& keys = tabkey.unwrap().first; const auto& keys = tabkey.unwrap().first;
const auto& reg = tabkey.unwrap().second; const auto& reg = tabkey.unwrap().second;
const auto inserted = insert_nested_key(data, const auto inserted = insert_nested_key(data,
toml::value(tab.unwrap(), reg), keys.begin(), keys.end(), reg); value_type(tab.unwrap(), reg), keys.begin(), keys.end(), reg);
if(!inserted) {return err(inserted.unwrap_err());} if(!inserted) {return err(inserted.unwrap_err());}
continue; continue;
@@ -1736,8 +1757,14 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
} // detail } // detail
inline table parse(std::istream& is, std::string fname = "unknown file") template<typename Comment = ::toml::discard_comments,
template<typename ...> class Table = std::unordered_map,
template<typename ...> class Array = std::vector>
basic_value<Comment, Table, Array>
parse(std::istream& is, const std::string& fname = "unknown file")
{ {
using value_type = basic_value<Comment, Table, Array>;
const auto beg = is.tellg(); const auto beg = is.tellg();
is.seekg(0, std::ios::end); is.seekg(0, std::ios::end);
const auto end = is.tellg(); const auto end = is.tellg();
@@ -1767,7 +1794,7 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
} }
} }
const auto data = detail::parse_toml_file(loc); const auto data = detail::parse_toml_file<value_type>(loc);
if(!data) if(!data)
{ {
throw syntax_error(data.unwrap_err()); throw syntax_error(data.unwrap_err());
@@ -1775,14 +1802,17 @@ inline table parse(std::istream& is, std::string fname = "unknown file")
return data.unwrap(); return data.unwrap();
} }
inline table parse(const std::string& fname) template<typename Comment = ::toml::discard_comments,
template<typename ...> class Table = std::unordered_map,
template<typename ...> class Array = std::vector>
inline basic_value<Comment, Table, Array> parse(const std::string& fname)
{ {
std::ifstream ifs(fname.c_str(), std::ios_base::binary); std::ifstream ifs(fname.c_str(), std::ios_base::binary);
if(!ifs.good()) if(!ifs.good())
{ {
throw std::runtime_error("toml::parse: file open error -> " + fname); throw std::runtime_error("toml::parse: file open error -> " + fname);
} }
return parse(ifs, fname); return parse<Comment, Table, Array>(ifs, fname);
} }
} // toml } // toml