~gabriel1984sibiu/agros2d/agros2d

« back to all changes in this revision

Viewing changes to resources/python/logilab/astng/as_string.py

  • Committer: Grevutiu Gabriel
  • Date: 2014-11-15 19:05:36 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20141115190536-1d4q8ez0f8b89ktj
originalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

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