OLD | NEW |
| (Empty) |
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. | |
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr | |
3 # copyright 2003-2010 Sylvain Thenault, all rights reserved. | |
4 # contact mailto:thenault@gmail.com | |
5 # | |
6 # This file is part of logilab-astng. | |
7 # | |
8 # logilab-astng is free software: you can redistribute it and/or modify it | |
9 # under the terms of the GNU Lesser General Public License as published by the | |
10 # Free Software Foundation, either version 2.1 of the License, or (at your | |
11 # option) any later version. | |
12 # | |
13 # logilab-astng is distributed in the hope that it will be useful, but | |
14 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | |
16 # for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public License along | |
19 # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. | |
20 """This module renders ASTNG nodes to string representation. | |
21 | |
22 It will probably not work on bare _ast trees. | |
23 """ | |
24 import sys | |
25 | |
26 | |
27 INDENT = ' ' # 4 spaces ; keep indentation variable | |
28 | |
29 | |
30 def _import_string(names): | |
31 """return a list of (name, asname) formatted as a string""" | |
32 _names = [] | |
33 for name, asname in names: | |
34 if asname is not None: | |
35 _names.append('%s as %s' % (name, asname)) | |
36 else: | |
37 _names.append(name) | |
38 return ', '.join(_names) | |
39 | |
40 | |
41 class AsStringVisitor(object): | |
42 """Visitor to render an ASTNG node as string """ | |
43 | |
44 def __call__(self, node): | |
45 """Makes this visitor behave as a simple function""" | |
46 return node.accept(self) | |
47 | |
48 def _stmt_list(self, stmts): | |
49 """return a list of nodes to string""" | |
50 stmts = '\n'.join([nstr for nstr in [n.accept(self) for n in stmts] if n
str]) | |
51 return INDENT + stmts.replace('\n', '\n'+INDENT) | |
52 | |
53 | |
54 ## visit_<node> methods ########################################### | |
55 | |
56 def visit_arguments(self, node): | |
57 """return an astng.Function node as string""" | |
58 return node.format_args() | |
59 | |
60 def visit_assattr(self, node): | |
61 """return an astng.AssAttr node as string""" | |
62 return self.visit_getattr(node) | |
63 | |
64 def visit_assert(self, node): | |
65 """return an astng.Assert node as string""" | |
66 if node.fail: | |
67 return 'assert %s, %s' % (node.test.accept(self), | |
68 node.fail.accept(self)) | |
69 return 'assert %s' % node.test.accept(self) | |
70 | |
71 def visit_assname(self, node): | |
72 """return an astng.AssName node as string""" | |
73 return node.name | |
74 | |
75 def visit_assign(self, node): | |
76 """return an astng.Assign node as string""" | |
77 lhs = ' = '.join([n.accept(self) for n in node.targets]) | |
78 return '%s = %s' % (lhs, node.value.accept(self)) | |
79 | |
80 def visit_augassign(self, node): | |
81 """return an astng.AugAssign node as string""" | |
82 return '%s %s %s' % (node.target.accept(self), node.op, node.value.accep
t(self)) | |
83 | |
84 def visit_backquote(self, node): | |
85 """return an astng.Backquote node as string""" | |
86 return '`%s`' % node.value.accept(self) | |
87 | |
88 def visit_binop(self, node): | |
89 """return an astng.BinOp node as string""" | |
90 return '(%s) %s (%s)' % (node.left.accept(self), node.op, node.right.acc
ept(self)) | |
91 | |
92 def visit_boolop(self, node): | |
93 """return an astng.BoolOp node as string""" | |
94 return (' %s ' % node.op).join(['(%s)' % n.accept(self) | |
95 for n in node.values]) | |
96 | |
97 def visit_break(self, node): | |
98 """return an astng.Break node as string""" | |
99 return 'break' | |
100 | |
101 def visit_callfunc(self, node): | |
102 """return an astng.CallFunc node as string""" | |
103 expr_str = node.func.accept(self) | |
104 args = [arg.accept(self) for arg in node.args] | |
105 if node.starargs: | |
106 args.append( '*' + node.starargs.accept(self)) | |
107 if node.kwargs: | |
108 args.append( '**' + node.kwargs.accept(self)) | |
109 return '%s(%s)' % (expr_str, ', '.join(args)) | |
110 | |
111 def visit_class(self, node): | |
112 """return an astng.Class node as string""" | |
113 decorate = node.decorators and node.decorators.accept(self) or '' | |
114 bases = ', '.join([n.accept(self) for n in node.bases]) | |
115 bases = bases and '(%s)' % bases or '' | |
116 docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' | |
117 return '\n\n%sclass %s%s:%s\n%s\n' % (decorate, node.name, bases, docs, | |
118 self._stmt_list( node.body)) | |
119 | |
120 def visit_compare(self, node): | |
121 """return an astng.Compare node as string""" | |
122 rhs_str = ' '.join(['%s %s' % (op, expr.accept(self)) | |
123 for op, expr in node.ops]) | |
124 return '%s %s' % (node.left.accept(self), rhs_str) | |
125 | |
126 def visit_comprehension(self, node): | |
127 """return an astng.Comprehension node as string""" | |
128 ifs = ''.join([ ' if %s' % n.accept(self) for n in node.ifs]) | |
129 return 'for %s in %s%s' % (node.target.accept(self), | |
130 node.iter.accept(self), ifs ) | |
131 | |
132 def visit_const(self, node): | |
133 """return an astng.Const node as string""" | |
134 return repr(node.value) | |
135 | |
136 def visit_continue(self, node): | |
137 """return an astng.Continue node as string""" | |
138 return 'continue' | |
139 | |
140 def visit_delete(self, node): # XXX check if correct | |
141 """return an astng.Delete node as string""" | |
142 return 'del %s' % ', '.join([child.accept(self) | |
143 for child in node.targets]) | |
144 | |
145 def visit_delattr(self, node): | |
146 """return an astng.DelAttr node as string""" | |
147 return self.visit_getattr(node) | |
148 | |
149 def visit_delname(self, node): | |
150 """return an astng.DelName node as string""" | |
151 return node.name | |
152 | |
153 def visit_decorators(self, node): | |
154 """return an astng.Decorators node as string""" | |
155 return '@%s\n' % '\n@'.join([item.accept(self) for item in node.nodes]) | |
156 | |
157 def visit_dict(self, node): | |
158 """return an astng.Dict node as string""" | |
159 return '{%s}' % ', '.join(['%s: %s' % (key.accept(self), | |
160 value.accept(self)) for key, value in node.items]) | |
161 | |
162 def visit_dictcomp(self, node): | |
163 """return an astng.DictComp node as string""" | |
164 return '{%s: %s %s}' % (node.key.accept(self), node.value.accept(self), | |
165 ' '.join([n.accept(self) for n in node.generators])) | |
166 | |
167 def visit_discard(self, node): | |
168 """return an astng.Discard node as string""" | |
169 return node.value.accept(self) | |
170 | |
171 def visit_emptynode(self, node): | |
172 """dummy method for visiting an Empty node""" | |
173 return '' | |
174 | |
175 def visit_excepthandler(self, node): | |
176 if node.type: | |
177 if node.name: | |
178 excs = 'except %s, %s' % (node.type.accept(self), | |
179 node.name.accept(self)) | |
180 else: | |
181 excs = 'except %s' % node.type.accept(self) | |
182 else: | |
183 excs = 'except' | |
184 return '%s:\n%s' % (excs, self._stmt_list(node.body)) | |
185 | |
186 def visit_ellipsis(self, node): | |
187 """return an astng.Ellipsis node as string""" | |
188 return '...' | |
189 | |
190 def visit_empty(self, node): | |
191 """return an Empty node as string""" | |
192 return '' | |
193 | |
194 def visit_exec(self, node): | |
195 """return an astng.Exec node as string""" | |
196 if node.locals: | |
197 return 'exec %s in %s, %s' % (node.expr.accept(self), | |
198 node.locals.accept(self), | |
199 node.globals.accept(self)) | |
200 if node.globals: | |
201 return 'exec %s in %s' % (node.expr.accept(self), | |
202 node.globals.accept(self)) | |
203 return 'exec %s' % node.expr.accept(self) | |
204 | |
205 def visit_extslice(self, node): | |
206 """return an astng.ExtSlice node as string""" | |
207 return ','.join( [dim.accept(self) for dim in node.dims] ) | |
208 | |
209 def visit_for(self, node): | |
210 """return an astng.For node as string""" | |
211 fors = 'for %s in %s:\n%s' % (node.target.accept(self), | |
212 node.iter.accept(self), | |
213 self._stmt_list( node.body)) | |
214 if node.orelse: | |
215 fors = '%s\nelse:\n%s' % (fors, self._stmt_list(node.orelse)) | |
216 return fors | |
217 | |
218 def visit_from(self, node): | |
219 """return an astng.From node as string""" | |
220 return 'from %s import %s' % ('.' * (node.level or 0) + node.modname, | |
221 _import_string(node.names)) | |
222 | |
223 def visit_function(self, node): | |
224 """return an astng.Function node as string""" | |
225 decorate = node.decorators and node.decorators.accept(self) or '' | |
226 docs = node.doc and '\n%s"""%s"""' % (INDENT, node.doc) or '' | |
227 return '\n%sdef %s(%s):%s\n%s' % (decorate, node.name, node.args.accept(
self), | |
228 docs, self._stmt_list(node.body)) | |
229 | |
230 def visit_genexpr(self, node): | |
231 """return an astng.GenExpr node as string""" | |
232 return '(%s %s)' % (node.elt.accept(self), ' '.join([n.accept(self) | |
233 for n in node.generators])) | |
234 | |
235 def visit_getattr(self, node): | |
236 """return an astng.Getattr node as string""" | |
237 return '%s.%s' % (node.expr.accept(self), node.attrname) | |
238 | |
239 def visit_global(self, node): | |
240 """return an astng.Global node as string""" | |
241 return 'global %s' % ', '.join(node.names) | |
242 | |
243 def visit_if(self, node): | |
244 """return an astng.If node as string""" | |
245 ifs = ['if %s:\n%s' % (node.test.accept(self), self._stmt_list(node.body
))] | |
246 if node.orelse:# XXX use elif ??? | |
247 ifs.append('else:\n%s' % self._stmt_list(node.orelse)) | |
248 return '\n'.join(ifs) | |
249 | |
250 def visit_ifexp(self, node): | |
251 """return an astng.IfExp node as string""" | |
252 return '%s if %s else %s' % (node.body.accept(self), | |
253 node.test.accept(self), node.orelse.accept(self)) | |
254 | |
255 def visit_import(self, node): | |
256 """return an astng.Import node as string""" | |
257 return 'import %s' % _import_string(node.names) | |
258 | |
259 def visit_keyword(self, node): | |
260 """return an astng.Keyword node as string""" | |
261 return '%s=%s' % (node.arg, node.value.accept(self)) | |
262 | |
263 def visit_lambda(self, node): | |
264 """return an astng.Lambda node as string""" | |
265 return 'lambda %s: %s' % (node.args.accept(self), node.body.accept(self)
) | |
266 | |
267 def visit_list(self, node): | |
268 """return an astng.List node as string""" | |
269 return '[%s]' % ', '.join([child.accept(self) for child in node.elts]) | |
270 | |
271 def visit_listcomp(self, node): | |
272 """return an astng.ListComp node as string""" | |
273 return '[%s %s]' % (node.elt.accept(self), ' '.join([n.accept(self) | |
274 for n in node.generators])) | |
275 | |
276 def visit_module(self, node): | |
277 """return an astng.Module node as string""" | |
278 docs = node.doc and '"""%s"""\n\n' % node.doc or '' | |
279 return docs + '\n'.join([n.accept(self) for n in node.body]) + '\n\n' | |
280 | |
281 def visit_name(self, node): | |
282 """return an astng.Name node as string""" | |
283 return node.name | |
284 | |
285 def visit_pass(self, node): | |
286 """return an astng.Pass node as string""" | |
287 return 'pass' | |
288 | |
289 def visit_print(self, node): | |
290 """return an astng.Print node as string""" | |
291 nodes = ', '.join([n.accept(self) for n in node.values]) | |
292 if not node.nl: | |
293 nodes = '%s,' % nodes | |
294 if node.dest: | |
295 return 'print >> %s, %s' % (node.dest.accept(self), nodes) | |
296 return 'print %s' % nodes | |
297 | |
298 def visit_raise(self, node): | |
299 """return an astng.Raise node as string""" | |
300 if node.exc: | |
301 if node.inst: | |
302 if node.tback: | |
303 return 'raise %s, %s, %s' % (node.exc.accept(self), | |
304 node.inst.accept(self), | |
305 node.tback.accept(self)) | |
306 return 'raise %s, %s' % (node.exc.accept(self), | |
307 node.inst.accept(self)) | |
308 return 'raise %s' % node.exc.accept(self) | |
309 return 'raise' | |
310 | |
311 def visit_return(self, node): | |
312 """return an astng.Return node as string""" | |
313 if node.value: | |
314 return 'return %s' % node.value.accept(self) | |
315 else: | |
316 return 'return' | |
317 | |
318 def visit_index(self, node): | |
319 """return a astng.Index node as string""" | |
320 return node.value.accept(self) | |
321 | |
322 def visit_set(self, node): | |
323 """return an astng.Set node as string""" | |
324 return '{%s}' % ', '.join([child.accept(self) for child in node.elts]) | |
325 | |
326 def visit_setcomp(self, node): | |
327 """return an astng.SetComp node as string""" | |
328 return '{%s %s}' % (node.elt.accept(self), ' '.join([n.accept(self) | |
329 for n in node.generators])) | |
330 | |
331 def visit_slice(self, node): | |
332 """return a astng.Slice node as string""" | |
333 lower = node.lower and node.lower.accept(self) or '' | |
334 upper = node.upper and node.upper.accept(self) or '' | |
335 step = node.step and node.step.accept(self) or '' | |
336 if step: | |
337 return '%s:%s:%s' % (lower, upper, step) | |
338 return '%s:%s' % (lower, upper) | |
339 | |
340 def visit_subscript(self, node): | |
341 """return an astng.Subscript node as string""" | |
342 return '%s[%s]' % (node.value.accept(self), node.slice.accept(self)) | |
343 | |
344 def visit_tryexcept(self, node): | |
345 """return an astng.TryExcept node as string""" | |
346 trys = ['try:\n%s' % self._stmt_list( node.body)] | |
347 for handler in node.handlers: | |
348 trys.append(handler.accept(self)) | |
349 if node.orelse: | |
350 trys.append('else:\n%s' % self._stmt_list(node.orelse)) | |
351 return '\n'.join(trys) | |
352 | |
353 def visit_tryfinally(self, node): | |
354 """return an astng.TryFinally node as string""" | |
355 return 'try:\n%s\nfinally:\n%s' % (self._stmt_list( node.body), | |
356 self._stmt_list(node.finalbody)) | |
357 | |
358 def visit_tuple(self, node): | |
359 """return an astng.Tuple node as string""" | |
360 return '(%s)' % ', '.join([child.accept(self) for child in node.elts]) | |
361 | |
362 def visit_unaryop(self, node): | |
363 """return an astng.UnaryOp node as string""" | |
364 if node.op == 'not': | |
365 operator = 'not ' | |
366 else: | |
367 operator = node.op | |
368 return '%s%s' % (operator, node.operand.accept(self)) | |
369 | |
370 def visit_while(self, node): | |
371 """return an astng.While node as string""" | |
372 whiles = 'while %s:\n%s' % (node.test.accept(self), | |
373 self._stmt_list(node.body)) | |
374 if node.orelse: | |
375 whiles = '%s\nelse:\n%s' % (whiles, self._stmt_list(node.orelse)) | |
376 return whiles | |
377 | |
378 def visit_with(self, node): # 'with' without 'as' is possible | |
379 """return an astng.With node as string""" | |
380 as_var = node.vars and " as (%s)" % (node.vars.accept(self)) or "" | |
381 withs = 'with (%s)%s:\n%s' % (node.expr.accept(self), as_var, | |
382 self._stmt_list( node.body)) | |
383 return withs | |
384 | |
385 def visit_yield(self, node): | |
386 """yield an ast.Yield node as string""" | |
387 yi_val = node.value and (" " + node.value.accept(self)) or "" | |
388 return 'yield' + yi_val | |
389 | |
390 | |
391 class AsStringVisitor3k(AsStringVisitor): | |
392 """AsStringVisitor3k overwrites some AsStringVisitor methods""" | |
393 | |
394 def visit_excepthandler(self, node): | |
395 if node.type: | |
396 if node.name: | |
397 excs = 'except %s as %s' % (node.type.accept(self), | |
398 node.name.accept(self)) | |
399 else: | |
400 excs = 'except %s' % node.type.accept(self) | |
401 else: | |
402 excs = 'except' | |
403 return '%s:\n%s' % (excs, self._stmt_list(node.body)) | |
404 | |
405 def visit_nonlocal(self, node): | |
406 """return an astng.Nonlocal node as string""" | |
407 return 'nonlocal %s' % ', '.join(node.names) | |
408 | |
409 def visit_raise(self, node): | |
410 """return an astng.Raise node as string""" | |
411 if node.exc: | |
412 if node.cause: | |
413 return 'raise %s from %s' % (node.exc.accept(self), | |
414 node.cause.accept(self)) | |
415 return 'raise %s' % node.exc.accept(self) | |
416 return 'raise' | |
417 | |
418 def visit_starred(self, node): | |
419 """return Starred node as string""" | |
420 return "*" + node.value.accept(self) | |
421 | |
422 if sys.version_info >= (3, 0): | |
423 AsStringVisitor = AsStringVisitor3k | |
424 | |
425 # this visitor is stateless, thus it can be reused | |
426 as_string = AsStringVisitor() | |
427 | |
OLD | NEW |