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

Format enums with one value per line #216

Merged
merged 9 commits into from Oct 19, 2017
Merged

Conversation

altendky
Copy link
Contributor

Issue #213

@altendky
Copy link
Contributor Author

I'm not particularly confident that the punctuation parameter is the proper approach. Perhaps I should call self.visit() directly on the assignment in _generate_enum_body()?

@altendky
Copy link
Contributor Author

Incomplete tests, fixing them and fixing a bug with 'empty' enums such as used in typedefs.

@@ -280,6 +281,25 @@ def test_compound_literal(self):
self._assert_ctoc_correct('int i = ++(int){ 1 };')
self._assert_ctoc_correct('struct foo_s foo = (struct foo_s){ 1, 2 };')

def test_enum(self):
s = textwrap.dedent(r'''
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 dedent necessary? none of the other tests use it since the code is being parsed anyway

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_assert_ctoc_correct() is not checking the formatting and my change is a formatting change so it would seem that my test should do at least something different. I just verified this by checking that all three of the following tests pass.

    def test_enum_a(self):
        s = textwrap.dedent(r'''
            enum e
            {
              a = 1,
              b = 2,
              c = 3
            };
        '''[1:])

        self._assert_ctoc_correct(s)

    def test_enum_b(self):
        s = r'''
            enum e
            {
              a = 1,
              b = 2,
              c = 3
            };
        '''

        self._assert_ctoc_correct(s)

    def test_enum_c(self):
        s = r'''enum e {a = 1, b = 2, c = 3};'''

        self._assert_ctoc_correct(s)

Copy link
Owner

Choose a reason for hiding this comment

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

Ah, I see. If that's the case, no problem. The other tests don't tend to do one-to-one comparison of actual formatting, but I guess it's OK in this case. I'm a bit worried that this test will be fragile because it compares large strings, but we can fix it if it becomes and issue.

if name in ('struct', 'union'):
members = n.decls
body_function = self._generate_struct_union_body
elif name in ('enum',):
Copy link
Owner

Choose a reason for hiding this comment

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

this should probably be:

else:
    assert name == 'enum'
    ... rest of code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is my understanding that assert is only proper in test code. But, the gist that an exception should be raised for an invalid input does sound good. How about leaving the elif and adding an else that raises a to-be-defined exception?

UnknownTypeError('`{name}` not recognized'.format(name=name))

Given that this is an internal method it seems that we may not need a nice user error. I'll note that as is we'd get an UnboundLocalError for the following access to members. I added a test for that and will adjust it based on the implementation decision.

Copy link
Owner

Choose a reason for hiding this comment

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

I actually think assert is fine in this case, since it's checking an invariant in the code - it's a bug if this place is reached, so assert is appropriate.

body_function = self._generate_struct_union_body
elif name in ('enum',):
if n.values is None:
members = ()
Copy link
Owner

Choose a reason for hiding this comment

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

members = () if n.values is None else n.values.enumerators

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pending above possibilities I'll change this.

if i == len(members) - 1:
punctuation = ''

s.append(self._generate_stmt(
Copy link
Owner

Choose a reason for hiding this comment

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

I wonder why you need to build an AST node again here, why won't just emitting the text do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to make it look like how struct and union were done, but failing. I removed the punctuation parameter from _generate_stmt() and added visit_Enumerator(). Perhaps this will fit better with the existing code.

Copy link
Contributor Author

@altendky altendky left a comment

Choose a reason for hiding this comment

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

Thanks for the very prompt review.

I pushed a couple commits but let me know how you want to proceed on the remaining points.

@@ -280,6 +281,25 @@ def test_compound_literal(self):
self._assert_ctoc_correct('int i = ++(int){ 1 };')
self._assert_ctoc_correct('struct foo_s foo = (struct foo_s){ 1, 2 };')

def test_enum(self):
s = textwrap.dedent(r'''
Copy link
Contributor Author

Choose a reason for hiding this comment

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

_assert_ctoc_correct() is not checking the formatting and my change is a formatting change so it would seem that my test should do at least something different. I just verified this by checking that all three of the following tests pass.

    def test_enum_a(self):
        s = textwrap.dedent(r'''
            enum e
            {
              a = 1,
              b = 2,
              c = 3
            };
        '''[1:])

        self._assert_ctoc_correct(s)

    def test_enum_b(self):
        s = r'''
            enum e
            {
              a = 1,
              b = 2,
              c = 3
            };
        '''

        self._assert_ctoc_correct(s)

    def test_enum_c(self):
        s = r'''enum e {a = 1, b = 2, c = 3};'''

        self._assert_ctoc_correct(s)

if name in ('struct', 'union'):
members = n.decls
body_function = self._generate_struct_union_body
elif name in ('enum',):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is my understanding that assert is only proper in test code. But, the gist that an exception should be raised for an invalid input does sound good. How about leaving the elif and adding an else that raises a to-be-defined exception?

UnknownTypeError('`{name}` not recognized'.format(name=name))

Given that this is an internal method it seems that we may not need a nice user error. I'll note that as is we'd get an UnboundLocalError for the following access to members. I added a test for that and will adjust it based on the implementation decision.

body_function = self._generate_struct_union_body
elif name in ('enum',):
if n.values is None:
members = ()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pending above possibilities I'll change this.

if i == len(members) - 1:
punctuation = ''

s.append(self._generate_stmt(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to make it look like how struct and union were done, but failing. I removed the punctuation parameter from _generate_stmt() and added visit_Enumerator(). Perhaps this will fit better with the existing code.

@@ -280,6 +281,25 @@ def test_compound_literal(self):
self._assert_ctoc_correct('int i = ++(int){ 1 };')
self._assert_ctoc_correct('struct foo_s foo = (struct foo_s){ 1, 2 };')

def test_enum(self):
s = textwrap.dedent(r'''
Copy link
Owner

Choose a reason for hiding this comment

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

Ah, I see. If that's the case, no problem. The other tests don't tend to do one-to-one comparison of actual formatting, but I guess it's OK in this case. I'm a bit worried that this test will be fragile because it compares large strings, but we can fix it if it becomes and issue.


def _generate_enum_body(self, members):
s = []

Copy link
Owner

Choose a reason for hiding this comment

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

Python usually prefers denser style - none of the empty lines in this function are really necessary

def _generate_enum_body(self, members):
s = []

for value in members:
Copy link
Owner

Choose a reason for hiding this comment

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

Actually, this loop can be turned into a simple list comprehension, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I refactored and it got simpler and I missed that last step.


s.append(line)

return ''.join(s)[:-2] + '\n'
Copy link
Owner

Choose a reason for hiding this comment

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

A comment should say why the [:-2] is needed here

@eliben eliben merged commit 7547e85 into eliben:master Oct 19, 2017
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.

None yet

2 participants