blob: 60d219f57707a41dae8b4d9a0abef4894e148374 [file] [log] [blame]
Martin v. Löwisef04c442008-03-19 05:04:44 +00001"""Utility functions, node construction macros, etc."""
2# Author: Collin Winter
3
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +00004from itertools import islice
5
Martin v. Löwisef04c442008-03-19 05:04:44 +00006# Local imports
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +00007from .pgen2 import token
8from .pytree import Leaf, Node
9from .pygram import python_symbols as syms
10from . import patcomp
Martin v. Löwisef04c442008-03-19 05:04:44 +000011
12
13###########################################################
14### Common node-construction "macros"
15###########################################################
16
17def KeywordArg(keyword, value):
18 return Node(syms.argument,
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +000019 [keyword, Leaf(token.EQUAL, "="), value])
Martin v. Löwisef04c442008-03-19 05:04:44 +000020
21def LParen():
22 return Leaf(token.LPAR, "(")
23
24def RParen():
25 return Leaf(token.RPAR, ")")
26
27def Assign(target, source):
28 """Build an assignment statement"""
29 if not isinstance(target, list):
30 target = [target]
31 if not isinstance(source, list):
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000032 source.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +000033 source = [source]
34
35 return Node(syms.atom,
36 target + [Leaf(token.EQUAL, "=", prefix=" ")] + source)
37
38def Name(name, prefix=None):
39 """Return a NAME leaf"""
40 return Leaf(token.NAME, name, prefix=prefix)
41
42def Attr(obj, attr):
43 """A node tuple for obj.attr"""
44 return [obj, Node(syms.trailer, [Dot(), attr])]
45
46def Comma():
47 """A comma leaf"""
48 return Leaf(token.COMMA, ",")
49
50def Dot():
51 """A period (.) leaf"""
52 return Leaf(token.DOT, ".")
53
54def ArgList(args, lparen=LParen(), rparen=RParen()):
55 """A parenthesised argument list, used by Call()"""
Benjamin Petersoncf603822008-09-01 19:56:06 +000056 node = Node(syms.trailer, [lparen.clone(), rparen.clone()])
57 if args:
58 node.insert_child(1, Node(syms.arglist, args))
59 return node
Martin v. Löwisef04c442008-03-19 05:04:44 +000060
Benjamin Petersoncf603822008-09-01 19:56:06 +000061def Call(func_name, args=None, prefix=None):
Martin v. Löwisef04c442008-03-19 05:04:44 +000062 """A function call"""
63 node = Node(syms.power, [func_name, ArgList(args)])
64 if prefix is not None:
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000065 node.prefix = prefix
Martin v. Löwisef04c442008-03-19 05:04:44 +000066 return node
67
68def Newline():
69 """A newline literal"""
70 return Leaf(token.NEWLINE, "\n")
71
72def BlankLine():
73 """A blank line"""
74 return Leaf(token.NEWLINE, "")
75
76def Number(n, prefix=None):
77 return Leaf(token.NUMBER, n, prefix=prefix)
78
79def Subscript(index_node):
80 """A numeric or string subscript"""
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +000081 return Node(syms.trailer, [Leaf(token.LBRACE, "["),
Martin v. Löwisef04c442008-03-19 05:04:44 +000082 index_node,
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +000083 Leaf(token.RBRACE, "]")])
Martin v. Löwisef04c442008-03-19 05:04:44 +000084
85def String(string, prefix=None):
86 """A string leaf"""
87 return Leaf(token.STRING, string, prefix=prefix)
88
89def ListComp(xp, fp, it, test=None):
90 """A list comprehension of the form [xp for fp in it if test].
91
92 If test is None, the "if test" part is omitted.
93 """
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000094 xp.prefix = ""
95 fp.prefix = " "
96 it.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +000097 for_leaf = Leaf(token.NAME, "for")
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +000098 for_leaf.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +000099 in_leaf = Leaf(token.NAME, "in")
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +0000100 in_leaf.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +0000101 inner_args = [for_leaf, fp, in_leaf, it]
102 if test:
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +0000103 test.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +0000104 if_leaf = Leaf(token.NAME, "if")
Benjamin Peterson2c3ac6b2009-06-11 23:47:38 +0000105 if_leaf.prefix = " "
Martin v. Löwisef04c442008-03-19 05:04:44 +0000106 inner_args.append(Node(syms.comp_if, [if_leaf, test]))
107 inner = Node(syms.listmaker, [xp, Node(syms.comp_for, inner_args)])
108 return Node(syms.atom,
109 [Leaf(token.LBRACE, "["),
110 inner,
111 Leaf(token.RBRACE, "]")])
112
Martin v. Löwisa675ef12008-03-24 00:50:58 +0000113def FromImport(package_name, name_leafs):
114 """ Return an import statement in the form:
115 from package import name_leafs"""
116 # XXX: May not handle dotted imports properly (eg, package_name='foo.bar')
Benjamin Petersond613bb42008-07-16 18:44:47 +0000117 #assert package_name == '.' or '.' not in package_name, "FromImport has "\
118 # "not been tested with dotted package names -- use at your own "\
119 # "peril!"
Martin v. Löwisa675ef12008-03-24 00:50:58 +0000120
121 for leaf in name_leafs:
122 # Pull the leaves out of their old tree
123 leaf.remove()
124
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000125 children = [Leaf(token.NAME, "from"),
Martin v. Löwisa675ef12008-03-24 00:50:58 +0000126 Leaf(token.NAME, package_name, prefix=" "),
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000127 Leaf(token.NAME, "import", prefix=" "),
Martin v. Löwisa675ef12008-03-24 00:50:58 +0000128 Node(syms.import_as_names, name_leafs)]
129 imp = Node(syms.import_from, children)
130 return imp
131
132
Martin v. Löwisef04c442008-03-19 05:04:44 +0000133###########################################################
134### Determine whether a node represents a given literal
135###########################################################
136
137def is_tuple(node):
138 """Does the node represent a tuple literal?"""
139 if isinstance(node, Node) and node.children == [LParen(), RParen()]:
140 return True
141 return (isinstance(node, Node)
142 and len(node.children) == 3
143 and isinstance(node.children[0], Leaf)
144 and isinstance(node.children[1], Node)
145 and isinstance(node.children[2], Leaf)
146 and node.children[0].value == "("
147 and node.children[2].value == ")")
148
149def is_list(node):
150 """Does the node represent a list literal?"""
151 return (isinstance(node, Node)
152 and len(node.children) > 1
153 and isinstance(node.children[0], Leaf)
154 and isinstance(node.children[-1], Leaf)
155 and node.children[0].value == "["
156 and node.children[-1].value == "]")
157
Martin v. Löwisef04c442008-03-19 05:04:44 +0000158
159###########################################################
160### Misc
161###########################################################
162
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000163def parenthesize(node):
164 return Node(syms.atom, [LParen(), node, RParen()])
165
Martin v. Löwis3de92bf2008-04-10 02:50:50 +0000166
167consuming_calls = set(["sorted", "list", "set", "any", "all", "tuple", "sum",
Benjamin Peterson57af3872012-11-29 10:55:22 -0500168 "min", "max", "enumerate"])
Martin v. Löwis3de92bf2008-04-10 02:50:50 +0000169
Martin v. Löwisef04c442008-03-19 05:04:44 +0000170def attr_chain(obj, attr):
171 """Follow an attribute chain.
Martin v. Löwisf733c602008-03-19 05:26:18 +0000172
Martin v. Löwisef04c442008-03-19 05:04:44 +0000173 If you have a chain of objects where a.foo -> b, b.foo-> c, etc,
174 use this to iterate over all objects in the chain. Iteration is
175 terminated by getattr(x, attr) is None.
Martin v. Löwisf733c602008-03-19 05:26:18 +0000176
Martin v. Löwisef04c442008-03-19 05:04:44 +0000177 Args:
178 obj: the starting object
179 attr: the name of the chaining attribute
Martin v. Löwisf733c602008-03-19 05:26:18 +0000180
Martin v. Löwisef04c442008-03-19 05:04:44 +0000181 Yields:
182 Each successive object in the chain.
183 """
184 next = getattr(obj, attr)
185 while next:
186 yield next
187 next = getattr(next, attr)
188
Martin v. Löwisf733c602008-03-19 05:26:18 +0000189p0 = """for_stmt< 'for' any 'in' node=any ':' any* >
190 | comp_for< 'for' any 'in' node=any any* >
191 """
192p1 = """
193power<
194 ( 'iter' | 'list' | 'tuple' | 'sorted' | 'set' | 'sum' |
Benjamin Peterson57af3872012-11-29 10:55:22 -0500195 'any' | 'all' | 'enumerate' | (any* trailer< '.' 'join' >) )
Martin v. Löwisf733c602008-03-19 05:26:18 +0000196 trailer< '(' node=any ')' >
197 any*
198>
199"""
200p2 = """
201power<
Benjamin Peterson57af3872012-11-29 10:55:22 -0500202 ( 'sorted' | 'enumerate' )
Martin v. Löwisf733c602008-03-19 05:26:18 +0000203 trailer< '(' arglist<node=any any*> ')' >
204 any*
205>
206"""
207pats_built = False
208def in_special_context(node):
209 """ Returns true if node is in an environment where all that is required
Benjamin Peterson57af3872012-11-29 10:55:22 -0500210 of it is being iterable (ie, it doesn't matter if it returns a list
211 or an iterator).
Martin v. Löwisf733c602008-03-19 05:26:18 +0000212 See test_map_nochange in test_fixers.py for some examples and tests.
213 """
214 global p0, p1, p2, pats_built
215 if not pats_built:
Martin v. Löwisf733c602008-03-19 05:26:18 +0000216 p0 = patcomp.compile_pattern(p0)
Benjamin Peterson57af3872012-11-29 10:55:22 -0500217 p1 = patcomp.compile_pattern(p1)
Martin v. Löwisf733c602008-03-19 05:26:18 +0000218 p2 = patcomp.compile_pattern(p2)
219 pats_built = True
220 patterns = [p0, p1, p2]
221 for pattern, parent in zip(patterns, attr_chain(node, "parent")):
222 results = {}
223 if pattern.match(parent, results) and results["node"] is node:
224 return True
225 return False
226
Benjamin Peterson8bcddca2009-01-03 16:53:14 +0000227def is_probably_builtin(node):
228 """
229 Check that something isn't an attribute or function name etc.
230 """
Benjamin Peterson608d8bc2009-05-05 23:23:31 +0000231 prev = node.prev_sibling
Benjamin Peterson8bcddca2009-01-03 16:53:14 +0000232 if prev is not None and prev.type == token.DOT:
233 # Attribute lookup.
234 return False
235 parent = node.parent
236 if parent.type in (syms.funcdef, syms.classdef):
237 return False
238 if parent.type == syms.expr_stmt and parent.children[0] is node:
239 # Assignment.
240 return False
241 if parent.type == syms.parameters or \
242 (parent.type == syms.typedargslist and (
243 (prev is not None and prev.type == token.COMMA) or
244 parent.children[0] is node
245 )):
246 # The name of an argument.
247 return False
248 return True
249
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000250def find_indentation(node):
251 """Find the indentation of *node*."""
252 while node is not None:
253 if node.type == syms.suite and len(node.children) > 2:
254 indent = node.children[1]
255 if indent.type == token.INDENT:
256 return indent.value
257 node = node.parent
258 return ""
259
Martin v. Löwisef04c442008-03-19 05:04:44 +0000260###########################################################
261### The following functions are to find bindings in a suite
262###########################################################
263
264def make_suite(node):
265 if node.type == syms.suite:
266 return node
267 node = node.clone()
268 parent, node.parent = node.parent, None
269 suite = Node(syms.suite, [node])
270 suite.parent = parent
271 return suite
272
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000273def find_root(node):
274 """Find the top level namespace."""
Martin v. Löwisef04c442008-03-19 05:04:44 +0000275 # Scamper up to the top level namespace
276 while node.type != syms.file_input:
Martin v. Löwisef04c442008-03-19 05:04:44 +0000277 node = node.parent
Benjamin Peterson1654d742012-09-25 11:48:50 -0400278 if not node:
279 raise ValueError("root found before file_input node was found.")
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000280 return node
Martin v. Löwisef04c442008-03-19 05:04:44 +0000281
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000282def does_tree_import(package, name, node):
283 """ Returns true if name is imported from package at the
284 top level of the tree which node belongs to.
285 To cover the case of an import like 'import foo', use
286 None for the package and 'foo' for the name. """
287 binding = find_binding(name, find_root(node), package)
Martin v. Löwisef04c442008-03-19 05:04:44 +0000288 return bool(binding)
289
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000290def is_import(node):
291 """Returns true if the node is an import statement."""
292 return node.type in (syms.import_name, syms.import_from)
293
294def touch_import(package, name, node):
295 """ Works like `does_tree_import` but adds an import statement
296 if it was not imported. """
297 def is_import_stmt(node):
Benjamin Petersonf37eb3a2010-10-14 23:00:04 +0000298 return (node.type == syms.simple_stmt and node.children and
299 is_import(node.children[0]))
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000300
301 root = find_root(node)
302
303 if does_tree_import(package, name, root):
304 return
305
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000306 # figure out where to insert the new import. First try to find
307 # the first import and then skip to the last one.
308 insert_pos = offset = 0
309 for idx, node in enumerate(root.children):
310 if not is_import_stmt(node):
311 continue
312 for offset, node2 in enumerate(root.children[idx:]):
313 if not is_import_stmt(node2):
314 break
315 insert_pos = idx + offset
316 break
317
318 # if there are no imports where we can insert, find the docstring.
319 # if that also fails, we stick to the beginning of the file
320 if insert_pos == 0:
321 for idx, node in enumerate(root.children):
Benjamin Petersonf37eb3a2010-10-14 23:00:04 +0000322 if (node.type == syms.simple_stmt and node.children and
323 node.children[0].type == token.STRING):
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000324 insert_pos = idx + 1
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000325 break
326
327 if package is None:
328 import_ = Node(syms.import_name, [
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000329 Leaf(token.NAME, "import"),
330 Leaf(token.NAME, name, prefix=" ")
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000331 ])
332 else:
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000333 import_ = FromImport(package, [Leaf(token.NAME, name, prefix=" ")])
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000334
335 children = [import_, Newline()]
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000336 root.insert_child(insert_pos, Node(syms.simple_stmt, children))
337
338
Martin v. Löwisef04c442008-03-19 05:04:44 +0000339_def_syms = set([syms.classdef, syms.funcdef])
340def find_binding(name, node, package=None):
341 """ Returns the node which binds variable name, otherwise None.
342 If optional argument package is supplied, only imports will
343 be returned.
344 See test cases for examples."""
345 for child in node.children:
346 ret = None
347 if child.type == syms.for_stmt:
348 if _find(name, child.children[1]):
349 return child
350 n = find_binding(name, make_suite(child.children[-1]), package)
351 if n: ret = n
352 elif child.type in (syms.if_stmt, syms.while_stmt):
353 n = find_binding(name, make_suite(child.children[-1]), package)
354 if n: ret = n
355 elif child.type == syms.try_stmt:
356 n = find_binding(name, make_suite(child.children[2]), package)
357 if n:
358 ret = n
359 else:
360 for i, kid in enumerate(child.children[3:]):
361 if kid.type == token.COLON and kid.value == ":":
362 # i+3 is the colon, i+4 is the suite
363 n = find_binding(name, make_suite(child.children[i+4]), package)
364 if n: ret = n
365 elif child.type in _def_syms and child.children[1].value == name:
366 ret = child
367 elif _is_import_binding(child, name, package):
368 ret = child
369 elif child.type == syms.simple_stmt:
370 ret = find_binding(name, child, package)
371 elif child.type == syms.expr_stmt:
Martin v. Löwisf733c602008-03-19 05:26:18 +0000372 if _find(name, child.children[0]):
373 ret = child
Martin v. Löwisef04c442008-03-19 05:04:44 +0000374
375 if ret:
376 if not package:
377 return ret
Benjamin Peterson0b24b3d2008-12-16 03:57:54 +0000378 if is_import(ret):
Martin v. Löwisef04c442008-03-19 05:04:44 +0000379 return ret
380 return None
381
382_block_syms = set([syms.funcdef, syms.classdef, syms.trailer])
383def _find(name, node):
384 nodes = [node]
385 while nodes:
386 node = nodes.pop()
387 if node.type > 256 and node.type not in _block_syms:
388 nodes.extend(node.children)
389 elif node.type == token.NAME and node.value == name:
390 return node
391 return None
392
393def _is_import_binding(node, name, package=None):
394 """ Will reuturn node if node will import name, or node
395 will import * from package. None is returned otherwise.
396 See test cases for examples. """
397
398 if node.type == syms.import_name and not package:
399 imp = node.children[1]
400 if imp.type == syms.dotted_as_names:
401 for child in imp.children:
402 if child.type == syms.dotted_as_name:
403 if child.children[2].value == name:
404 return node
405 elif child.type == token.NAME and child.value == name:
406 return node
407 elif imp.type == syms.dotted_as_name:
408 last = imp.children[-1]
409 if last.type == token.NAME and last.value == name:
410 return node
411 elif imp.type == token.NAME and imp.value == name:
412 return node
413 elif node.type == syms.import_from:
Benjamin Petersondf6dc8f2008-06-15 02:57:40 +0000414 # str(...) is used to make life easier here, because
Martin v. Löwisef04c442008-03-19 05:04:44 +0000415 # from a.b import parses to ['import', ['a', '.', 'b'], ...]
Martin v. Löwis8a5f8ca2008-03-19 05:33:36 +0000416 if package and str(node.children[1]).strip() != package:
Martin v. Löwisef04c442008-03-19 05:04:44 +0000417 return None
418 n = node.children[3]
Benjamin Peterson4eb5fa52010-08-08 19:01:25 +0000419 if package and _find("as", n):
Martin v. Löwisef04c442008-03-19 05:04:44 +0000420 # See test_from_import_as for explanation
421 return None
422 elif n.type == syms.import_as_names and _find(name, n):
423 return node
424 elif n.type == syms.import_as_name:
425 child = n.children[2]
426 if child.type == token.NAME and child.value == name:
427 return node
428 elif n.type == token.NAME and n.value == name:
429 return node
430 elif package and n.type == token.STAR:
431 return node
432 return None