Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise an exception from the grammar? #222

Open
rowlesmr opened this issue Sep 19, 2022 · 3 comments
Open

Raise an exception from the grammar? #222

rowlesmr opened this issue Sep 19, 2022 · 3 comments

Comments

@rowlesmr
Copy link

rowlesmr commented Sep 19, 2022

Hi all

Is there an ability to raise an exception straight from the grammar?

grammar = 
"""
datablockheading  = DATA  blockframecode
DATA = "data_"
blockframecode = nonblankchar+ / RAISE_ERROR
nonblankchar = ~"[A-Za-z0-9]"
"""

If not, what is the best sort of way to accomplish the same behaviour? I'm coming from PEGTL.

@erikrose
Copy link
Owner

I never got around to adding fine-grained error reporting to Parsimonious, but the design in my head involved annotated PEG-style cuts. Semantically, they might have been similar to what you suggest here, if I guess the behavior right.

In the meantime, you could define a visitor method called visit_RAISE_ERROR (in this case) and raise an exception from there.

@lucaswiman
Copy link
Collaborator

In the meantime, you could define a visitor method called visit_RAISE_ERROR (in this case) and raise an exception from there.

I don't think that would work since you'd end up with failed parsing where it doesn't consume all the input. E.g. you could define RAISE_ERROR to either consume zero characters or the rest of the string, neither of which would work for some grammars:

from parsimonious import *
g = Grammar(r"""
    parenthesized = "(" addition_expr ")"
    addition_expr = (number "+" number) / RAISE_ERROR
    number = ~"\d+"
    RAISE_ERROR = ~".+"m
""")
g.parse("(...)")  # parsimonious.exceptions.ParseError: Rule 'number' didn't match at '...)' (line 1, column 2).

There the RAISE_ERROR node doesn't match because it greedily consumes the ) at the end.

It's a bit clunky, but one option would be to define your own custom expression type that just raises an error:

from parsimonious.expressions import Expression
class RAISE_ERROR(Expression):
    def _uncached_match(self, text, pos, cache, error):
        raise Exception(f"You messed up at {pos}, 🤦‍♂️.")


g = Grammar(r"""
    parenthesized = "(" addition_expr ")"
    addition_expr = (number "+" number) / RAISE_ERROR
    number = ~"\d+"
""", RAISE_ERROR=RAISE_ERROR())
g.parse("(...)")  # Exception: You messed up at 1, 🤦‍♂️.

@erikrose
Copy link
Owner

erikrose commented Oct 8, 2022

Good point. So yes, I think your workaround is the best bet for the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants