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

Enhance rule success strategy #82

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

0dminnimda
Copy link
Contributor

@0dminnimda 0dminnimda commented Feb 19, 2023

Closes #81

Also now it does not matter, if a user decides to return None as a node for some rule, now it will not affect anything
Also now instead of calling bool on the returning objects (which may be expensive) only a boolean flag will be set

This will also help a little with #70

Use func() is not None where suitable and not rely on the boolean value of the returned object this seems to be more reasonable for more broader applications

Now PythonCallMakerVisitor will determine if the value should be checked to be not None or should be checked as a boolean value (previous behavior)

Also read the conversation

@MatthieuDartiailh
Copy link
Collaborator

I am not familiar enough with the project history to know if something similar was considered before. @pablogsal would know more but he has been quite busy recently.

@lysnikolaou
Copy link
Contributor

I don't think something like this was considered while initially working on the project. However, we were more focussed on the C generator, making such edge cases in the python generator easier to miss.

To be honest, I'm a bit torn on this. While this seems like something that would work, I'm inclined to say that just checking is not None everywhere seems like an easier way that would also make the generated parsers easier to understand. Returning None from actions to have the rule fail is also more a feature than a bug and consistency with the CPython parser (where we're returning NULL to make rules fail all over the place) is something I'd love to keep going forward.

Not a strong opinion, so I'll let @pablogsal make the final call.

@0dminnimda
Copy link
Contributor Author

0dminnimda commented Feb 24, 2023

just checking is not None everywhere

Almost, the original bug is that loop0 can return an empty list, wich is evaluates to be False, but it shoud be considered a successful match. This logic is fine for loop1, but not for loop0

So the smallest fix is to handle

  • loop1 as func()
  • loop0 as func() is not None, or func(), (it doesn't really matter as those funcitons always returns a list)

Returning None from actions to have the rule fail is also more a feature than a bug and consistency with the CPython parser (where we're returning NULL to make rules fail all over the place) is something I'd love to keep going forward.

If I think about it as a feature it does indeed looks to be a neat thing to have, but it's not necessarily lost.
This pr introduces more control as to what will be considered a match and having None to be a failed match is not hard
Just change 3 lines of code and it's there.

What I like about this implementation is that only the function itself (and not the caller) is responsible for saying is this a match or not

On a side note I haven't had time to investigate what was the problem of a failed CI jobs, when I have the time I will look into that

@0dminnimda
Copy link
Contributor Author

Ok so the problem is that memorization does not restore value of the _matched

  1. One way is to return the value alongside the actual return
  2. The other way is to add the code to handle it in the memorizer, but I'd rather not change the code as it is made to handle general memorization and I don't want to ruin it
  3. And the third way to go is to handle the responcibility of handling the output value to the caller (as it was done before)

I don't want to touch the 2, although the logic keeping _matched is sync would not really risk breaking the code, but as mentioned it would become less general

1 seems to be a little messy it adds more code to the call (ex. ((l := self._result(self.term()),) and self._matched) and self.term would return tuple[actual_result, matched]), although this is a code generator and the generated code is not meant to be read it's just not nice

3 would grant the least amoung of changing but None would remain to be a invalid match, although given the argument of @lysnikolaou I would consider this to be fine


In the end I think that I tried to squish two prs/features into one, and if we really want to get read of the None as a stop value we it should be discussed and then changed in a different pr. In this pr I'd rather concentrate on fixing the actual problem #81

And I think that for now if users want to return None they should either use their own empty value like EmptyValue = object() or wrap it in another class like Wrapper(None) and to get it they use wrapper.value

Also if we want users be able to make empty values that are bool(value) == False, then we should use not bool(self.x()) as match check and use is None, I am gonna ensure it in this pr as well

@0dminnimda
Copy link
Contributor Author

Ok, tox straight up just does not work, I ran all of the pytests, linting tests, regen-metaparser but tox refures to succeed either here or locally

@0dminnimda 0dminnimda marked this pull request as ready for review February 27, 2023 01:19
@@ -80,6 +80,9 @@ def __init__(self, name: str, type: Optional[str], rhs: Rhs, memo: Optional[obje
def is_loop(self) -> bool:
return self.name.startswith("_loop")

def is_loop1(self) -> bool:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be removes as it's not used anywhere

@@ -214,6 +217,16 @@ def visit_Name(self, node: ast.Name) -> Set[str]:
return {node.id}


class RuleProperties(NamedTuple):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be removes alongside is_loop1, as it then would not really add anything
although I still think it's nicer

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

Successfully merging this pull request may close these issues.

Bug with zero or more rule
3 participants