diff --git a/include/fkYAML/detail/input/lexical_analyzer.hpp b/include/fkYAML/detail/input/lexical_analyzer.hpp index ecae08eb..7d94bd2b 100644 --- a/include/fkYAML/detail/input/lexical_analyzer.hpp +++ b/include/fkYAML/detail/input/lexical_analyzer.hpp @@ -396,6 +396,16 @@ class lexical_analyzer { /// @brief Skip until a newline code or a null character is found. void scan_comment() { FK_YAML_ASSERT(*m_cur_itr == '#'); + if FK_YAML_LIKELY (m_cur_itr != m_begin_itr) { + switch (*(m_cur_itr - 1)) { + case ' ': + case '\t': + case '\n': + break; + default: + emit_error("Comment must not begin right after non-break characters"); + } + } skip_until_line_end(); } diff --git a/single_include/fkYAML/node.hpp b/single_include/fkYAML/node.hpp index 30dcf0bf..784953f3 100644 --- a/single_include/fkYAML/node.hpp +++ b/single_include/fkYAML/node.hpp @@ -3698,6 +3698,16 @@ class lexical_analyzer { /// @brief Skip until a newline code or a null character is found. void scan_comment() { FK_YAML_ASSERT(*m_cur_itr == '#'); + if FK_YAML_LIKELY (m_cur_itr != m_begin_itr) { + switch (*(m_cur_itr - 1)) { + case ' ': + case '\t': + case '\n': + break; + default: + emit_error("Comment must not begin right after non-break characters"); + } + } skip_until_line_end(); } diff --git a/tests/unit_test/test_lexical_analyzer_class.cpp b/tests/unit_test/test_lexical_analyzer_class.cpp index b8273ee3..837b49a1 100644 --- a/tests/unit_test/test_lexical_analyzer_class.cpp +++ b/tests/unit_test/test_lexical_analyzer_class.cpp @@ -235,6 +235,31 @@ TEST_CASE("LexicalAnalyzer_EndOfDocuments") { REQUIRE(token.type == fkyaml::detail::lexical_token_t::END_OF_BUFFER); } +TEST_CASE("LexicalAnalyzer_Comment") { + fkyaml::detail::lexical_token token; + + SECTION("valid comments") { + auto input = GENERATE( + fkyaml::detail::str_view("# comment"), + fkyaml::detail::str_view(" # comment"), + fkyaml::detail::str_view("\t# comment\n"), + fkyaml::detail::str_view("\n# comment")); + fkyaml::detail::lexical_analyzer lexer(input); + REQUIRE_NOTHROW(token = lexer.get_next_token()); + REQUIRE(token.type == fkyaml::detail::lexical_token_t::END_OF_BUFFER); + } + + // regression test for https://github.com/fktn-k/fkYAML/pull/469 + SECTION("invalid comments") { + fkyaml::detail::str_view input("\'foo\'#invalid"); + fkyaml::detail::lexical_analyzer lexer(input); + REQUIRE_NOTHROW(token = lexer.get_next_token()); + REQUIRE(token.type == fkyaml::detail::lexical_token_t::SINGLE_QUOTED_SCALAR); + REQUIRE(token.str == "foo"); + REQUIRE_THROWS_AS(lexer.get_next_token(), fkyaml::parse_error); + } +} + TEST_CASE("LexicalAnalyzer_Colon") { fkyaml::detail::lexical_token token;