Edgewall Software

source: trunk/genshi/template/astutil.py

Last change on this file was 1250, checked in by hodgestar, 10 years ago

Add support for kwonlyargs and kw_defaults attributes of AST argument nodes.

  • Property svn:eol-style set to native
File size: 26.1 KB
Line 
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2008-2010 Edgewall Software
4# All rights reserved.
5#
6# This software is licensed as described in the file COPYING, which
7# you should have received as part of this distribution. The terms
8# are also available at http://genshi.edgewall.org/wiki/License.
9#
10# This software consists of voluntary contributions made by many
11# individuals. For the exact contribution history, see the revision
12# history and logs, available at http://genshi.edgewall.org/log/.
13
14"""Support classes for generating code from abstract syntax trees."""
15
16try:
17    import _ast
18except ImportError:
19    from genshi.template.ast24 import _ast, parse
20else:
21    def parse(source, mode):
22        return compile(source, '', mode, _ast.PyCF_ONLY_AST)
23
24from genshi.compat import IS_PYTHON2, isstring
25
26__docformat__ = 'restructuredtext en'
27
28
29class ASTCodeGenerator(object):
30    """General purpose base class for AST transformations.
31
32    Every visitor method can be overridden to return an AST node that has been
33    altered or replaced in some way.
34    """
35    def __init__(self, tree):
36        self.lines_info = []
37        self.line_info = None
38        self.code = ''
39        self.line = None
40        self.last = None
41        self.indent = 0
42        self.blame_stack = []
43        self.visit(tree)
44        if self.line.strip():
45            self.code += self.line + '\n'
46            self.lines_info.append(self.line_info)
47        self.line = None
48        self.line_info = None
49
50    def _change_indent(self, delta):
51        self.indent += delta
52
53    def _new_line(self):
54        if self.line is not None:
55            self.code += self.line + '\n'
56            self.lines_info.append(self.line_info)
57        self.line = ' '*4*self.indent
58        if len(self.blame_stack) == 0:
59            self.line_info = []
60            self.last = None
61        else:
62            self.line_info = [(0, self.blame_stack[-1],)]
63            self.last = self.blame_stack[-1]
64
65    def _write(self, s):
66        if len(s) == 0:
67            return
68        if len(self.blame_stack) == 0:
69            if self.last is not None:
70                self.last = None
71                self.line_info.append((len(self.line), self.last))
72        else:
73            if self.last != self.blame_stack[-1]:
74                self.last = self.blame_stack[-1]
75                self.line_info.append((len(self.line), self.last))
76        self.line += s
77
78    def visit(self, node):
79        if node is None:
80            return None
81        if type(node) is tuple:
82            return tuple([self.visit(n) for n in node])
83        try:
84            self.blame_stack.append((node.lineno, node.col_offset,))
85            info = True
86        except AttributeError:
87            info = False
88        visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None)
89        if visitor is None:
90            raise Exception('Unhandled node type %r' % type(node))
91        ret = visitor(node)
92        if info:
93            self.blame_stack.pop()
94        return ret
95
96    def visit_Module(self, node):
97        for n in node.body:
98            self.visit(n)
99    visit_Interactive = visit_Module
100    visit_Suite = visit_Module
101
102    def visit_Expression(self, node):
103        self._new_line()
104        return self.visit(node.body)
105
106    # Python < 3.4
107    # arguments = (expr* args, identifier? vararg,
108    #              identifier? kwarg, expr* defaults)
109    #
110    # Python >= 3.4
111    # arguments = (arg* args, arg? vararg, arg* kwonlyargs, expr* kw_defaults,
112    #              arg? kwarg, expr* defaults)
113    def visit_arguments(self, node):
114        def write_possible_comma():
115            if _first[0]:
116                _first[0] = False
117            else:
118                self._write(', ')
119        _first = [True]
120
121        def write_args(args, defaults):
122            no_default_count = len(args) - len(defaults)
123            for i, arg in enumerate(args):
124                write_possible_comma()
125                self.visit(arg)
126                default_idx = i - no_default_count
127                if default_idx >= 0 and defaults[default_idx] is not None:
128                    self._write('=')
129                    self.visit(defaults[i - no_default_count])
130
131        write_args(node.args, node.defaults)
132        if getattr(node, 'vararg', None):
133            write_possible_comma()
134            self._write('*')
135            if isstring(node.vararg):
136                self._write(node.vararg)
137            else:
138                self.visit(node.vararg)
139        if getattr(node, 'kwonlyargs', None):
140            write_args(node.kwonlyargs, node.kw_defaults)
141        if getattr(node, 'kwarg', None):
142            write_possible_comma()
143            self._write('**')
144            if isstring(node.kwarg):
145                self._write(node.kwarg)
146            else:
147                self.visit(node.kwarg)
148
149    if not IS_PYTHON2:
150        # In Python 3 arguments get a special node
151        def visit_arg(self, node):
152            self._write(node.arg)
153
154    # FunctionDef(identifier name, arguments args,
155    #                           stmt* body, expr* decorator_list)
156    def visit_FunctionDef(self, node):
157        decarators = ()
158        if hasattr(node, 'decorator_list'):
159            decorators = getattr(node, 'decorator_list')
160        else: # different name in earlier Python versions
161            decorators = getattr(node, 'decorators', ())
162        for decorator in decorators:
163            self._new_line()
164            self._write('@')
165            self.visit(decorator)
166        self._new_line()
167        self._write('def ' + node.name + '(')
168        self.visit(node.args)
169        self._write('):')
170        self._change_indent(1)
171        for statement in node.body:
172            self.visit(statement)
173        self._change_indent(-1)
174
175    # ClassDef(identifier name, expr* bases, stmt* body)
176    def visit_ClassDef(self, node):
177        self._new_line()
178        self._write('class ' + node.name)
179        if node.bases:
180            self._write('(')
181            self.visit(node.bases[0])
182            for base in node.bases[1:]:
183                self._write(', ')
184                self.visit(base)
185            self._write(')')
186        self._write(':')
187        self._change_indent(1)
188        for statement in node.body:
189            self.visit(statement)
190        self._change_indent(-1)
191
192    # Return(expr? value)
193    def visit_Return(self, node):
194        self._new_line()
195        self._write('return')
196        if getattr(node, 'value', None):
197            self._write(' ')
198            self.visit(node.value)
199
200    # Delete(expr* targets)
201    def visit_Delete(self, node):
202        self._new_line()
203        self._write('del ')
204        self.visit(node.targets[0])
205        for target in node.targets[1:]:
206            self._write(', ')
207            self.visit(target)
208
209    # Assign(expr* targets, expr value)
210    def visit_Assign(self, node):
211        self._new_line()
212        for target in node.targets:
213            self.visit(target)
214            self._write(' = ')
215        self.visit(node.value)
216
217    # AugAssign(expr target, operator op, expr value)
218    def visit_AugAssign(self, node):
219        self._new_line()
220        self.visit(node.target)
221        self._write(' ' + self.binary_operators[node.op.__class__] + '= ')
222        self.visit(node.value)
223
224    # Print(expr? dest, expr* values, bool nl)
225    def visit_Print(self, node):
226        self._new_line()
227        self._write('print')
228        if getattr(node, 'dest', None):
229            self._write(' >> ')
230            self.visit(node.dest)
231            if getattr(node, 'values', None):
232                self._write(', ')
233        else:
234            self._write(' ')
235        if getattr(node, 'values', None):
236            self.visit(node.values[0])
237            for value in node.values[1:]:
238                self._write(', ')
239                self.visit(value)
240        if not node.nl:
241            self._write(',')
242
243    # For(expr target, expr iter, stmt* body, stmt* orelse)
244    def visit_For(self, node):
245        self._new_line()
246        self._write('for ')
247        self.visit(node.target)
248        self._write(' in ')
249        self.visit(node.iter)
250        self._write(':')
251        self._change_indent(1)
252        for statement in node.body:
253            self.visit(statement)
254        self._change_indent(-1)
255        if getattr(node, 'orelse', None):
256            self._new_line()
257            self._write('else:')
258            self._change_indent(1)
259            for statement in node.orelse:
260                self.visit(statement)
261            self._change_indent(-1)
262
263    # While(expr test, stmt* body, stmt* orelse)
264    def visit_While(self, node):
265        self._new_line()
266        self._write('while ')
267        self.visit(node.test)
268        self._write(':')
269        self._change_indent(1)
270        for statement in node.body:
271            self.visit(statement)
272        self._change_indent(-1)
273        if getattr(node, 'orelse', None):
274            self._new_line()
275            self._write('else:')
276            self._change_indent(1)
277            for statement in node.orelse:
278                self.visit(statement)
279            self._change_indent(-1)
280
281    # If(expr test, stmt* body, stmt* orelse)
282    def visit_If(self, node):
283        self._new_line()
284        self._write('if ')
285        self.visit(node.test)
286        self._write(':')
287        self._change_indent(1)
288        for statement in node.body:
289            self.visit(statement)
290        self._change_indent(-1)
291        if getattr(node, 'orelse', None):
292            self._new_line()
293            self._write('else:')
294            self._change_indent(1)
295            for statement in node.orelse:
296                self.visit(statement)
297            self._change_indent(-1)
298
299    # With(expr context_expr, expr? optional_vars, stmt* body)
300    # With(withitem* items, stmt* body) in Python >= 3.3
301    def visit_With(self, node):
302        self._new_line()
303        self._write('with ')
304        items = getattr(node, 'items', None)
305        first = True
306        if items is None:
307            items = [node]
308        for item in items:
309            if not first:
310                self._write(', ')
311            first = False
312            self.visit(item.context_expr)
313            if getattr(item, 'optional_vars', None):
314                self._write(' as ')
315                self.visit(item.optional_vars)
316        self._write(':')
317        self._change_indent(1)
318        for statement in node.body:
319            self.visit(statement)
320        self._change_indent(-1)
321
322    if IS_PYTHON2:
323        # Raise(expr? type, expr? inst, expr? tback)
324        def visit_Raise(self, node):
325            self._new_line()
326            self._write('raise')
327            if not node.type:
328                return
329            self._write(' ')
330            self.visit(node.type)
331            if not node.inst:
332                return
333            self._write(', ')
334            self.visit(node.inst)
335            if not node.tback:
336                return
337            self._write(', ')
338            self.visit(node.tback)
339    else:
340        # Raise(expr? exc from expr? cause)
341        def visit_Raise(self, node):
342            self._new_line()
343            self._write('raise')
344            if not node.exc:
345                return
346            self._write(' ')
347            self.visit(node.exc)
348            if not node.cause:
349                return
350            self._write(' from ')
351            self.visit(node.cause)
352
353    # TryExcept(stmt* body, excepthandler* handlers, stmt* orelse)
354    def visit_TryExcept(self, node):
355        self._new_line()
356        self._write('try:')
357        self._change_indent(1)
358        for statement in node.body:
359            self.visit(statement)
360        self._change_indent(-1)
361        if getattr(node, 'handlers', None):
362            for handler in node.handlers:
363                self.visit(handler)
364        self._new_line()
365        if getattr(node, 'orelse', None):
366            self._write('else:')
367            self._change_indent(1)
368            for statement in node.orelse:
369                self.visit(statement)
370            self._change_indent(-1)
371
372    # excepthandler = (expr? type, expr? name, stmt* body)
373    def visit_ExceptHandler(self, node):
374        self._new_line()
375        self._write('except')
376        if getattr(node, 'type', None):
377            self._write(' ')
378            self.visit(node.type)
379        if getattr(node, 'name', None):
380            self._write(', ')
381            self.visit(node.name)
382        self._write(':')
383        self._change_indent(1)
384        for statement in node.body:
385            self.visit(statement)
386        self._change_indent(-1)
387    visit_excepthandler = visit_ExceptHandler
388
389    # TryFinally(stmt* body, stmt* finalbody)
390    def visit_TryFinally(self, node):
391        self._new_line()
392        self._write('try:')
393        self._change_indent(1)
394        for statement in node.body:
395            self.visit(statement)
396        self._change_indent(-1)
397
398        if getattr(node, 'finalbody', None):
399            self._new_line()
400            self._write('finally:')
401            self._change_indent(1)
402            for statement in node.finalbody:
403                self.visit(statement)
404            self._change_indent(-1)
405
406    # New in Py3.3
407    # Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody)
408    def visit_Try(self, node):
409        self._new_line()
410        self._write('try:')
411        self._change_indent(1)
412        for statement in node.body:
413            self.visit(statement)
414        self._change_indent(-1)
415        if getattr(node, 'handlers', None):
416            for handler in node.handlers:
417                self.visit(handler)
418        self._new_line()
419        if getattr(node, 'orelse', None):
420            self._write('else:')
421            self._change_indent(1)
422            for statement in node.orelse:
423                self.visit(statement)
424            self._change_indent(-1)
425        if getattr(node, 'finalbody', None):
426            self._new_line()
427            self._write('finally:')
428            self._change_indent(1)
429            for statement in node.finalbody:
430                self.visit(statement)
431            self._change_indent(-1)
432
433    # Assert(expr test, expr? msg)
434    def visit_Assert(self, node):
435        self._new_line()
436        self._write('assert ')
437        self.visit(node.test)
438        if getattr(node, 'msg', None):
439            self._write(', ')
440            self.visit(node.msg)
441
442    def visit_alias(self, node):
443        self._write(node.name)
444        if getattr(node, 'asname', None):
445            self._write(' as ')
446            self._write(node.asname)
447
448    # Import(alias* names)
449    def visit_Import(self, node):
450        self._new_line()
451        self._write('import ')
452        self.visit(node.names[0])
453        for name in node.names[1:]:
454            self._write(', ')
455            self.visit(name)
456
457    # ImportFrom(identifier module, alias* names, int? level)
458    def visit_ImportFrom(self, node):
459        self._new_line()
460        self._write('from ')
461        if node.level:
462            self._write('.' * node.level)
463        self._write(node.module)
464        self._write(' import ')
465        self.visit(node.names[0])
466        for name in node.names[1:]:
467            self._write(', ')
468            self.visit(name)
469
470    # Exec(expr body, expr? globals, expr? locals)
471    def visit_Exec(self, node):
472        self._new_line()
473        self._write('exec ')
474        self.visit(node.body)
475        if not node.globals:
476            return
477        self._write(', ')
478        self.visit(node.globals)
479        if not node.locals:
480            return
481        self._write(', ')
482        self.visit(node.locals)
483
484    # Global(identifier* names)
485    def visit_Global(self, node):
486        self._new_line()
487        self._write('global ')
488        self.visit(node.names[0])
489        for name in node.names[1:]:
490            self._write(', ')
491            self.visit(name)
492
493    # Expr(expr value)
494    def visit_Expr(self, node):
495        self._new_line()
496        self.visit(node.value)
497
498    # Pass
499    def visit_Pass(self, node):
500        self._new_line()
501        self._write('pass')
502
503    # Break
504    def visit_Break(self, node):
505        self._new_line()
506        self._write('break')
507
508    # Continue
509    def visit_Continue(self, node):
510        self._new_line()
511        self._write('continue')
512
513    ### EXPRESSIONS
514    def with_parens(f):
515        def _f(self, node):
516            self._write('(')
517            f(self, node)
518            self._write(')')
519        return _f
520
521    bool_operators = {_ast.And: 'and', _ast.Or: 'or'}
522
523    # BoolOp(boolop op, expr* values)
524    @with_parens
525    def visit_BoolOp(self, node):
526        joiner = ' ' + self.bool_operators[node.op.__class__] + ' '
527        self.visit(node.values[0])
528        for value in node.values[1:]:
529            self._write(joiner)
530            self.visit(value)
531
532    binary_operators = {
533        _ast.Add: '+',
534        _ast.Sub: '-',
535        _ast.Mult: '*',
536        _ast.Div: '/',
537        _ast.Mod: '%',
538        _ast.Pow: '**',
539        _ast.LShift: '<<',
540        _ast.RShift: '>>',
541        _ast.BitOr: '|',
542        _ast.BitXor: '^',
543        _ast.BitAnd: '&',
544        _ast.FloorDiv: '//'
545    }
546
547    # BinOp(expr left, operator op, expr right)
548    @with_parens
549    def visit_BinOp(self, node):
550        self.visit(node.left)
551        self._write(' ' + self.binary_operators[node.op.__class__] + ' ')
552        self.visit(node.right)
553
554    unary_operators = {
555        _ast.Invert: '~',
556        _ast.Not: 'not',
557        _ast.UAdd: '+',
558        _ast.USub: '-',
559    }
560
561    # UnaryOp(unaryop op, expr operand)
562    def visit_UnaryOp(self, node):
563        self._write(self.unary_operators[node.op.__class__] + ' ')
564        self.visit(node.operand)
565
566    # Lambda(arguments args, expr body)
567    @with_parens
568    def visit_Lambda(self, node):
569        self._write('lambda ')
570        self.visit(node.args)
571        self._write(': ')
572        self.visit(node.body)
573
574    # IfExp(expr test, expr body, expr orelse)
575    @with_parens
576    def visit_IfExp(self, node):
577        self.visit(node.body)
578        self._write(' if ')
579        self.visit(node.test)
580        self._write(' else ')
581        self.visit(node.orelse)
582
583    # Dict(expr* keys, expr* values)
584    def visit_Dict(self, node):
585        self._write('{')
586        for key, value in zip(node.keys, node.values):
587            self.visit(key)
588            self._write(': ')
589            self.visit(value)
590            self._write(', ')
591        self._write('}')
592
593    # ListComp(expr elt, comprehension* generators)
594    def visit_ListComp(self, node):
595        self._write('[')
596        self.visit(node.elt)
597        for generator in node.generators:
598            # comprehension = (expr target, expr iter, expr* ifs)
599            self._write(' for ')
600            self.visit(generator.target)
601            self._write(' in ')
602            self.visit(generator.iter)
603            for ifexpr in generator.ifs:
604                self._write(' if ')
605                self.visit(ifexpr)
606        self._write(']')
607
608    # GeneratorExp(expr elt, comprehension* generators)
609    def visit_GeneratorExp(self, node):
610        self._write('(')
611        self.visit(node.elt)
612        for generator in node.generators:
613            # comprehension = (expr target, expr iter, expr* ifs)
614            self._write(' for ')
615            self.visit(generator.target)
616            self._write(' in ')
617            self.visit(generator.iter)
618            for ifexpr in generator.ifs:
619                self._write(' if ')
620                self.visit(ifexpr)
621        self._write(')')
622
623    # Yield(expr? value)
624    def visit_Yield(self, node):
625        self._write('yield')
626        if getattr(node, 'value', None):
627            self._write(' ')
628            self.visit(node.value)
629
630    comparision_operators = {
631        _ast.Eq: '==',
632        _ast.NotEq: '!=',
633        _ast.Lt: '<',
634        _ast.LtE: '<=',
635        _ast.Gt: '>',
636        _ast.GtE: '>=',
637        _ast.Is: 'is',
638        _ast.IsNot: 'is not',
639        _ast.In: 'in',
640        _ast.NotIn: 'not in',
641    }
642
643    # Compare(expr left, cmpop* ops, expr* comparators)
644    @with_parens
645    def visit_Compare(self, node):
646        self.visit(node.left)
647        for op, comparator in zip(node.ops, node.comparators):
648            self._write(' ' + self.comparision_operators[op.__class__] + ' ')
649            self.visit(comparator)
650
651    # Call(expr func, expr* args, keyword* keywords,
652    #                         expr? starargs, expr? kwargs)
653    def visit_Call(self, node):
654        self.visit(node.func)
655        self._write('(')
656        first = True
657        for arg in node.args:
658            if not first:
659                self._write(', ')
660            first = False
661            self.visit(arg)
662
663        for keyword in node.keywords:
664            if not first:
665                self._write(', ')
666            first = False
667            # keyword = (identifier arg, expr value)
668            self._write(keyword.arg)
669            self._write('=')
670            self.visit(keyword.value)
671        if getattr(node, 'starargs', None):
672            if not first:
673                self._write(', ')
674            first = False
675            self._write('*')
676            self.visit(node.starargs)
677
678        if getattr(node, 'kwargs', None):
679            if not first:
680                self._write(', ')
681            first = False
682            self._write('**')
683            self.visit(node.kwargs)
684        self._write(')')
685
686    # Repr(expr value)
687    def visit_Repr(self, node):
688        self._write('`')
689        self.visit(node.value)
690        self._write('`')
691
692    # Num(object n)
693    def visit_Num(self, node):
694        self._write(repr(node.n))
695
696    # Str(string s)
697    def visit_Str(self, node):
698        self._write(repr(node.s))
699
700    if not IS_PYTHON2:
701        # Bytes(bytes s)
702        def visit_Bytes(self, node):
703            self._write(repr(node.s))
704
705    # Attribute(expr value, identifier attr, expr_context ctx)
706    def visit_Attribute(self, node):
707        self.visit(node.value)
708        self._write('.')
709        self._write(node.attr)
710
711    # Subscript(expr value, slice slice, expr_context ctx)
712    def visit_Subscript(self, node):
713        self.visit(node.value)
714        self._write('[')
715        def _process_slice(node):
716            if isinstance(node, _ast.Ellipsis):
717                self._write('...')
718            elif isinstance(node, _ast.Slice):
719                if getattr(node, 'lower', 'None'):
720                    self.visit(node.lower)
721                self._write(':')
722                if getattr(node, 'upper', None):
723                    self.visit(node.upper)
724                if getattr(node, 'step', None):
725                    self._write(':')
726                    self.visit(node.step)
727            elif isinstance(node, _ast.Index):
728                self.visit(node.value)
729            elif isinstance(node, _ast.ExtSlice):
730                self.visit(node.dims[0])
731                for dim in node.dims[1:]:
732                    self._write(', ')
733                    self.visit(dim)
734            else:
735                raise NotImplemented('Slice type not implemented')
736        _process_slice(node.slice)
737        self._write(']')
738
739    # Name(identifier id, expr_context ctx)
740    def visit_Name(self, node):
741        self._write(node.id)
742
743    # NameConstant(singleton value)
744    def visit_NameConstant(self, node):
745        if node.value is None:
746            self._write('None')
747        elif node.value is True:
748            self._write('True')
749        elif node.value is False:
750            self._write('False')
751        else:
752            raise Exception("Unknown NameConstant %r" % (node.value,))
753
754    # List(expr* elts, expr_context ctx)
755    def visit_List(self, node):
756        self._write('[')
757        for elt in node.elts:
758            self.visit(elt)
759            self._write(', ')
760        self._write(']')
761
762    # Tuple(expr *elts, expr_context ctx)
763    def visit_Tuple(self, node):
764        self._write('(')
765        for elt in node.elts:
766            self.visit(elt)
767            self._write(', ')
768        self._write(')')
769
770
771class ASTTransformer(object):
772    """General purpose base class for AST transformations.
773   
774    Every visitor method can be overridden to return an AST node that has been
775    altered or replaced in some way.
776    """
777
778    def visit(self, node):
779        if node is None:
780            return None
781        if type(node) is tuple:
782            return tuple([self.visit(n) for n in node])
783        visitor = getattr(self, 'visit_%s' % node.__class__.__name__, None)
784        if visitor is None:
785            return node
786        return visitor(node)
787
788    def _clone(self, node):
789        clone = node.__class__()
790        for name in getattr(clone, '_attributes', ()):
791            try:
792                setattr(clone, name, getattr(node, name))
793            except AttributeError:
794                pass
795        for name in clone._fields:
796            try:
797                value = getattr(node, name)
798            except AttributeError:
799                pass
800            else:
801                if value is None:
802                    pass
803                elif isinstance(value, list):
804                    value = [self.visit(x) for x in value]
805                elif isinstance(value, tuple):
806                    value = tuple(self.visit(x) for x in value)
807                else: 
808                    value = self.visit(value)
809                setattr(clone, name, value)
810        return clone
811
812    visit_Module = _clone
813    visit_Interactive = _clone
814    visit_Expression = _clone
815    visit_Suite = _clone
816
817    visit_FunctionDef = _clone
818    visit_ClassDef = _clone
819    visit_Return = _clone
820    visit_Delete = _clone
821    visit_Assign = _clone
822    visit_AugAssign = _clone
823    visit_Print = _clone
824    visit_For = _clone
825    visit_While = _clone
826    visit_If = _clone
827    visit_With = _clone
828    visit_Raise = _clone
829    visit_TryExcept = _clone
830    visit_TryFinally = _clone
831    visit_Try = _clone
832    visit_Assert = _clone
833    visit_ExceptHandler = _clone
834
835    visit_Import = _clone
836    visit_ImportFrom = _clone
837    visit_Exec = _clone
838    visit_Global = _clone
839    visit_Expr = _clone
840    # Pass, Break, Continue don't need to be copied
841
842    visit_BoolOp = _clone
843    visit_BinOp = _clone
844    visit_UnaryOp = _clone
845    visit_Lambda = _clone
846    visit_IfExp = _clone
847    visit_Dict = _clone
848    visit_ListComp = _clone
849    visit_GeneratorExp = _clone
850    visit_Yield = _clone
851    visit_Compare = _clone
852    visit_Call = _clone
853    visit_Repr = _clone
854    # Num, Str don't need to be copied
855
856    visit_Attribute = _clone
857    visit_Subscript = _clone
858    visit_Name = _clone
859    visit_NameConstant = _clone
860    visit_List = _clone
861    visit_Tuple = _clone
862
863    visit_comprehension = _clone
864    visit_excepthandler = _clone
865    visit_arguments = _clone
866    visit_keyword = _clone
867    visit_alias = _clone
868
869    visit_Slice = _clone
870    visit_ExtSlice = _clone
871    visit_Index = _clone
872
873    del _clone
Note: See TracBrowser for help on using the repository browser.