taocpp / PEGTL

Parsing Expression Grammar Template Library
Boost Software License 1.0
1.94k stars 228 forks source link

Q: raise failure from action? #69

Closed cppden closed 7 years ago

cppden commented 7 years ago

Is it possible to raise global error from an action? E.g., a grammar accepts 1..3 digits but there's additional constraint on the value in these digits, namely TTL can be 0..255 but not 256 or 999 which is valid by the grammar itself. In the action I can add a check for the range but how to trigger error? Tried to use throw tao::pegtl::parse_error but can't compile since: const class tao::pegtl::internal::action_input<tao::pegtl::lf_crlf_eol, (tao::pegtl::tracking_mode)1u>' has no member named 'position'

d-frey commented 7 years ago

This seems odd. It looks like your code is looking for a member named position, not a method called position. How are you calling the ctor? It should be something like:

throw tao::pegtl::parse_error( "my message", in );

Can you provide the actual code in case the problem persists?

cppden commented 7 years ago

Extracted all parts to prepare the code to show the problem and found out that with the current master code compiles fine (the code where I've faced the compilation problem has #define TAOCPP_PEGTL_VERSION "2.0.0"). Just in case the code is here. However now I don't see any reason for throwing parse_error from action since the same way I can throw any exception as the PEGTL doesn't catch any when using parse<R,A>(...) call. So then the question is the same - is there a way to convert additional constraint on input beyond the grammar rules? Do I have to use try_catch rule only? Thanks!

thelema commented 7 years ago

@cppden I suggest that putting too much intelligence into the parser will result in bad error messages and instead there should be a separate phase of semantic checks on the parsed result to ensure things like TTL being in the correct range.

cppden commented 7 years ago

Thanks @thelema. This is what I've done already - leaving for a user code to validate the range. Still it's not a slick solution IMHO as requires a user to remember of this extra validation step and check it every time the value (e.g. TTL) is about to be accessed.

d-frey commented 7 years ago

We were thinking about allowing the apply-methods to have a bool return type and when you return false, you could generate a local failure. This must be optional, as supporting it requires additional markers in the Duseltronik and it is therefore slightly less efficient than the void version of apply. We are planning on detecting the return type so that you can use the additional feature (at the additional cost) only where needed. I will talk to Colin again, as I currently am a bit pressed on time.

I don't think that the error messages will get worse, in fact in this case it might even help to have this kind of error being reported early and locally. As this would generate a local error it might even be used to implement more complex grammars, e.g. one parsing path for numbers smaller than 256, another parsing path for larger numbers, etc.

skyrich62 commented 7 years ago

Hi, I've done something similar with the match() method. Simply call the base class match, and then if the range isn't valid return false thru the input_mark.

Take a look here: https://github.com/skyrich62/AFE/blob/master/grammar.h You'll see what I did in the grammar rule for identifier.

It's a bit more code than throwing an exception and catching it, but you have much more control.

ColinH commented 7 years ago

The possibility to have apply() and apply0() action functions return a bool instead of the usual void is now implemented. The PEGTL core will rewind the input when an action returns false (unlike for rules that have to take care of this themselves). To the rest of the grammar there is no difference between a rule returning false, or the attached action returning false.

cppden commented 7 years ago

Thank you so much for such handy feature! PEGTL rules! ;)

ColinH commented 7 years ago

We are still refining the implementation to make it consistent with the control hooks.

And one thing to remember, with bool actions there is the possibility of at< rule > succeeding (because of the implicit disable<>), but rule failing (when the action returns false), for the same input.

ColinH commented 7 years ago

As per commit 0efa60453bfe46e7ef7f5cba2b1319c7df0b886f the control hooks are now called after the actions; the documentation was updated to reflect the new behaviour.