| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
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
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -115,10 +115,10 @@ def _format(node): | |
|
|
||
| def copy_location(new_node, old_node): | ||
| """ | ||
| Copy source location (`lineno` and `col_offset` attributes) from | ||
| *old_node* to *new_node* if possible, and return *new_node*. | ||
| Copy source location (`lineno`, `col_offset`, `end_lineno`, and `end_col_offset` | ||
| attributes) from *old_node* to *new_node* if possible, and return *new_node*. | ||
| """ | ||
| for attr in 'lineno', 'col_offset': | ||
| for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset': | ||
| if attr in old_node._attributes and attr in new_node._attributes \ | ||
| and hasattr(old_node, attr): | ||
| setattr(new_node, attr, getattr(old_node, attr)) | ||
| Expand All | @@ -133,31 +133,44 @@ def fix_missing_locations(node): | |
| recursively where not already set, by setting them to the values of the | ||
| parent node. It works recursively starting at *node*. | ||
| """ | ||
| def _fix(node, lineno, col_offset): | ||
| def _fix(node, lineno, col_offset, end_lineno, end_col_offset): | ||
| if 'lineno' in node._attributes: | ||
| if not hasattr(node, 'lineno'): | ||
| node.lineno = lineno | ||
| else: | ||
| lineno = node.lineno | ||
| if 'end_lineno' in node._attributes: | ||
| if not hasattr(node, 'end_lineno'): | ||
| node.end_lineno = end_lineno | ||
| else: | ||
| end_lineno = node.end_lineno | ||
| if 'col_offset' in node._attributes: | ||
| if not hasattr(node, 'col_offset'): | ||
| node.col_offset = col_offset | ||
| else: | ||
| col_offset = node.col_offset | ||
| if 'end_col_offset' in node._attributes: | ||
| if not hasattr(node, 'end_col_offset'): | ||
| node.end_col_offset = end_col_offset | ||
| else: | ||
| end_col_offset = node.end_col_offset | ||
| for child in iter_child_nodes(node): | ||
| _fix(child, lineno, col_offset) | ||
| _fix(node, 1, 0) | ||
| _fix(child, lineno, col_offset, end_lineno, end_col_offset) | ||
| _fix(node, 1, 0, 1, 0) | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis whole function looks a bit suspicious.Shouldn't it at least ensure that (end_lineno, end_col_offset) > (lineno, col_offset)? (Again, I guess I don't know the use case.)
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis function is used to compile manually generated AST to bytecode. Although technically end positions are not needed for the compiler (only start positions are recorded in the byte code), it is probably good to have them fixed. The algorithm for fixing is quite naive (take either a position of nearest root-side node if known, otherwise use start of the file), but it never intended to be robust, it exist just to allow compilation in those case where a user doesn't care about line numbers.
Sorry, something went wrong.
All reactions
|
||
| return node | ||
|
|
||
|
|
||
| def increment_lineno(node, n=1): | ||
| """ | ||
| Increment the line number of each node in the tree starting at *node* by *n*. | ||
| This is useful to "move code" to a different location in a file. | ||
| Increment the line number and end line number of each node in the tree | ||
| starting at *node* by *n*. This is useful to "move code" to a different | ||
| location in a file. | ||
| """ | ||
| for child in walk(node): | ||
| if 'lineno' in child._attributes: | ||
| child.lineno = getattr(child, 'lineno', 0) + n | ||
| if 'end_lineno' in child._attributes: | ||
| child.end_lineno = getattr(child, 'end_lineno', 0) + n | ||
| return node | ||
|
|
||
|
|
||
| Expand Down Expand Up | @@ -213,6 +226,77 @@ def get_docstring(node, clean=True): | |
| return text | ||
|
|
||
|
|
||
| def _splitlines_no_ff(source): | ||
|
Comment thread
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityAnother option is to use .splitlines(keepends=True) (which considers \f as an endline) and then re-join those that aren't ending in \r or \n, I am not sure which approach is better.
Sorry, something went wrong.
All reactions
|
||
| """Split a string into lines ignoring form feed and other chars. | ||
|
|
||
| This mimics how the Python parser splits source code. | ||
| """ | ||
| idx = 0 | ||
| lines = [] | ||
| next_line = '' | ||
| while idx < len(source): | ||
| c = source[idx] | ||
| next_line += c | ||
| idx += 1 | ||
| # Keep \r\n together | ||
| if c == '\r' and idx < len(source) and source[idx] == '\n': | ||
| next_line += '\n' | ||
| idx += 1 | ||
| if c in '\r\n': | ||
| lines.append(next_line) | ||
| next_line = '' | ||
|
|
||
| if next_line: | ||
| lines.append(next_line) | ||
| return lines | ||
|
|
||
|
|
||
| def _pad_whitespace(source): | ||
| """Replace all chars except '\f\t' in a line with spaces.""" | ||
| result = '' | ||
| for c in source: | ||
| if c in '\f\t': | ||
| result += c | ||
| else: | ||
| result += ' ' | ||
| return result | ||
|
|
||
|
|
||
| def get_source_segment(source, node, *, padded=False): | ||
| """Get source code segment of the *source* that generated *node*. | ||
|
|
||
| If some location information (`lineno`, `end_lineno`, `col_offset`, | ||
| or `end_col_offset`) is missing, return None. | ||
|
|
||
| If *padded* is `True`, the first line of a multi-line statement will | ||
| be padded with spaces to match its original position. | ||
| """ | ||
| try: | ||
| lineno = node.lineno - 1 | ||
| end_lineno = node.end_lineno - 1 | ||
| col_offset = node.col_offset | ||
| end_col_offset = node.end_col_offset | ||
| except AttributeError: | ||
| return None | ||
|
|
||
| lines = _splitlines_no_ff(source) | ||
| if end_lineno == lineno: | ||
| return lines[lineno].encode()[col_offset:end_col_offset].decode() | ||
|
|
||
| if padded: | ||
| padding = _pad_whitespace(lines[lineno].encode()[:col_offset].decode()) | ||
| else: | ||
| padding = '' | ||
|
|
||
| first = padding + lines[lineno].encode()[col_offset:].decode() | ||
| last = lines[end_lineno].encode()[:end_col_offset].decode() | ||
| lines = lines[lineno+1:end_lineno] | ||
|
|
||
| lines.insert(0, first) | ||
| lines.append(last) | ||
| return ''.join(lines) | ||
|
|
||
|
|
||
| def walk(node): | ||
| """ | ||
| Recursively yield all descendant nodes in the tree starting at *node* | ||
| Expand Down | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -62,14 +62,16 @@ def test_product(self): | |
|
|
||
| def test_attributes(self): | ||
| stmt = self.types['stmt'] | ||
| self.assertEqual(len(stmt.attributes), 2) | ||
| self.assertEqual(len(stmt.attributes), 4) | ||
| self.assertEqual(str(stmt.attributes[0]), 'Field(int, lineno)') | ||
| self.assertEqual(str(stmt.attributes[1]), 'Field(int, col_offset)') | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityAdd tests for stmt.attributes[2] and stmt.attributes[3]?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityAdded.
Sorry, something went wrong.
All reactions
|
||
| self.assertEqual(str(stmt.attributes[2]), 'Field(int, end_lineno, opt=True)') | ||
| self.assertEqual(str(stmt.attributes[3]), 'Field(int, end_col_offset, opt=True)') | ||
|
|
||
| def test_constructor_fields(self): | ||
| ehandler = self.types['excepthandler'] | ||
| self.assertEqual(len(ehandler.types), 1) | ||
| self.assertEqual(len(ehandler.attributes), 2) | ||
| self.assertEqual(len(ehandler.attributes), 4) | ||
|
|
||
| cons = ehandler.types[0] | ||
| self.assertIsInstance(cons, self.asdl.Constructor) | ||
| Expand Down | ||
| Back | FazBrowse Home | New Git URL |
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.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityDoes this only affect the node, or the whole tree? I've never used this so I don't know what to expect from context.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityThis one (unlike some others) is non-recursive, one can even copy from a node of a different kind.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.