Closed rowlesmr closed 1 year ago
I can't see anything obviously wrong, either. Can you reduce your code into a small but complete example and post it?
How's this? I've collapsed the namespaces and deleted a bunch of rules that aren't necessary for the example to work. The only rules I've changed are value
and unquoted_string
in order to remove rules that I've removed. Everything is still in the same order as in the real file. I've maintained the same level of indirections through various rules due to the actions I need to take (I've removed those as well).
Compiling in MSVC, Visual Studio 2022 (v143), /O2 /Ot.
Using /std:c++17, /std:c++20, and /std:c++latest, the development version always fails to build with
tao_dev\pegtl\must_if.hpp(61,34): error C2338: static_assert failed: 'explicit error message required for Rule'
Using /std:c++17, /std:c++20, and /std:c++latest, the 3.x branch always fails to build with
tao_3\pegtl\must_if.hpp(50,64): error C2338: static_assert failed: 'Errors::template message< Rule > != nullptr'
additionally, under /std:c++20, and /std:c++latest, there is also
error C4996: '_Header_ciso646': warning STL4036: <ciso646> is removed in C++20. You can define _SILENCE_CXX20_CISO646_REMOVED_WARNING or _SILENCE_ALL_CXX20_DEPRECATION_WARNINGS to suppress this warning.
#include "tao_dev/pegtl.hpp"
namespace row
{
namespace pegtl = tao::pegtl;
namespace pegtl8 = tao::pegtl::utf8;
//reserved words
struct DATA : TAO_PEGTL_ISTRING("data_") {};
struct non_blank_char : pegtl8::ranges<0x0021, 0x007E, 0x00A0, 0xD7FF, 0xE000, 0xFDCF, 0xFDF0, 0xFFFD, 0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, 0xF0000, 0xFFFFD, 0x100000, 0x10FFFD> {};
struct restrict_char : pegtl8::ranges<0x0021, 0x005A, 0x005C, 0x005C, 0x005E, 0x007A, 0x007C, 0x007C, 0x007E, 0x007E, 0x00A0, 0xD7FF, 0xE000, 0xFDCF, 0xFDF0, 0xFFFD, 0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, 0xF0000, 0xFFFFD, 0x100000, 0x10FFFD> {};
struct lead_char : pegtl8::ranges<0x0021, 0x0021, 0x0025, 0x0026, 0x0028, 0x005A, 0x005C, 0x005C, 0x005E, 0x005E, 0x0060, 0x007A, 0x007C, 0x007C, 0x007E, 0x007E, 0x00A0, 0xD7FF, 0xE000, 0xFDCF, 0xFDF0, 0xFFFD, 0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, 0xF0000, 0xFFFFD, 0x100000, 0x10FFFD> {};
//Whitespace, and comments
struct line_term : pegtl::sor<pegtl::seq<pegtl::one<'\r'>, pegtl::opt<pegtl::one<'\n'>>>, pegtl::one<'\n'>> {};
struct comment : pegtl::if_must<pegtl::one<'#'>, pegtl::until<pegtl::eolf>> {};
struct ws : pegtl::blank {};
struct wschar : pegtl::sor<ws, line_term> {};
struct whitespace : pegtl::plus<pegtl::sor<wschar, comment>> {};
struct ws_or_eof : pegtl::sor<whitespace, pegtl::eof> {};
//unquoted string
struct unquoted_string : pegtl::seq<lead_char, pegtl::star<restrict_char>> {};
//other values
struct lst;
struct value : pegtl::sor<unquoted_string, lst> {};
//List
struct lst_begin : pegtl::one<'['> {};
struct lst_end : pegtl::one<']'> {};
struct lst_value : value {};
struct lst_values : pegtl::opt<pegtl::opt<whitespace>, lst_value, pegtl::star<whitespace, lst_value>> {};
struct lst : pegtl::if_must<lst_begin, lst_values, /*pegtl::opt<whitespace>,*/ lst_end> {}; //rule is broken to test error messages
//Actions:
template<typename Rule>
struct action : pegtl::nothing<Rule> {};
template<> struct action< lst > {
template<typename Input> static void apply(const Input& in) {
std::cout << "The list is done.\n";
}
};
//Error messages:
template< typename >
inline constexpr const char* error_message = nullptr;
template<>
inline constexpr auto error_message< lst_end > = "Test123";
struct error {
template< typename Rule >
static constexpr auto message = error_message< Rule >;
};
template< typename Rule >
using control = pegtl::must_if< error >::control< Rule >;
}
int main()
{
std::string bad_string{"[ q w e ]"};
std::string good_string{"[ q w e]"};
tao::pegtl::string_input<tao::pegtl::tracking_mode::eager, tao::pegtl::eol::lf_crlf> in(bad_string, "string");
try
{
tao::pegtl::parse< row::lst, row::action, row::control >(in); //tao::pegtl::normal
}
catch (const tao::pegtl::parse_error& e)
{
const auto p = e.positions().front();
std::cerr << e.what() << '\n'
<< in.line_at(p) << '\n'
<< std::setw(p.column) << '^' << std::endl;
}
}
I think the issue is that you have more rules to cover. Your grammar uses:
if_must< lst_begin, lst_values, lst_end >
meaning that you need to provide error message specializations for lst_end
, but also for lst_values
. Also, you grammar contains
if_must<one<'#'>, until<eolf>>
which means you also need to specialize for until<eolf>
. Once I add the two missing specializations, it start to compile. https://godbolt.org/z/fojoh8159
With other compilers, the error messages from the compiler also contain lst_values
and until<eolf>
to hint at which specializations are missing. I haven't tested it, but I think MSVC should also do this. But well... it's still C++ error messages and the PEGTL is quite heavy on templates, so it's definitely not easy to spot it immediately. ;)
Knowing the answer, I can now kind of parse the error messages. I can also see how I read the docs wrong. I'll have to see how I'd reword it.
until<eolf>
this is why it failed when I went nuclear and added all of my rules; I didn't add that one.
until<eolf>
this is why it failed when I went nuclear and added all of my rules; I didn't add that one.
Note that you probably don't want to specialize for until<eolf>
directly, as you might have this rule in several places in the future within your grammar. You would want to add struct comment_end : until<eolf> {};
, use that in your comment
rule and specialize for comment_end
.
You would want to add
struct comment_end : until<eolf> {};
, use that in yourcomment
rule and specialize forcomment_end
.
Wilco.
Can confirm. Adding those missing rules enabled compilation.
I am getting a static assert error:
error C2338: static_assert failed: 'explicit error message required for Rule'
(from line 61 of tao\pegtl\must_if.hpp). I don't understand what I need to do to satisfy the assert, or even when the error means.If I run the error message example, it works, so I know my setup can allow it to happen.
.
As an example, I have an input which fails with the error message:
I would like to specialise the error message.
From the examples, I've put together:
and then called the parse function as
I can't see anything obviously wrong with what I've done, unless I've put an error message on something that shouldn't, or need to put a message on something else.
. I have to see if I can make up a mwe without breaking anything else.