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

implement parsing free conversion operators #95

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

Conversation

ostr00000
Copy link

Closes #94

Copy link
Author

@ostr00000 ostr00000 left a comment

Choose a reason for hiding this comment

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

I wrote some comments about the code, explaining why I chose such solutions.
Not everything is perfect, so I am open to suggestions.

@@ -697,7 +698,7 @@ def _parse_template_specialization(self) -> TemplateSpecialization:

try:
parsed_type, mods = self._parse_type(None)
if parsed_type is None:
Copy link
Author

Choose a reason for hiding this comment

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

_parse_type now return Union of types. According to typing rules, there should be if checking which type is returned (that is the reason why function should not return Union)

@@ -2331,8 +2332,6 @@ def _parse_type(
tok = get_token()

pqname: typing.Optional[PQName] = None
pqname_optional = False
Copy link
Author

Choose a reason for hiding this comment

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

This is no longer used

Comment on lines +2348 to +2350
mods = ParsedTypeModifiers(vars, both, meths)
po = self._parse_member_operator()
return po, mods
Copy link
Author

Choose a reason for hiding this comment

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

Here we are parsing the old cases + some additional parsing that was in _parse_operator_conversion. I extracted that to a new function to make code a bit simpler.

po = self._parse_member_operator()
return po, mods

pqname, op = self._parse_pqname(
Copy link
Author

Choose a reason for hiding this comment

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

We must run _parse_pqname because we do not know if this is operator or another function. But if we already ran this function, we cannot return (or I do not found such functions) processed tokens,

Copy link
Author

Choose a reason for hiding this comment

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

Also, I changed argument fn_ok to True to not raise error when operator is detected.


if op is not None:
# special case: conversion operator, but also a free operator
mods = ParsedTypeModifiers(vars, both, meths)
Copy link
Author

Choose a reason for hiding this comment

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

This is only parsed when we detected operator as a free operator.

) -> Operator:
"""This function parses operator implemented outside class body."""
last_seg = pqname.segments[-1]
assert last_seg.name.startswith("operator")
Copy link
Author

Choose a reason for hiding this comment

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

This is a bit strange to me: why there is not used more complex type in NameSpecifier and operator name is concatenated? Anyway, we do not care here about this name. We take the real operator name from op variable.

Copy link
Member

Choose a reason for hiding this comment

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

The operator name gets concatenated in _parse_pqname_name... I think it would be better for that function to not concatenate and let the eventual user of the operator make that call.

Copy link
Author

Choose a reason for hiding this comment

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

ok, I changed _parse_pqname_name to not concatenate this. This caused even more large change for something that seems like it should be rather simple, because I changed return types for several functions from str|None to list[LexToken].

assert last_seg.name.startswith("operator")
last_seg.name = "operator"

type_name = PQName([NameSpecifier(p) for p in op.split(PlyLexer.t_DBL_COLON)])
Copy link
Author

Choose a reason for hiding this comment

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

This is the part where I am the most hesitant, because we split here operator by ::.
It seems good enough (the code is parsed after all), but if there is a better way, I think it should be changed.

Copy link
Member

Choose a reason for hiding this comment

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

I also don't like this.

Comment on lines -2548 to -2549
tok = self._next_token_must_be("operator")

Copy link
Author

Choose a reason for hiding this comment

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

The token tok has already been processed in _parse_type.

Copy link
Author

Choose a reason for hiding this comment

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

Actually, perhaps a more appropriate name for this function would be _parse_type_or_operator ?

Comment on lines 304 to 316
@dataclass
class Operator:
"""An internal structure for parsing operator."""

pqname: PQName
"""Possibly qualified name for operator."""
operator_name: str
"""Conversion operator have always `conversion` str in this attribute."""
ctype: Type
"""Return type for this operator."""
cmods: "ParsedTypeModifiers"
"""Return type modifiers for this operator."""

Copy link
Author

Choose a reason for hiding this comment

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

This is only for internal usage to store data between _parse_type and _parse_operator_conversion in _parse_declarations method.

tests/test_operators.py Show resolved Hide resolved
Copy link
Member

@virtuald virtuald left a comment

Choose a reason for hiding this comment

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

This is a surprisingly large change for something that seems like it should be rather simple. However, I poked at it a little bit and I can see why it's complex, since this sort of operator violates some of my assumptions.

I might have time this weekend to try to find a simpler option.

@@ -298,6 +301,23 @@ def format_decl(self, name: str):
return f"{c}{v}{self.typename.format()} {name}"


@dataclass
class Operator:
Copy link
Member

Choose a reason for hiding this comment

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

I think if this isn't exposed to users, it probably doesn't belong in types.py

Copy link
Author

Choose a reason for hiding this comment

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

ok,
I had thought about it before, but since this module contains a lot of data classes, I decided to put it there.
I removed it from types.py and moved to parser.py, because only there it is used (I personally prefer to keep many small files, but I see that convention in this project is to keep small number of modules).

assert last_seg.name.startswith("operator")
last_seg.name = "operator"

type_name = PQName([NameSpecifier(p) for p in op.split(PlyLexer.t_DBL_COLON)])
Copy link
Member

Choose a reason for hiding this comment

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

I also don't like this.

) -> Operator:
"""This function parses operator implemented outside class body."""
last_seg = pqname.segments[-1]
assert last_seg.name.startswith("operator")
Copy link
Member

Choose a reason for hiding this comment

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

The operator name gets concatenated in _parse_pqname_name... I think it would be better for that function to not concatenate and let the eventual user of the operator make that call.

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.

[PARSE BUG]: Cannot parse free conversion operator
2 participants