-
Notifications
You must be signed in to change notification settings - Fork 636
showemptyattrs option on Node.show() #570
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
Conversation
pycparser/c_ast.py
Outdated
| pass | ||
|
|
||
| def show(self, buf=sys.stdout, offset=0, attrnames=False, nodenames=False, showcoord=False, _my_node_name=None): | ||
| def show(self, buf=sys.stdout, offset=0, attrnames=False, hideemptyattrs=False, nodenames=False, showcoord=False, _my_node_name=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, I think it's preferable to have positive logic as much as possible, to avoid double-negation in code and reasoning about code.
Can you make it showemptyattrs=True?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, yeah showemptyattrs does seem easier to reason about after extracting a helper.
if self.attr_names:
is_empty = lambda v: v is None or (hasattr(v, '__len__') and len(v) == 0)
nvlist = [(n, getattr(self,n)) for n in self.attr_names \
if showemptyattrs or not is_empty(getattr(self,n))]Do you think it is worth also extracting a filter, or just leave it inline?
if self.attr_names:
is_empty = lambda v: v is None or (hasattr(v, '__len__') and len(v) == 0)
attr_filter = lambda v: showemptyattrs or not is_empty(v)
nvlist = [(n, getattr(self,n)) for n in self.attr_names if attr_filter(getattr(self,n))]
pycparser/c_ast.py
Outdated
| buf.write(lead + self.__class__.__name__+ ': ') | ||
|
|
||
| if self.attr_names: | ||
| nvlist = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you factor out the emptiness check into a helper function, this loop can become a simple loop comprehension again:
nvlist = [(n, getattr(self, n)) for n in self.attr_names if ...]
Or something similar
|
Ok, new commit pushed. |
|
Thanks for merging! Just to have it indexed by google, I'll drop an example here about how users can patch in their own custom #!/usr/bin/env python3
# Demonstration of patching in an alternative Node.show() method.
import sys
from pycparser import c_parser
from pycparser.c_ast import *
def show(self, buf=sys.stdout, indent=4, showcoord=True, _my_node_name=None, _lead='', _lastcoord=None, _depth=1):
""" Pretty print the Node and all its attributes and
children (recursively) to a buffer.
buf:
Open IO buffer into which the Node is printed.
indent:
The number of spaces to indent at each level.
showcoord:
Do you want the coordinates of each Node to be
displayed.
returns the number of parens which need to be closed by the parent.
"""
# print the node type
s = _lead
if _my_node_name:
s += "%s = " % _my_node_name
s += "%s(" % (self.__class__.__name__)
if showcoord and self.coord:
# only print the line number if it has changed
coord_did_change = _lastcoord is None \
or self.coord.file != _lastcoord.file \
or self.coord.line != _lastcoord.line
if coord_did_change:
s += ' // '
if self.coord.file:
s += '%s ' % self.coord.file
s += 'line %s' % self.coord.line
_lastcoord = self.coord
buf.write(s + '\n')
# use dots to give visual column cues
lead2 = _lead + '.' + (' ' * (indent-1))
# print the attributes
if self.attr_names:
for name, value in [(n, getattr(self,n)) for n in self.attr_names]:
# suppress empty fields
if value is None:
continue
if hasattr(value, '__len__') and len(value) == 0:
continue
buf.write(lead2 + "%s = %s\n" % (name, value))
# print the children.
unclosed_depth = 0
for i, (child_name, child) in enumerate(self.children()):
is_last = i+1 == len(self.children())
unclosed_depth = child.show(
buf,
indent=indent,
_my_node_name=child_name,
_lead=lead2,
_lastcoord=_lastcoord,
_depth=_depth+1
)
if not is_last:
dot_spaces = ('.' + ' '*(indent-1))
spaces_cparen = ')' + ' ' * (indent-1)
buf.write((dot_spaces * _depth) + (spaces_cparen * unclosed_depth) + '\n')
else:
# let the caller close out parens after the last child
pass
if _depth == 1:
# this is the final paren closing
unclosed_depth += 1
spaces_cparen = ')' + ' ' * (indent-1)
buf.write((spaces_cparen * unclosed_depth) + '\n')
else:
# let the caller close out parens after the last child
return unclosed_depth + 1
# patch in our custom show
Node.show = show
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.stderr.write("Error: no filename given.\n")
sys.exit(1)
fname = sys.argv[1]
with open(fname, 'r') as fd:
text = fd.read()
parser = c_parser.CParser()
ast = parser.parse(text)
ast.show()given int main(int argc, char** argv) {
printf("Hello, world!\n");
return 0;
}the above prints the following: |
This PR adds a
hideemptyattrsoption toNode.show(). Let me know what you think!Given
hello.c:Here's a comparison of all of the options.
default
show():with
hideemptyattrs:attrnames=True:with
hideemptyattrs:nodenames=True:with
hideemptyattrs:showcoord=True:with
hideemptyattrs: