| Index: tools/telemetry/third_party/rope/rope/refactor/patchedast.py
|
| diff --git a/tools/telemetry/third_party/rope/rope/refactor/patchedast.py b/tools/telemetry/third_party/rope/rope/refactor/patchedast.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e2b8db27f3f392f753001c631f298375204ed415
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/rope/rope/refactor/patchedast.py
|
| @@ -0,0 +1,753 @@
|
| +import collections
|
| +import re
|
| +import warnings
|
| +
|
| +from rope.base import ast, codeanalyze, exceptions
|
| +
|
| +try:
|
| + basestring
|
| +except NameError:
|
| + basestring = (str, bytes)
|
| +
|
| +def get_patched_ast(source, sorted_children=False):
|
| + """Adds ``region`` and ``sorted_children`` fields to nodes
|
| +
|
| + Adds ``sorted_children`` field only if `sorted_children` is True.
|
| +
|
| + """
|
| + return patch_ast(ast.parse(source), source, sorted_children)
|
| +
|
| +
|
| +def patch_ast(node, source, sorted_children=False):
|
| + """Patches the given node
|
| +
|
| + After calling, each node in `node` will have a new field named
|
| + `region` that is a tuple containing the start and end offsets
|
| + of the code that generated it.
|
| +
|
| + If `sorted_children` is true, a `sorted_children` field will
|
| + be created for each node, too. It is a list containing child
|
| + nodes as well as whitespaces and comments that occur between
|
| + them.
|
| +
|
| + """
|
| + if hasattr(node, 'region'):
|
| + return node
|
| + walker = _PatchingASTWalker(source, children=sorted_children)
|
| + ast.call_for_nodes(node, walker)
|
| + return node
|
| +
|
| +
|
| +def node_region(patched_ast_node):
|
| + """Get the region of a patched ast node"""
|
| + return patched_ast_node.region
|
| +
|
| +
|
| +def write_ast(patched_ast_node):
|
| + """Extract source form a patched AST node with `sorted_children` field
|
| +
|
| + If the node is patched with sorted_children turned off you can use
|
| + `node_region` function for obtaining code using module source code.
|
| + """
|
| + result = []
|
| + for child in patched_ast_node.sorted_children:
|
| + if isinstance(child, ast.AST):
|
| + result.append(write_ast(child))
|
| + else:
|
| + result.append(child)
|
| + return ''.join(result)
|
| +
|
| +
|
| +class MismatchedTokenError(exceptions.RopeError):
|
| + pass
|
| +
|
| +
|
| +class _PatchingASTWalker(object):
|
| +
|
| + def __init__(self, source, children=False):
|
| + self.source = _Source(source)
|
| + self.children = children
|
| + self.lines = codeanalyze.SourceLinesAdapter(source)
|
| + self.children_stack = []
|
| +
|
| + Number = object()
|
| + String = object()
|
| + semicolon_or_as_in_except = object()
|
| +
|
| + def __call__(self, node):
|
| + method = getattr(self, '_' + node.__class__.__name__, None)
|
| + if method is not None:
|
| + return method(node)
|
| + # ???: Unknown node; what should we do here?
|
| + warnings.warn('Unknown node type <%s>; please report!'
|
| + % node.__class__.__name__, RuntimeWarning)
|
| + node.region = (self.source.offset, self.source.offset)
|
| + if self.children:
|
| + node.sorted_children = ast.get_children(node)
|
| +
|
| + def _handle(self, node, base_children, eat_parens=False, eat_spaces=False):
|
| + if hasattr(node, 'region'):
|
| + # ???: The same node was seen twice; what should we do?
|
| + warnings.warn(
|
| + 'Node <%s> has been already patched; please report!' %
|
| + node.__class__.__name__, RuntimeWarning)
|
| + return
|
| + base_children = collections.deque(base_children)
|
| + self.children_stack.append(base_children)
|
| + children = collections.deque()
|
| + formats = []
|
| + suspected_start = self.source.offset
|
| + start = suspected_start
|
| + first_token = True
|
| + while base_children:
|
| + child = base_children.popleft()
|
| + if child is None:
|
| + continue
|
| + offset = self.source.offset
|
| + if isinstance(child, ast.AST):
|
| + ast.call_for_nodes(child, self)
|
| + token_start = child.region[0]
|
| + else:
|
| + if child is self.String:
|
| + region = self.source.consume_string(
|
| + end=self._find_next_statement_start())
|
| + elif child is self.Number:
|
| + region = self.source.consume_number()
|
| + elif child == '!=':
|
| + # INFO: This has been added to handle deprecated ``<>``
|
| + region = self.source.consume_not_equal()
|
| + elif child == self.semicolon_or_as_in_except:
|
| + # INFO: This has been added to handle deprecated
|
| + # semicolon in except
|
| + region = self.source.consume_except_as_or_semicolon()
|
| + else:
|
| + region = self.source.consume(child)
|
| + child = self.source[region[0]:region[1]]
|
| + token_start = region[0]
|
| + if not first_token:
|
| + formats.append(self.source[offset:token_start])
|
| + if self.children:
|
| + children.append(self.source[offset:token_start])
|
| + else:
|
| + first_token = False
|
| + start = token_start
|
| + if self.children:
|
| + children.append(child)
|
| + start = self._handle_parens(children, start, formats)
|
| + if eat_parens:
|
| + start = self._eat_surrounding_parens(
|
| + children, suspected_start, start)
|
| + if eat_spaces:
|
| + if self.children:
|
| + children.appendleft(self.source[0:start])
|
| + end_spaces = self.source[self.source.offset:]
|
| + self.source.consume(end_spaces)
|
| + if self.children:
|
| + children.append(end_spaces)
|
| + start = 0
|
| + if self.children:
|
| + node.sorted_children = children
|
| + node.region = (start, self.source.offset)
|
| + self.children_stack.pop()
|
| +
|
| + def _handle_parens(self, children, start, formats):
|
| + """Changes `children` and returns new start"""
|
| + opens, closes = self._count_needed_parens(formats)
|
| + old_end = self.source.offset
|
| + new_end = None
|
| + for i in range(closes):
|
| + new_end = self.source.consume(')')[1]
|
| + if new_end is not None:
|
| + if self.children:
|
| + children.append(self.source[old_end:new_end])
|
| + new_start = start
|
| + for i in range(opens):
|
| + new_start = self.source.rfind_token('(', 0, new_start)
|
| + if new_start != start:
|
| + if self.children:
|
| + children.appendleft(self.source[new_start:start])
|
| + start = new_start
|
| + return start
|
| +
|
| + def _eat_surrounding_parens(self, children, suspected_start, start):
|
| + index = self.source.rfind_token('(', suspected_start, start)
|
| + if index is not None:
|
| + old_start = start
|
| + old_offset = self.source.offset
|
| + start = index
|
| + if self.children:
|
| + children.appendleft(self.source[start + 1:old_start])
|
| + children.appendleft('(')
|
| + token_start, token_end = self.source.consume(')')
|
| + if self.children:
|
| + children.append(self.source[old_offset:token_start])
|
| + children.append(')')
|
| + return start
|
| +
|
| + def _count_needed_parens(self, children):
|
| + start = 0
|
| + opens = 0
|
| + for child in children:
|
| + if not isinstance(child, basestring):
|
| + continue
|
| + if child == '' or child[0] in '\'"':
|
| + continue
|
| + index = 0
|
| + while index < len(child):
|
| + if child[index] == ')':
|
| + if opens > 0:
|
| + opens -= 1
|
| + else:
|
| + start += 1
|
| + if child[index] == '(':
|
| + opens += 1
|
| + if child[index] == '#':
|
| + try:
|
| + index = child.index('\n', index)
|
| + except ValueError:
|
| + break
|
| + index += 1
|
| + return start, opens
|
| +
|
| + def _find_next_statement_start(self):
|
| + for children in reversed(self.children_stack):
|
| + for child in children:
|
| + if isinstance(child, ast.stmt):
|
| + return child.col_offset \
|
| + + self.lines.get_line_start(child.lineno)
|
| + return len(self.source.source)
|
| +
|
| + _operators = {'And': 'and', 'Or': 'or', 'Add': '+', 'Sub': '-',
|
| + 'Mult': '*', 'Div': '/', 'Mod': '%', 'Pow': '**',
|
| + 'LShift': '<<', 'RShift': '>>', 'BitOr': '|', 'BitAnd': '&',
|
| + 'BitXor': '^', 'FloorDiv': '//', 'Invert': '~',
|
| + 'Not': 'not', 'UAdd': '+', 'USub': '-', 'Eq': '==',
|
| + 'NotEq': '!=', 'Lt': '<', 'LtE': '<=', 'Gt': '>',
|
| + 'GtE': '>=', 'Is': 'is', 'IsNot': 'is not', 'In': 'in',
|
| + 'NotIn': 'not in'}
|
| +
|
| + def _get_op(self, node):
|
| + return self._operators[node.__class__.__name__].split(' ')
|
| +
|
| + def _Attribute(self, node):
|
| + self._handle(node, [node.value, '.', node.attr])
|
| +
|
| + def _Assert(self, node):
|
| + children = ['assert', node.test]
|
| + if node.msg:
|
| + children.append(',')
|
| + children.append(node.msg)
|
| + self._handle(node, children)
|
| +
|
| + def _Assign(self, node):
|
| + children = self._child_nodes(node.targets, '=')
|
| + children.append('=')
|
| + children.append(node.value)
|
| + self._handle(node, children)
|
| +
|
| + def _AugAssign(self, node):
|
| + children = [node.target]
|
| + children.extend(self._get_op(node.op))
|
| + children.extend(['=', node.value])
|
| + self._handle(node, children)
|
| +
|
| + def _Repr(self, node):
|
| + self._handle(node, ['`', node.value, '`'])
|
| +
|
| + def _BinOp(self, node):
|
| + children = [node.left] + self._get_op(node.op) + [node.right]
|
| + self._handle(node, children)
|
| +
|
| + def _BoolOp(self, node):
|
| + self._handle(node, self._child_nodes(node.values,
|
| + self._get_op(node.op)[0]))
|
| +
|
| + def _Break(self, node):
|
| + self._handle(node, ['break'])
|
| +
|
| + def _Call(self, node):
|
| + children = [node.func, '(']
|
| + args = list(node.args) + node.keywords
|
| + children.extend(self._child_nodes(args, ','))
|
| + if node.starargs is not None:
|
| + if args:
|
| + children.append(',')
|
| + children.extend(['*', node.starargs])
|
| + if node.kwargs is not None:
|
| + if args or node.starargs is not None:
|
| + children.append(',')
|
| + children.extend(['**', node.kwargs])
|
| + children.append(')')
|
| + self._handle(node, children)
|
| +
|
| + def _ClassDef(self, node):
|
| + children = []
|
| + if getattr(node, 'decorator_list', None):
|
| + for decorator in node.decorator_list:
|
| + children.append('@')
|
| + children.append(decorator)
|
| + children.extend(['class', node.name])
|
| + if node.bases:
|
| + children.append('(')
|
| + children.extend(self._child_nodes(node.bases, ','))
|
| + children.append(')')
|
| + children.append(':')
|
| + children.extend(node.body)
|
| + self._handle(node, children)
|
| +
|
| + def _Compare(self, node):
|
| + children = []
|
| + children.append(node.left)
|
| + for op, expr in zip(node.ops, node.comparators):
|
| + children.extend(self._get_op(op))
|
| + children.append(expr)
|
| + self._handle(node, children)
|
| +
|
| + def _Delete(self, node):
|
| + self._handle(node, ['del'] + self._child_nodes(node.targets, ','))
|
| +
|
| + def _Num(self, node):
|
| + self._handle(node, [self.Number])
|
| +
|
| + def _Str(self, node):
|
| + self._handle(node, [self.String])
|
| +
|
| + def _Continue(self, node):
|
| + self._handle(node, ['continue'])
|
| +
|
| + def _Dict(self, node):
|
| + children = []
|
| + children.append('{')
|
| + if node.keys:
|
| + for index, (key, value) in enumerate(zip(node.keys, node.values)):
|
| + children.extend([key, ':', value])
|
| + if index < len(node.keys) - 1:
|
| + children.append(',')
|
| + children.append('}')
|
| + self._handle(node, children)
|
| +
|
| + def _Ellipsis(self, node):
|
| + self._handle(node, ['...'])
|
| +
|
| + def _Expr(self, node):
|
| + self._handle(node, [node.value])
|
| +
|
| + def _Exec(self, node):
|
| + children = []
|
| + children.extend(['exec', node.body])
|
| + if node.globals:
|
| + children.extend(['in', node.globals])
|
| + if node.locals:
|
| + children.extend([',', node.locals])
|
| + self._handle(node, children)
|
| +
|
| + def _ExtSlice(self, node):
|
| + children = []
|
| + for index, dim in enumerate(node.dims):
|
| + if index > 0:
|
| + children.append(',')
|
| + children.append(dim)
|
| + self._handle(node, children)
|
| +
|
| + def _For(self, node):
|
| + children = ['for', node.target, 'in', node.iter, ':']
|
| + children.extend(node.body)
|
| + if node.orelse:
|
| + children.extend(['else', ':'])
|
| + children.extend(node.orelse)
|
| + self._handle(node, children)
|
| +
|
| + def _ImportFrom(self, node):
|
| + children = ['from']
|
| + if node.level:
|
| + children.append('.' * node.level)
|
| + # see comment at rope.base.ast.walk
|
| + children.extend([node.module or '',
|
| + 'import'])
|
| + children.extend(self._child_nodes(node.names, ','))
|
| + self._handle(node, children)
|
| +
|
| + def _alias(self, node):
|
| + children = [node.name]
|
| + if node.asname:
|
| + children.extend(['as', node.asname])
|
| + self._handle(node, children)
|
| +
|
| + def _FunctionDef(self, node):
|
| + children = []
|
| + try:
|
| + decorators = getattr(node, 'decorator_list')
|
| + except AttributeError:
|
| + decorators = getattr(node, 'decorators', None)
|
| + if decorators:
|
| + for decorator in decorators:
|
| + children.append('@')
|
| + children.append(decorator)
|
| + children.extend(['def', node.name, '(', node.args])
|
| + children.extend([')', ':'])
|
| + children.extend(node.body)
|
| + self._handle(node, children)
|
| +
|
| + def _arguments(self, node):
|
| + children = []
|
| + args = list(node.args)
|
| + defaults = [None] * (len(args) - len(node.defaults)) + \
|
| + list(node.defaults)
|
| + for index, (arg, default) in enumerate(zip(args, defaults)):
|
| + if index > 0:
|
| + children.append(',')
|
| + self._add_args_to_children(children, arg, default)
|
| + if node.vararg is not None:
|
| + if args:
|
| + children.append(',')
|
| + children.extend(['*', node.vararg])
|
| + if node.kwarg is not None:
|
| + if args or node.vararg is not None:
|
| + children.append(',')
|
| + children.extend(['**', node.kwarg])
|
| + self._handle(node, children)
|
| +
|
| + def _add_args_to_children(self, children, arg, default):
|
| + if isinstance(arg, (list, tuple)):
|
| + self._add_tuple_parameter(children, arg)
|
| + else:
|
| + children.append(arg)
|
| + if default is not None:
|
| + children.append('=')
|
| + children.append(default)
|
| +
|
| + def _add_tuple_parameter(self, children, arg):
|
| + children.append('(')
|
| + for index, token in enumerate(arg):
|
| + if index > 0:
|
| + children.append(',')
|
| + if isinstance(token, (list, tuple)):
|
| + self._add_tuple_parameter(children, token)
|
| + else:
|
| + children.append(token)
|
| + children.append(')')
|
| +
|
| + def _GeneratorExp(self, node):
|
| + children = [node.elt]
|
| + children.extend(node.generators)
|
| + self._handle(node, children, eat_parens=True)
|
| +
|
| + def _comprehension(self, node):
|
| + children = ['for', node.target, 'in', node.iter]
|
| + if node.ifs:
|
| + for if_ in node.ifs:
|
| + children.append('if')
|
| + children.append(if_)
|
| + self._handle(node, children)
|
| +
|
| + def _Global(self, node):
|
| + children = self._child_nodes(node.names, ',')
|
| + children.insert(0, 'global')
|
| + self._handle(node, children)
|
| +
|
| + def _If(self, node):
|
| + if self._is_elif(node):
|
| + children = ['elif']
|
| + else:
|
| + children = ['if']
|
| + children.extend([node.test, ':'])
|
| + children.extend(node.body)
|
| + if node.orelse:
|
| + if len(node.orelse) == 1 and self._is_elif(node.orelse[0]):
|
| + pass
|
| + else:
|
| + children.extend(['else', ':'])
|
| + children.extend(node.orelse)
|
| + self._handle(node, children)
|
| +
|
| + def _is_elif(self, node):
|
| + if not isinstance(node, ast.If):
|
| + return False
|
| + offset = self.lines.get_line_start(node.lineno) + node.col_offset
|
| + word = self.source[offset:offset + 4]
|
| + # XXX: This is a bug; the offset does not point to the first
|
| + alt_word = self.source[offset - 5:offset - 1]
|
| + return 'elif' in (word, alt_word)
|
| +
|
| + def _IfExp(self, node):
|
| + return self._handle(node, [node.body, 'if', node.test,
|
| + 'else', node.orelse])
|
| +
|
| + def _Import(self, node):
|
| + children = ['import']
|
| + children.extend(self._child_nodes(node.names, ','))
|
| + self._handle(node, children)
|
| +
|
| + def _keyword(self, node):
|
| + self._handle(node, [node.arg, '=', node.value])
|
| +
|
| + def _Lambda(self, node):
|
| + self._handle(node, ['lambda', node.args, ':', node.body])
|
| +
|
| + def _List(self, node):
|
| + self._handle(node, ['['] + self._child_nodes(node.elts, ',') + [']'])
|
| +
|
| + def _ListComp(self, node):
|
| + children = ['[', node.elt]
|
| + children.extend(node.generators)
|
| + children.append(']')
|
| + self._handle(node, children)
|
| +
|
| + def _Module(self, node):
|
| + self._handle(node, list(node.body), eat_spaces=True)
|
| +
|
| + def _Name(self, node):
|
| + self._handle(node, [node.id])
|
| +
|
| + def _Pass(self, node):
|
| + self._handle(node, ['pass'])
|
| +
|
| + def _Print(self, node):
|
| + children = ['print']
|
| + if node.dest:
|
| + children.extend(['>>', node.dest])
|
| + if node.values:
|
| + children.append(',')
|
| + children.extend(self._child_nodes(node.values, ','))
|
| + if not node.nl:
|
| + children.append(',')
|
| + self._handle(node, children)
|
| +
|
| + def _Raise(self, node):
|
| + children = ['raise']
|
| + if node.type:
|
| + children.append(node.type)
|
| + if node.inst:
|
| + children.append(',')
|
| + children.append(node.inst)
|
| + if node.tback:
|
| + children.append(',')
|
| + children.append(node.tback)
|
| + self._handle(node, children)
|
| +
|
| + def _Return(self, node):
|
| + children = ['return']
|
| + if node.value:
|
| + children.append(node.value)
|
| + self._handle(node, children)
|
| +
|
| + def _Sliceobj(self, node):
|
| + children = []
|
| + for index, slice in enumerate(node.nodes):
|
| + if index > 0:
|
| + children.append(':')
|
| + if slice:
|
| + children.append(slice)
|
| + self._handle(node, children)
|
| +
|
| + def _Index(self, node):
|
| + self._handle(node, [node.value])
|
| +
|
| + def _Subscript(self, node):
|
| + self._handle(node, [node.value, '[', node.slice, ']'])
|
| +
|
| + def _Slice(self, node):
|
| + children = []
|
| + if node.lower:
|
| + children.append(node.lower)
|
| + children.append(':')
|
| + if node.upper:
|
| + children.append(node.upper)
|
| + if node.step:
|
| + children.append(':')
|
| + children.append(node.step)
|
| + self._handle(node, children)
|
| +
|
| + def _TryFinally(self, node):
|
| + children = []
|
| + if len(node.body) != 1 or not isinstance(node.body[0], ast.TryExcept):
|
| + children.extend(['try', ':'])
|
| + children.extend(node.body)
|
| + children.extend(['finally', ':'])
|
| + children.extend(node.finalbody)
|
| + self._handle(node, children)
|
| +
|
| + def _TryExcept(self, node):
|
| + children = ['try', ':']
|
| + children.extend(node.body)
|
| + children.extend(node.handlers)
|
| + if node.orelse:
|
| + children.extend(['else', ':'])
|
| + children.extend(node.orelse)
|
| + self._handle(node, children)
|
| +
|
| + def _ExceptHandler(self, node):
|
| + self._excepthandler(node)
|
| +
|
| + def _excepthandler(self, node):
|
| + # self._handle(node, [self.semicolon_or_as_in_except])
|
| + children = ['except']
|
| + if node.type:
|
| + children.append(node.type)
|
| + if node.name:
|
| + children.append(self.semicolon_or_as_in_except)
|
| + children.append(node.name)
|
| + children.append(':')
|
| + children.extend(node.body)
|
| +
|
| + self._handle(node, children)
|
| +
|
| + def _Tuple(self, node):
|
| + if node.elts:
|
| + self._handle(node, self._child_nodes(node.elts, ','),
|
| + eat_parens=True)
|
| + else:
|
| + self._handle(node, ['(', ')'])
|
| +
|
| + def _UnaryOp(self, node):
|
| + children = self._get_op(node.op)
|
| + children.append(node.operand)
|
| + self._handle(node, children)
|
| +
|
| + def _Yield(self, node):
|
| + children = ['yield']
|
| + if node.value:
|
| + children.append(node.value)
|
| + self._handle(node, children)
|
| +
|
| + def _While(self, node):
|
| + children = ['while', node.test, ':']
|
| + children.extend(node.body)
|
| + if node.orelse:
|
| + children.extend(['else', ':'])
|
| + children.extend(node.orelse)
|
| + self._handle(node, children)
|
| +
|
| + def _With(self, node):
|
| + children = ['with', node.context_expr]
|
| + if node.optional_vars:
|
| + children.extend(['as', node.optional_vars])
|
| + children.append(':')
|
| + children.extend(node.body)
|
| + self._handle(node, children)
|
| +
|
| + def _child_nodes(self, nodes, separator):
|
| + children = []
|
| + for index, child in enumerate(nodes):
|
| + children.append(child)
|
| + if index < len(nodes) - 1:
|
| + children.append(separator)
|
| + return children
|
| +
|
| +
|
| +class _Source(object):
|
| +
|
| + def __init__(self, source):
|
| + self.source = source
|
| + self.offset = 0
|
| +
|
| + def consume(self, token):
|
| + try:
|
| + while True:
|
| + new_offset = self.source.index(token, self.offset)
|
| + if self._good_token(token, new_offset):
|
| + break
|
| + else:
|
| + self._skip_comment()
|
| + except (ValueError, TypeError):
|
| + raise MismatchedTokenError(
|
| + 'Token <%s> at %s cannot be matched' %
|
| + (token, self._get_location()))
|
| + self.offset = new_offset + len(token)
|
| + return (new_offset, self.offset)
|
| +
|
| + def consume_string(self, end=None):
|
| + if _Source._string_pattern is None:
|
| + original = codeanalyze.get_string_pattern()
|
| + pattern = r'(%s)((\s|\\\n|#[^\n]*\n)*(%s))*' % \
|
| + (original, original)
|
| + _Source._string_pattern = re.compile(pattern)
|
| + repattern = _Source._string_pattern
|
| + return self._consume_pattern(repattern, end)
|
| +
|
| + def consume_number(self):
|
| + if _Source._number_pattern is None:
|
| + _Source._number_pattern = re.compile(
|
| + self._get_number_pattern())
|
| + repattern = _Source._number_pattern
|
| + return self._consume_pattern(repattern)
|
| +
|
| + def consume_not_equal(self):
|
| + if _Source._not_equals_pattern is None:
|
| + _Source._not_equals_pattern = re.compile(r'<>|!=')
|
| + repattern = _Source._not_equals_pattern
|
| + return self._consume_pattern(repattern)
|
| +
|
| + def consume_except_as_or_semicolon(self):
|
| + repattern = re.compile(r'as|,')
|
| + return self._consume_pattern(repattern)
|
| +
|
| + def _good_token(self, token, offset, start=None):
|
| + """Checks whether consumed token is in comments"""
|
| + if start is None:
|
| + start = self.offset
|
| + try:
|
| + comment_index = self.source.rindex('#', start, offset)
|
| + except ValueError:
|
| + return True
|
| + try:
|
| + new_line_index = self.source.rindex('\n', start, offset)
|
| + except ValueError:
|
| + return False
|
| + return comment_index < new_line_index
|
| +
|
| + def _skip_comment(self):
|
| + self.offset = self.source.index('\n', self.offset + 1)
|
| +
|
| + def _get_location(self):
|
| + lines = self.source[:self.offset].split('\n')
|
| + return (len(lines), len(lines[-1]))
|
| +
|
| + def _consume_pattern(self, repattern, end=None):
|
| + while True:
|
| + if end is None:
|
| + end = len(self.source)
|
| + match = repattern.search(self.source, self.offset, end)
|
| + if self._good_token(match.group(), match.start()):
|
| + break
|
| + else:
|
| + self._skip_comment()
|
| + self.offset = match.end()
|
| + return match.start(), match.end()
|
| +
|
| + def till_token(self, token):
|
| + new_offset = self.source.index(token, self.offset)
|
| + return self[self.offset:new_offset]
|
| +
|
| + def rfind_token(self, token, start, end):
|
| + index = start
|
| + while True:
|
| + try:
|
| + index = self.source.rindex(token, start, end)
|
| + if self._good_token(token, index, start=start):
|
| + return index
|
| + else:
|
| + end = index
|
| + except ValueError:
|
| + return None
|
| +
|
| + def from_offset(self, offset):
|
| + return self[offset:self.offset]
|
| +
|
| + def find_backwards(self, pattern, offset):
|
| + return self.source.rindex(pattern, 0, offset)
|
| +
|
| + def __getitem__(self, index):
|
| + return self.source[index]
|
| +
|
| + def __getslice__(self, i, j):
|
| + return self.source[i:j]
|
| +
|
| + def _get_number_pattern(self):
|
| + # HACK: It is merely an approaximation and does the job
|
| + integer = r'(0|0x)?[\da-fA-F]+[lL]?'
|
| + return r'(%s(\.\d*)?|(\.\d+))([eE][-+]?\d*)?[jJ]?' % integer
|
| +
|
| + _string_pattern = None
|
| + _number_pattern = None
|
| + _not_equals_pattern = None
|
|
|