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

Merge ast and parser from forward #3

Merged
merged 68 commits into from
Jun 10, 2022
Merged

Merge ast and parser from forward #3

merged 68 commits into from
Jun 10, 2022

Conversation

Legotier
Copy link
Collaborator

No description provided.

Legotier and others added 24 commits May 6, 2022 08:53
This does not adapt the tests to the new features, it just makes sure there are no errors due to the renaming of classes or changed parameters in functions
None was never an allowed value for nodes in a networkx.DiGraph, but older versions of networkx apparently didn't throw an error when it was added
Copy link
Owner

@Philipp15b Philipp15b left a comment

Choose a reason for hiding this comment

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

Thanks a lot, excellent work! I just added some comments. Please make sure each file has an empty line at the end (otherwise Github shows the ugly red icon at the end). There might also be a bug in the change to cfg.py. The linter found a bunch of minor problems, it would be great if you could fix them as well. See https://github.com/Philipp15b/probably/runs/6505098898?check_suite_focus=true.

We should also note all breaking changes in this pull request so we can update other tools that depend on it. I see the following:

  • Changed names FloatLitExpr to RealLitExpr
  • Changed operator precedence so that the : operator now binds less strong than multiplication (what does that mean in practice, do we have an example?)
  • Changed the constructor of the Program class and the Program.from_parse function to require one more parameter
  • Probably now depends on at least Python 3.9
  • Rename Assoc.Left to LEFT and Right to RIGHT
  • More?

probably/pgcl/ast.py Outdated Show resolved Hide resolved
probably/pgcl/ast.py Outdated Show resolved Hide resolved
probably/pgcl/ast.py Outdated Show resolved Hide resolved
probably/pgcl/syntax.py Outdated Show resolved Hide resolved
probably/pgcl/cfg.py Outdated Show resolved Hide resolved
probably/pgcl/parser.py Outdated Show resolved Hide resolved
probably/pgcl/parser.py Outdated Show resolved Hide resolved
probably/pgcl/parser.py Outdated Show resolved Hide resolved
probably/pgcl/parser.py Outdated Show resolved Hide resolved
return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))),
prob=lit)
elif t.children[1].data == 'true' or t.children[1].data == 'false':
raise SyntaxError("Plot instruction does not support boolean operators")
Copy link
Owner

Choose a reason for hiding this comment

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

Again, belongs in the type checker.

Copy link
Owner

Choose a reason for hiding this comment

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

Is this actually resolved?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oops

Copy link
Collaborator Author

@Legotier Legotier Jun 3, 2022

Choose a reason for hiding this comment

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

I think there is actually a bug in the parsing of plot instructions. If we write !Plot[x, true] in pGCL, the true is interpreted as a VarExpr with value true instead of as an (illegal) boolean literal.

Which also raises the question, shouldn't it be forbidden to have variables etc. that are called "true" or "false"?

Copy link
Owner

Choose a reason for hiding this comment

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

You're right! I guess the nicest way to solve this would be to parse full expressions in !Plot and then have a check somewhere that it's actually a variable. That way, we can give proper error messages.

I had hoped that the parser would reject any keywords as variables, e.g. true := whatever should give an error. If that's not the case, another bug! I'd solve that by manually rejecting all keywords such as true and false in the _parse_var function:

def _parse_var(t: Tree) -> Var:
assert t.data == 'var'
assert t.children[0].type == 'CNAME' # type: ignore
return str(_child_str(t, 0))

Copy link
Collaborator Author

@Legotier Legotier Jun 3, 2022

Choose a reason for hiding this comment

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

I had hoped that the parser would reject any keywords as variables, e.g. true := whatever should give an error. If that's not the case, another bug!

Fixed by 0a598c2, at least for true and false (are there even more?).

I guess the nicest way to solve this would be to parse full expressions in !Plot and then have a check somewhere that it's actually a variable.

I feel like this is just treating the symptoms (i.e., retrospectively fixing that the tree generated by lark contains a var node where a literal should be) instead of fighting the actual cause (i.e., making sure that there isn't even a var node in the first place). Wouldn't it be more elegant to somehow change the lark grammar such that true and false are never recognized as variable names? If we do it like you propose, this check needs to occur after the parsing is finished, or we need a global list in the parser that contains all variables in the current program (similar to the parameter dict). Both of these possibilities seem wrong to me.

For example, commit 12167a5 does this. This fixes both of these problems, it just leads to some very cryptic error messages when a variable has an illegal name.

Copy link
Owner

Choose a reason for hiding this comment

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

If we do it like you propose, this check needs to occur after the parsing is finished, or we need a global list in the parser that contains all variables in the current program (similar to the parameter dict)

I don't understand that. Just check whether a variable name is a keyword and throw an error if that's the case. I think that's the easiest way to do this. As an additional safety measure, the constructor of VarExpr could assert that the name is not a keyword.

it just leads to some very cryptic error messages when a variable has an illegal name

This is exactly why we should be liberal in what we parse and then provide useful error messages afterwards.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed, more or less. It's still not in the typechecker, but wrongly typed code can't be parsed anyways in this case.

@Legotier

This comment was marked as duplicate.

probably/pgcl/check.py Outdated Show resolved Hide resolved
probably/pgcl/check.py Outdated Show resolved Hide resolved
probably/pgcl/syntax.py Outdated Show resolved Hide resolved
probably/pgcl/syntax.py Outdated Show resolved Hide resolved
probably/pgcl/check.py Outdated Show resolved Hide resolved
probably/pgcl/parser.py Outdated Show resolved Hide resolved
probably/pgcl/syntax.py Outdated Show resolved Hide resolved
probably/pgcl/syntax.py Outdated Show resolved Hide resolved
@@ -441,7 +441,8 @@ def _parse_query(t: Tree):
assert isinstance(lit, RealLitExpr)
return PlotInstr(VarExpr(_parse_var(_child_tree(t, 0))),
prob=lit)
elif t.children[1].data in ('true', 'false'):
elif t.children[1].data in ('true', 'false') or \
(t.children[1].data == 'var' and t.children[1].children[0] in ('true', 'false')):
raise SyntaxError("Plot instruction does not support boolean operators")
Copy link
Collaborator Author

@Legotier Legotier Jun 8, 2022

Choose a reason for hiding this comment

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

This is a workaround for the problem mentioned here, so we get a nicer error message. This check should still be moved to the typechecker, but I don't see how this can be done without some extensive rewrites, as the parsing of a PlotInstr already depends on the type of the literal. Also, the parser throws an error that there is an illegal variable name anyways, this change here just changes the error message.


format:
poetry run yapf -r -i probably/ tests/
poetry run isort probably/ tests/
Copy link
Owner

Choose a reason for hiding this comment

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

isort is not a dev-dependency, does this actually work?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It runs on my machine... Maybe some other package depends on isort? In any case, if this should stay here then we should probably add it to the dependencies

@Philipp15b Philipp15b merged commit ce51260 into master Jun 10, 2022
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.

3 participants