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