diff --git a/toml/parser.hpp b/toml/parser.hpp index aa36d0b..99eea49 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -13,14 +13,15 @@ namespace detail { template -result parse_boolean(location& loc) +result>, std::string> +parse_boolean(location& loc) { const auto first = loc.iter(); if(const auto token = lex_boolean::invoke(loc)) { const auto reg = token.unwrap(); - if (reg.str() == "true") {return ok(true);} - else if(reg.str() == "false") {return ok(false);} + if (reg.str() == "true") {return ok(std::make_pair(true, reg));} + else if(reg.str() == "false") {return ok(std::make_pair(false, reg));} else // internal error. { throw toml::internal_error(format_underline( @@ -34,7 +35,8 @@ result parse_boolean(location& loc) } template -result parse_binary_integer(location& loc) +result>, std::string> +parse_binary_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_bin_int::invoke(loc)) @@ -54,7 +56,7 @@ result parse_binary_integer(location& loc) token.unwrap(), "invalid token")); } } - return ok(retval); + return ok(std::make_pair(retval, token.unwrap())); } loc.iter() = first; return err(format_underline("[error] toml::parse_binary_integer", loc, @@ -62,7 +64,8 @@ result parse_binary_integer(location& loc) } template -result parse_octal_integer(location& loc) +result>, std::string> +parse_octal_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_oct_int::invoke(loc)) @@ -74,7 +77,7 @@ result parse_octal_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> std::oct >> retval; - return ok(retval); + return ok(std::make_pair(retval, token.unwrap())); } loc.iter() = first; @@ -83,7 +86,8 @@ result parse_octal_integer(location& loc) } template -result parse_hexadecimal_integer(location& loc) +result>, std::string> +parse_hexadecimal_integer(location& loc) { const auto first = loc.iter(); if(const auto token = lex_hex_int::invoke(loc)) @@ -95,7 +99,7 @@ result parse_hexadecimal_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> std::hex >> retval; - return ok(retval); + return ok(std::make_pair(retval, token.unwrap())); } loc.iter() = first; return err(format_underline("[error] toml::parse_hexadecimal_integer", loc, @@ -103,7 +107,8 @@ result parse_hexadecimal_integer(location& loc) } template -result parse_integer(location& loc) +result>, std::string> +parse_integer(location& loc) { const auto first = loc.iter(); if(first != loc.end() && *first == '0') @@ -111,6 +116,7 @@ result parse_integer(location& loc) if(const auto bin = parse_binary_integer (loc)) {return bin;} if(const auto oct = parse_octal_integer (loc)) {return oct;} if(const auto hex = parse_hexadecimal_integer(loc)) {return hex;} + // else, maybe just zero. } if(const auto token = lex_dec_int::invoke(loc)) @@ -121,7 +127,7 @@ result parse_integer(location& loc) std::istringstream iss(str); integer retval(0); iss >> retval; - return ok(retval); + return ok(std::make_pair(retval, token.unwrap())); } loc.iter() = first; return err(format_underline("[error] toml::parse_integer", loc, @@ -131,7 +137,8 @@ result parse_integer(location& loc) } template -result parse_floating(location& loc) +result>, std::string> +parse_floating(location& loc) { const auto first = loc.iter(); if(const auto token = lex_float::invoke(loc)) @@ -141,7 +148,8 @@ result parse_floating(location& loc) { if(std::numeric_limits::has_infinity) { - return ok(std::numeric_limits::infinity()); + return ok(std::make_pair( + std::numeric_limits::infinity(), token.unwrap())); } else { @@ -155,7 +163,8 @@ result parse_floating(location& loc) { if(std::numeric_limits::has_infinity) { - return ok(-std::numeric_limits::infinity()); + return ok(std::make_pair( + -std::numeric_limits::infinity(), token.unwrap())); } else { @@ -169,11 +178,13 @@ result parse_floating(location& loc) { if(std::numeric_limits::has_quiet_NaN) { - return ok(std::numeric_limits::quiet_NaN()); + return ok(std::make_pair( + std::numeric_limits::quiet_NaN(), token.unwrap())); } else if(std::numeric_limits::has_signaling_NaN) { - return ok(std::numeric_limits::signaling_NaN()); + return ok(std::make_pair( + std::numeric_limits::signaling_NaN(), token.unwrap())); } else { @@ -187,11 +198,13 @@ result parse_floating(location& loc) { if(std::numeric_limits::has_quiet_NaN) { - return ok(-std::numeric_limits::quiet_NaN()); + return ok(std::make_pair( + -std::numeric_limits::quiet_NaN(), token.unwrap())); } else if(std::numeric_limits::has_signaling_NaN) { - return ok(-std::numeric_limits::signaling_NaN()); + return ok(std::make_pair( + -std::numeric_limits::signaling_NaN(), token.unwrap())); } else { @@ -205,7 +218,7 @@ result parse_floating(location& loc) std::istringstream iss(str); floating v(0.0); iss >> v; - return ok(v); + return ok(std::make_pair(v, token.unwrap())); } loc.iter() = first; return err(format_underline("[error] toml::parse_floating: ", loc, @@ -320,7 +333,7 @@ result parse_escape_sequence(location& loc) } template -result +result>, std::string> parse_ml_basic_string(location& loc) { const auto first = loc.iter(); @@ -366,7 +379,7 @@ parse_ml_basic_string(location& loc) } delim = lex_ml_basic_string_delim::invoke(inner_loc); } - return ok(toml::string(retval)); + return ok(std::make_pair(toml::string(retval), token.unwrap())); } else { @@ -376,7 +389,8 @@ parse_ml_basic_string(location& loc) } template -result parse_basic_string(location& loc) +result>, std::string> +parse_basic_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_basic_string::invoke(loc)) @@ -413,7 +427,7 @@ result parse_basic_string(location& loc) } quot = lex_quotation_mark::invoke(inner_loc); } - return ok(toml::string(retval)); + return ok(std::make_pair(toml::string(retval), token.unwrap())); } else { @@ -423,7 +437,7 @@ result parse_basic_string(location& loc) } template -result +result>, std::string> parse_ml_literal_string(location& loc) { const auto first = loc.iter(); @@ -450,7 +464,9 @@ parse_ml_literal_string(location& loc) "parse_ml_literal_string: invalid token", inner_loc, "should be '''")); } - return ok(toml::string(body.unwrap().str())); + return ok(std::make_pair( + toml::string(body.unwrap().str(), toml::string_t::literal), + token.unwrap())); } else { @@ -460,7 +476,8 @@ parse_ml_literal_string(location& loc) } template -result parse_literal_string(location& loc) +result>, std::string> +parse_literal_string(location& loc) { const auto first = loc.iter(); if(const auto token = lex_literal_string::invoke(loc)) @@ -484,7 +501,9 @@ result parse_literal_string(location& loc) "parse_literal_string: invalid token", inner_loc, "should be '")); } - return ok(toml::string(body.unwrap().str())); + return ok(std::make_pair( + toml::string(body.unwrap().str(), toml::string_t::literal), + token.unwrap())); } else { @@ -494,30 +513,20 @@ result parse_literal_string(location& loc) } template -result parse_string(location& loc) +result>, std::string> +parse_string(location& loc) { - if(const auto rslt = parse_ml_basic_string(loc)) - { - return ok(rslt.unwrap()); - } - if(const auto rslt = parse_ml_literal_string(loc)) - { - return ok(rslt.unwrap()); - } - if(const auto rslt = parse_basic_string(loc)) - { - return ok(rslt.unwrap()); - } - if(const auto rslt = parse_literal_string(loc)) - { - return ok(rslt.unwrap()); - } + if(const auto rslt = parse_ml_basic_string(loc)) {return rslt;} + if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;} + if(const auto rslt = parse_basic_string(loc)) {return rslt;} + if(const auto rslt = parse_literal_string(loc)) {return rslt;} return err(format_underline("[error] toml::parse_string: not a string", loc, "not a string")); } template -result parse_local_date(location& loc) +result>, std::string> +parse_local_date(location& loc) { const auto first = loc.iter(); if(const auto token = lex_local_date::invoke(loc)) @@ -551,11 +560,12 @@ result parse_local_date(location& loc) "toml::parse_local_date: invalid day format", inner_loc, d.unwrap_err())); } - return ok(local_date( + return ok(std::make_pair(local_date( static_cast(from_string(y.unwrap().str(), 0)), static_cast( static_cast(from_string(m.unwrap().str(), 0)-1)), - static_cast(from_string(d.unwrap().str(), 0)))); + static_cast(from_string(d.unwrap().str(), 0))), + token.unwrap())); } else { @@ -568,7 +578,8 @@ result parse_local_date(location& loc) } template -result parse_local_time(location& loc) +result>, std::string> +parse_local_time(location& loc) { const auto first = loc.iter(); if(const auto token = lex_local_time::invoke(loc)) @@ -639,7 +650,7 @@ result parse_local_time(location& loc) inner_loc, secfrac.unwrap_err())); } } - return ok(time); + return ok(std::make_pair(time, token.unwrap())); } else { @@ -652,7 +663,7 @@ result parse_local_time(location& loc) } template -result +result>, std::string> parse_local_datetime(location& loc) { const auto first = loc.iter(); @@ -682,7 +693,9 @@ parse_local_datetime(location& loc) "toml::parse_local_datetime: invalid datetime format", inner_loc, "invalid time fomrat")); } - return ok(local_datetime(date.unwrap(), time.unwrap())); + return ok(std::make_pair( + local_datetime(date.unwrap().first, time.unwrap().first), + token.unwrap())); } else { @@ -695,7 +708,7 @@ parse_local_datetime(location& loc) } template -result +result>, std::string> parse_offset_datetime(location& loc) { const auto first = loc.iter(); @@ -732,7 +745,8 @@ parse_offset_datetime(location& loc) "toml::parse_offset_datetime: invalid datetime format", inner_loc, "should be `Z` or `+HH:MM`")); } - return ok(offset_datetime(datetime.unwrap(), offset)); + return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset), + token.unwrap())); } else { @@ -750,11 +764,11 @@ result parse_simple_key(location& loc) { if(const auto bstr = parse_basic_string(loc)) { - return ok(bstr.unwrap().str); + return ok(bstr.unwrap().first.str); } if(const auto lstr = parse_literal_string(loc)) { - return ok(lstr.unwrap().str); + return ok(lstr.unwrap().first.str); } if(const auto bare = lex_unquoted_key::invoke(loc)) { @@ -821,7 +835,8 @@ template result parse_value(location&); template -result parse_array(location& loc) +result>, std::string> +parse_array(location& loc) { const auto first = loc.iter(); if(loc.iter() == loc.end()) @@ -846,7 +861,8 @@ result parse_array(location& loc) if(loc.iter() != loc.end() && *loc.iter() == ']') { ++loc.iter(); // skip ']' - return ok(retval); + return ok(std::make_pair(retval, + region(loc, first, loc.iter()))); } if(auto val = parse_value(loc)) @@ -867,7 +883,8 @@ result parse_array(location& loc) if(loc.iter() != loc.end() && *loc.iter() == ']') { ++loc.iter(); // skip ']' - return ok(retval); + return ok(std::make_pair(retval, + region(loc, first, loc.iter()))); } else { @@ -1019,7 +1036,8 @@ insert_nested_key(table& root, const toml::value& v, } template -result parse_inline_table(location& loc) +result>, std::string> +parse_inline_table(location& loc) { const auto first = loc.iter(); table retval; @@ -1035,7 +1053,8 @@ result parse_inline_table(location& loc) if(loc.iter() != loc.end() && *loc.iter() == '}') { ++loc.iter(); // skip `}` - return ok(retval); + return ok(std::make_pair( + retval, region(loc, first, loc.iter()))); } const auto kv_r = parse_key_value_pair(loc); @@ -1062,7 +1081,8 @@ result parse_inline_table(location& loc) if(loc.iter() != loc.end() && *loc.iter() == '}') { ++loc.iter(); // skip `}` - return ok(retval); + return ok(std::make_pair( + retval, region(loc, first, loc.iter()))); } else { @@ -1084,16 +1104,26 @@ result parse_value(location& loc) { return err(std::string("[error] toml::parse_value: input is empty")); } - if(auto r = parse_string (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_array (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_inline_table (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_boolean (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_offset_datetime(loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_local_datetime (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_local_date (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_local_time (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_floating (loc)) {return ok(value(std::move(r.unwrap())));} - if(auto r = parse_integer (loc)) {return ok(value(std::move(r.unwrap())));} + if(auto r = parse_string (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_array (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_inline_table (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_boolean (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_offset_datetime(loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_local_datetime (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_local_date (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_local_time (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_floating (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} + if(auto r = parse_integer (loc)) + {return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));} const auto msg = format_underline("[error] toml::parse_value: " "unknown token appeared", loc, "unknown"); @@ -1102,7 +1132,8 @@ result parse_value(location& loc) } template -result, std::string> parse_table_key(location& loc) +result, region>, std::string> +parse_table_key(location& loc) { if(auto token = lex_std_table::invoke(loc)) { @@ -1126,7 +1157,7 @@ result, std::string> parse_table_key(location& loc) throw internal_error(format_underline("[error] " "toml::parse_table_key: no `]`", inner_loc, "should be `]`")); } - return keys; + return ok(std::make_pair(keys.unwrap(), token.unwrap())); } else { @@ -1135,7 +1166,7 @@ result, std::string> parse_table_key(location& loc) } template -result, std::string> +result, region>, std::string> parse_array_table_key(location& loc) { if(auto token = lex_array_table::invoke(loc)) @@ -1162,7 +1193,7 @@ parse_array_table_key(location& loc) throw internal_error(format_underline("[error] " "toml::parse_table_key: no `]]`", inner_loc, "should be `]]`")); } - return keys; + return ok(std::make_pair(keys.unwrap(), token.unwrap())); } else { @@ -1241,19 +1272,27 @@ result parse_toml_file(location& loc) { data = std::move(tab.unwrap()); } - else // failed (empty table is also success) + else // failed (empty table is regarded as success in parse_ml_table) { return err(tab.unwrap_err()); } while(loc.iter() != loc.end()) { + // here, the region of [table] is regarded as the table-key because + // the table body is normally too big and it is not so informative + // if the first key-value pair of the table is shown in the error + // message. 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); + const auto& keys = tabkey.unwrap().first; + const auto& reg = tabkey.unwrap().second; + + const auto inserted = insert_nested_key(data, + toml::value(tab.unwrap(), reg), + keys.begin(), keys.end(), /*is_array_of_table=*/ true); if(!inserted) {return err(inserted.unwrap_err());} continue; @@ -1263,8 +1302,11 @@ result parse_toml_file(location& 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()); + const auto& keys = tabkey.unwrap().first; + const auto& reg = tabkey.unwrap().second; + + const auto inserted = insert_nested_key(data, + toml::value(tab.unwrap(), reg), keys.begin(), keys.end()); if(!inserted) {return err(inserted.unwrap_err());} continue;