mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-09-17 17:58:09 +08:00
add toml::parse
This commit is contained in:
212
toml/parser.hpp
212
toml/parser.hpp
@@ -632,7 +632,7 @@ result<local_time, std::string> parse_local_time(location<Container>& loc)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(before_secfrac != loc.iter())
|
if(before_secfrac != inner_loc.iter())
|
||||||
{
|
{
|
||||||
throw internal_error(format_underline("[error]: "
|
throw internal_error(format_underline("[error]: "
|
||||||
"toml::parse_local_time: invalid subsecond format",
|
"toml::parse_local_time: invalid subsecond format",
|
||||||
@@ -1096,11 +1096,219 @@ result<value, std::string> parse_value(location<Container>& loc)
|
|||||||
if(auto r = parse_integer (loc)) {return ok(value(std::move(r.unwrap())));}
|
if(auto r = parse_integer (loc)) {return ok(value(std::move(r.unwrap())));}
|
||||||
|
|
||||||
const auto msg = format_underline("[error] toml::parse_value: "
|
const auto msg = format_underline("[error] toml::parse_value: "
|
||||||
"unknown token appeared", loc, "unknown", std::move(helps));
|
"unknown token appeared", loc, "unknown");
|
||||||
loc.iter() = first;
|
loc.iter() = first;
|
||||||
return err(msg);
|
return err(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
result<std::vector<key>, std::string> parse_table_key(location<Container>& loc)
|
||||||
|
{
|
||||||
|
if(auto token = lex_std_table::invoke(loc))
|
||||||
|
{
|
||||||
|
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||||
|
|
||||||
|
const auto open = lex_std_table_open::invoke(inner_loc);
|
||||||
|
if(!open || inner_loc.iter() == inner_loc.end())
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_table_key: no `[`", inner_loc, "should be `[`"));
|
||||||
|
}
|
||||||
|
const auto keys = parse_key(inner_loc);
|
||||||
|
if(!keys)
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_table_key: invalid key", inner_loc, "not key"));
|
||||||
|
}
|
||||||
|
const auto close = lex_std_table_close::invoke(inner_loc);
|
||||||
|
if(!close)
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_table_key: no `]`", inner_loc, "should be `]`"));
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return err(token.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
result<std::vector<key>, std::string>
|
||||||
|
parse_array_table_key(location<Container>& loc)
|
||||||
|
{
|
||||||
|
if(auto token = lex_array_table::invoke(loc))
|
||||||
|
{
|
||||||
|
location<std::string> inner_loc(loc.name(), token.unwrap().str());
|
||||||
|
|
||||||
|
const auto open = lex_array_table_open::invoke(inner_loc);
|
||||||
|
if(!open || inner_loc.iter() == inner_loc.end())
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_array_table_key: no `[[`", inner_loc,
|
||||||
|
"should be `[[`"));
|
||||||
|
}
|
||||||
|
const auto keys = parse_key(inner_loc);
|
||||||
|
if(!keys)
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_array_table_key: invalid key", inner_loc,
|
||||||
|
"not key"));
|
||||||
|
}
|
||||||
|
const auto close = lex_array_table_close::invoke(inner_loc);
|
||||||
|
if(!close)
|
||||||
|
{
|
||||||
|
throw internal_error(format_underline("[error] "
|
||||||
|
"toml::parse_table_key: no `]]`", inner_loc, "should be `]]`"));
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return err(token.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse table body (key-value pairs until the iter hits the next [tablekey])
|
||||||
|
template<typename Container>
|
||||||
|
result<table, std::string> parse_ml_table(location<Container>& loc)
|
||||||
|
{
|
||||||
|
const auto first = loc.iter();
|
||||||
|
if(first == loc.end())
|
||||||
|
{
|
||||||
|
return err(std::string("toml::parse_ml_table: input is empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
using skip_line = repeat<
|
||||||
|
sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, unlimited>;
|
||||||
|
skip_line::invoke(loc);
|
||||||
|
|
||||||
|
table tab;
|
||||||
|
while(loc.iter() != loc.end())
|
||||||
|
{
|
||||||
|
lex_ws::invoke(loc);
|
||||||
|
const auto before = loc.iter();
|
||||||
|
if(const auto tmp = parse_array_table_key(loc)) // next table found
|
||||||
|
{
|
||||||
|
loc.iter() = before;
|
||||||
|
return ok(tab);
|
||||||
|
}
|
||||||
|
if(const auto tmp = parse_table_key(loc)) // next table found
|
||||||
|
{
|
||||||
|
loc.iter() = before;
|
||||||
|
return ok(tab);
|
||||||
|
}
|
||||||
|
if(const auto kv = parse_key_value_pair(loc))
|
||||||
|
{
|
||||||
|
const std::vector<key>& keys = kv.unwrap().first;
|
||||||
|
const value& val = kv.unwrap().second;
|
||||||
|
const auto inserted =
|
||||||
|
insert_nested_key(tab, val, keys.begin(), keys.end());
|
||||||
|
if(!inserted)
|
||||||
|
{
|
||||||
|
return err(inserted.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return err(kv.unwrap_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_line::invoke(loc);
|
||||||
|
// comment lines are skipped by the above function call.
|
||||||
|
// However, if the file ends with comment without newline,
|
||||||
|
// it might cause parsing error because skip_line matches
|
||||||
|
// `comment + newline`, not `comment` itself. to skip the
|
||||||
|
// last comment, call lex_comment one more time.
|
||||||
|
lex_comment::invoke(loc);
|
||||||
|
}
|
||||||
|
return ok(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
result<table, std::string> parse_toml_file(location<Container>& loc)
|
||||||
|
{
|
||||||
|
const auto first = loc.iter();
|
||||||
|
if(first == loc.end())
|
||||||
|
{
|
||||||
|
return err(std::string("toml::detail::parse_toml_file: input is empty"));
|
||||||
|
}
|
||||||
|
|
||||||
|
table data;
|
||||||
|
/* root object is also table, but without [tablename] */
|
||||||
|
if(auto tab = parse_ml_table(loc))
|
||||||
|
{
|
||||||
|
data = std::move(tab.unwrap());
|
||||||
|
}
|
||||||
|
else // failed (empty table is also success)
|
||||||
|
{
|
||||||
|
return err(tab.unwrap_err());
|
||||||
|
}
|
||||||
|
while(loc.iter() != loc.end())
|
||||||
|
{
|
||||||
|
if(const auto tabkey = parse_array_table_key(loc))
|
||||||
|
{
|
||||||
|
const auto tab = parse_ml_table(loc);
|
||||||
|
if(!tab){return err(tab.unwrap_err());}
|
||||||
|
|
||||||
|
const auto inserted = insert_nested_key(data, tab.unwrap(),
|
||||||
|
tabkey.unwrap().begin(), tabkey.unwrap().end(), true);
|
||||||
|
if(!inserted) {return err(inserted.unwrap_err());}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(const auto tabkey = parse_table_key(loc))
|
||||||
|
{
|
||||||
|
const auto tab = parse_ml_table(loc);
|
||||||
|
if(!tab){return err(tab.unwrap_err());}
|
||||||
|
|
||||||
|
const auto inserted = insert_nested_key(data, tab.unwrap(),
|
||||||
|
tabkey.unwrap().begin(), tabkey.unwrap().end());
|
||||||
|
if(!inserted) {return err(inserted.unwrap_err());}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return err(format_underline("[error]: toml::parse_toml_file: "
|
||||||
|
"unknown line appeared", loc, "unknown format"));
|
||||||
|
}
|
||||||
|
return ok(data);
|
||||||
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
inline table parse(std::istream& is, std::string fname = "unknown file")
|
||||||
|
{
|
||||||
|
const auto beg = is.tellg();
|
||||||
|
is.seekg(0, std::ios::end);
|
||||||
|
const auto end = is.tellg();
|
||||||
|
const auto fsize = end - beg;
|
||||||
|
is.seekg(beg);
|
||||||
|
|
||||||
|
// read whole file as a sequence of char
|
||||||
|
std::vector<char> letters(fsize);
|
||||||
|
is.read(letters.data(), fsize);
|
||||||
|
|
||||||
|
detail::location<std::vector<char>>
|
||||||
|
loc(std::move(fname), std::move(letters));
|
||||||
|
|
||||||
|
const auto data = detail::parse_toml_file(loc);
|
||||||
|
if(!data)
|
||||||
|
{
|
||||||
|
throw syntax_error(data.unwrap_err());
|
||||||
|
}
|
||||||
|
return data.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline table parse(const std::string& fname)
|
||||||
|
{
|
||||||
|
std::ifstream ifs(fname.c_str());
|
||||||
|
if(!ifs.good())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("toml::parse: file open error -> " + fname);
|
||||||
|
}
|
||||||
|
return parse(ifs, fname);
|
||||||
|
}
|
||||||
|
|
||||||
} // toml
|
} // toml
|
||||||
#endif// TOML11_PARSER_HPP
|
#endif// TOML11_PARSER_HPP
|
||||||
|
Reference in New Issue
Block a user