diff --git a/toml/parser.hpp b/toml/parser.hpp index ab309fb..07a23d5 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -1331,7 +1331,7 @@ result parse_ml_table(location& loc) return err(std::string("toml::parse_ml_table: input is empty")); } - // XXX at lest one newline is needed + // XXX at lest one newline is needed. using skip_line = repeat< sequence, maybe, lex_newline>, at_least<1>>; skip_line::invoke(loc); @@ -1367,6 +1367,17 @@ result parse_ml_table(location& loc) return err(kv.unwrap_err()); } + // comment lines are skipped by the above function call. + // However, since the `skip_line` requires at least 1 newline, it fails + // if the file ends with ws and/or comment without newline. + // `skip_line` matches `ws? + comment? + newline`, not `ws` or `comment` + // itself. To skip the last ws and/or comment, call lexers. + // It does not matter if these fails, so the return value is discarded. + lex_ws::invoke(loc); + lex_comment::invoke(loc); + + // skip_line is (whitespace? comment? newline)_{1,}. multiple empty lines + // and comments after the last key-value pairs are allowed. const auto newline = skip_line::invoke(loc); if(!newline && loc.iter() != loc.end()) { @@ -1379,11 +1390,10 @@ result parse_ml_table(location& loc) return err(msg); } - // 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. + // the skip_lines only matches with lines that includes newline. + // to skip the last line that includes comment and/or whitespace + // but no newline, call them one more time. + lex_ws::invoke(loc); lex_comment::invoke(loc); } return ok(tab);