6 from cStringIO
import StringIO
8 from compiler
import ast
, parse
, walk
, syntax
9 from compiler
import pyassem
, misc
, future
, symbols
10 from compiler
.consts
import SC_LOCAL
, SC_GLOBAL_IMPLICIT
, SC_GLOBAL_EXPLICT
, \
12 from compiler
.consts
import (CO_VARARGS
, CO_VARKEYWORDS
, CO_NEWLOCALS
,
13 CO_NESTED
, CO_GENERATOR
, CO_FUTURE_DIVISION
,
14 CO_FUTURE_ABSIMPORT
, CO_FUTURE_WITH_STATEMENT
, CO_FUTURE_PRINT_FUNCTION
)
15 from compiler
.pyassem
import TupleArg
17 # XXX The version-specific code can go, since this code only works with 2.x.
18 # Do we have Python 1.x or Python 2.x?
20 VERSION
= sys
.version_info
[0]
21 except AttributeError:
24 callfunc_opcode_info
= {
25 # (Have *args, Have **args) : opcode
26 (0,0) : "CALL_FUNCTION",
27 (1,0) : "CALL_FUNCTION_VAR",
28 (0,1) : "CALL_FUNCTION_KW",
29 (1,1) : "CALL_FUNCTION_VAR_KW",
37 def compileFile(filename
, display
=0):
38 f
= open(filename
, 'U')
41 mod
= Module(buf
, filename
)
47 f
= open(filename
+ "c", "wb")
51 def compile(source
, filename
, mode
, flags
=None, dont_inherit
=None):
52 """Replacement for builtin compile() function"""
53 if flags
is not None or dont_inherit
is not None:
54 raise RuntimeError, "not implemented yet"
57 gen
= Interactive(source
, filename
)
59 gen
= Module(source
, filename
)
61 gen
= Expression(source
, filename
)
63 raise ValueError("compile() 3rd arg must be 'exec' or "
68 class AbstractCompileMode
:
70 mode
= None # defined by subclass
72 def __init__(self
, source
, filename
):
74 self
.filename
= filename
78 tree
= parse(self
.source
, self
.mode
)
79 misc
.set_filename(self
.filename
, tree
)
84 pass # implemented by subclass
89 class Expression(AbstractCompileMode
):
94 tree
= self
._get
_tree
()
95 gen
= ExpressionCodeGenerator(tree
)
96 self
.code
= gen
.getCode()
98 class Interactive(AbstractCompileMode
):
103 tree
= self
._get
_tree
()
104 gen
= InteractiveCodeGenerator(tree
)
105 self
.code
= gen
.getCode()
107 class Module(AbstractCompileMode
):
111 def compile(self
, display
=0):
112 tree
= self
._get
_tree
()
113 gen
= ModuleCodeGenerator(tree
)
116 print pprint
.pprint(tree
)
117 self
.code
= gen
.getCode()
120 f
.write(self
.getPycHeader())
121 marshal
.dump(self
.code
, f
)
123 MAGIC
= imp
.get_magic()
125 def getPycHeader(self
):
126 # compile.c uses marshal to write a long directly, with
127 # calling the interface that would also generate a 1-byte code
128 # to indicate the type of the value. simplest way to get the
129 # same effect is to call marshal and then skip the code.
130 mtime
= os
.path
.getmtime(self
.filename
)
131 mtime
= struct
.pack('<i', mtime
)
132 return self
.MAGIC
+ mtime
134 class LocalNameFinder
:
135 """Find local names in scope"""
136 def __init__(self
, names
=()):
137 self
.names
= misc
.Set()
138 self
.globals = misc
.Set()
142 # XXX list comprehensions and for loops
145 for elt
in self
.globals.elements():
146 if self
.names
.has_elt(elt
):
147 self
.names
.remove(elt
)
150 def visitDict(self
, node
):
153 def visitGlobal(self
, node
):
154 for name
in node
.names
:
155 self
.globals.add(name
)
157 def visitFunction(self
, node
):
158 self
.names
.add(node
.name
)
160 def visitLambda(self
, node
):
163 def visitImport(self
, node
):
164 for name
, alias
in node
.names
:
165 self
.names
.add(alias
or name
)
167 def visitFrom(self
, node
):
168 for name
, alias
in node
.names
:
169 self
.names
.add(alias
or name
)
171 def visitClass(self
, node
):
172 self
.names
.add(node
.name
)
174 def visitAssName(self
, node
):
175 self
.names
.add(node
.name
)
177 def is_constant_false(node
):
178 if isinstance(node
, ast
.Const
):
184 """Defines basic code generator for Python bytecode
186 This class is an abstract base class. Concrete subclasses must
187 define an __init__() that defines self.graph and then calls the
188 __init__() defined in this class.
190 The concrete class must also define the class attributes
191 NameFinder, FunctionGen, and ClassGen. These attributes can be
192 defined in the initClass() method, which is a hook for
193 initializing these methods after all the classes have been
197 optimized
= 0 # is namespace access optimized?
199 class_name
= None # provide default for instance variable
202 if self
.__initialized
is None:
204 self
.__class
__.__initialized
= 1
206 self
.locals = misc
.Stack()
207 self
.setups
= misc
.Stack()
208 self
.last_lineno
= None
209 self
._setupGraphDelegation
()
210 self
._div
_op
= "BINARY_DIVIDE"
212 # XXX set flags based on future features
213 futures
= self
.get_module().futures
214 for feature
in futures
:
215 if feature
== "division":
216 self
.graph
.setFlag(CO_FUTURE_DIVISION
)
217 self
._div
_op
= "BINARY_TRUE_DIVIDE"
218 elif feature
== "absolute_import":
219 self
.graph
.setFlag(CO_FUTURE_ABSIMPORT
)
220 elif feature
== "with_statement":
221 self
.graph
.setFlag(CO_FUTURE_WITH_STATEMENT
)
222 elif feature
== "print_function":
223 self
.graph
.setFlag(CO_FUTURE_PRINT_FUNCTION
)
226 """This method is called once for each class"""
228 def checkClass(self
):
229 """Verify that class is constructed correctly"""
231 assert hasattr(self
, 'graph')
232 assert getattr(self
, 'NameFinder')
233 assert getattr(self
, 'FunctionGen')
234 assert getattr(self
, 'ClassGen')
235 except AssertionError, msg
:
236 intro
= "Bad class construction for %s" % self
.__class
__.__name
__
237 raise AssertionError, intro
239 def _setupGraphDelegation(self
):
240 self
.emit
= self
.graph
.emit
241 self
.newBlock
= self
.graph
.newBlock
242 self
.startBlock
= self
.graph
.startBlock
243 self
.nextBlock
= self
.graph
.nextBlock
244 self
.setDocstring
= self
.graph
.setDocstring
247 """Return a code object"""
248 return self
.graph
.getCode()
250 def mangle(self
, name
):
251 if self
.class_name
is not None:
252 return misc
.mangle(name
, self
.class_name
)
256 def parseSymbols(self
, tree
):
257 s
= symbols
.SymbolVisitor()
261 def get_module(self
):
262 raise RuntimeError, "should be implemented by subclasses"
264 # Next five methods handle name access
266 def isLocalName(self
, name
):
267 return self
.locals.top().has_elt(name
)
269 def storeName(self
, name
):
270 self
._nameOp
('STORE', name
)
272 def loadName(self
, name
):
273 self
._nameOp
('LOAD', name
)
275 def delName(self
, name
):
276 self
._nameOp
('DELETE', name
)
278 def _nameOp(self
, prefix
, name
):
279 name
= self
.mangle(name
)
280 scope
= self
.scope
.check_name(name
)
281 if scope
== SC_LOCAL
:
282 if not self
.optimized
:
283 self
.emit(prefix
+ '_NAME', name
)
285 self
.emit(prefix
+ '_FAST', name
)
286 elif scope
== SC_GLOBAL_EXPLICT
:
287 self
.emit(prefix
+ '_GLOBAL', name
)
288 elif scope
== SC_GLOBAL_IMPLICIT
:
289 if not self
.optimized
:
290 self
.emit(prefix
+ '_NAME', name
)
292 self
.emit(prefix
+ '_GLOBAL', name
)
293 elif scope
== SC_FREE
or scope
== SC_CELL
:
294 self
.emit(prefix
+ '_DEREF', name
)
296 raise RuntimeError, "unsupported scope for var %s: %d" % \
299 def _implicitNameOp(self
, prefix
, name
):
300 """Emit name ops for names generated implicitly by for loops
302 The interpreter generates names that start with a period or
303 dollar sign. The symbol table ignores these names because
304 they aren't present in the program text.
307 self
.emit(prefix
+ '_FAST', name
)
309 self
.emit(prefix
+ '_NAME', name
)
311 # The set_lineno() function and the explicit emit() calls for
312 # SET_LINENO below are only used to generate the line number table.
313 # As of Python 2.3, the interpreter does not have a SET_LINENO
314 # instruction. pyassem treats SET_LINENO opcodes as a special case.
316 def set_lineno(self
, node
, force
=False):
317 """Emit SET_LINENO if necessary.
319 The instruction is considered necessary if the node has a
320 lineno attribute and it is different than the last lineno
323 Returns true if SET_LINENO was emitted.
325 There are no rules for when an AST node should have a lineno
326 attribute. The transformer and AST code need to be reviewed
327 and a consistent policy implemented and documented. Until
328 then, this method works around missing line numbers.
330 lineno
= getattr(node
, 'lineno', None)
331 if lineno
is not None and (lineno
!= self
.last_lineno
333 self
.emit('SET_LINENO', lineno
)
334 self
.last_lineno
= lineno
338 # The first few visitor methods handle nodes that generator new
339 # code objects. They use class attributes to determine what
340 # specialized code generators to use.
342 NameFinder
= LocalNameFinder
346 def visitModule(self
, node
):
347 self
.scopes
= self
.parseSymbols(node
)
348 self
.scope
= self
.scopes
[node
]
349 self
.emit('SET_LINENO', 0)
351 self
.emit('LOAD_CONST', node
.doc
)
352 self
.storeName('__doc__')
353 lnf
= walk(node
.node
, self
.NameFinder(), verbose
=0)
354 self
.locals.push(lnf
.getLocals())
355 self
.visit(node
.node
)
356 self
.emit('LOAD_CONST', None)
357 self
.emit('RETURN_VALUE')
359 def visitExpression(self
, node
):
360 self
.set_lineno(node
)
361 self
.scopes
= self
.parseSymbols(node
)
362 self
.scope
= self
.scopes
[node
]
363 self
.visit(node
.node
)
364 self
.emit('RETURN_VALUE')
366 def visitFunction(self
, node
):
367 self
._visitFuncOrLambda
(node
, isLambda
=0)
369 self
.setDocstring(node
.doc
)
370 self
.storeName(node
.name
)
372 def visitLambda(self
, node
):
373 self
._visitFuncOrLambda
(node
, isLambda
=1)
375 def _visitFuncOrLambda(self
, node
, isLambda
=0):
376 if not isLambda
and node
.decorators
:
377 for decorator
in node
.decorators
.nodes
:
378 self
.visit(decorator
)
379 ndecorators
= len(node
.decorators
.nodes
)
383 gen
= self
.FunctionGen(node
, self
.scopes
, isLambda
,
384 self
.class_name
, self
.get_module())
387 self
.set_lineno(node
)
388 for default
in node
.defaults
:
390 self
._makeClosure
(gen
, len(node
.defaults
))
391 for i
in range(ndecorators
):
392 self
.emit('CALL_FUNCTION', 1)
394 def visitClass(self
, node
):
395 gen
= self
.ClassGen(node
, self
.scopes
,
399 self
.set_lineno(node
)
400 self
.emit('LOAD_CONST', node
.name
)
401 for base
in node
.bases
:
403 self
.emit('BUILD_TUPLE', len(node
.bases
))
404 self
._makeClosure
(gen
, 0)
405 self
.emit('CALL_FUNCTION', 0)
406 self
.emit('BUILD_CLASS')
407 self
.storeName(node
.name
)
409 # The rest are standard visitor methods
411 # The next few implement control-flow statements
413 def visitIf(self
, node
):
414 end
= self
.newBlock()
415 numtests
= len(node
.tests
)
416 for i
in range(numtests
):
417 test
, suite
= node
.tests
[i
]
418 if is_constant_false(test
):
419 # XXX will need to check generator stuff here
421 self
.set_lineno(test
)
423 nextTest
= self
.newBlock()
424 self
.emit('POP_JUMP_IF_FALSE', nextTest
)
427 self
.emit('JUMP_FORWARD', end
)
428 self
.startBlock(nextTest
)
430 self
.visit(node
.else_
)
433 def visitWhile(self
, node
):
434 self
.set_lineno(node
)
436 loop
= self
.newBlock()
437 else_
= self
.newBlock()
439 after
= self
.newBlock()
440 self
.emit('SETUP_LOOP', after
)
443 self
.setups
.push((LOOP
, loop
))
445 self
.set_lineno(node
, force
=True)
446 self
.visit(node
.test
)
447 self
.emit('POP_JUMP_IF_FALSE', else_
or after
)
450 self
.visit(node
.body
)
451 self
.emit('JUMP_ABSOLUTE', loop
)
453 self
.startBlock(else_
) # or just the POPs if not else clause
454 self
.emit('POP_BLOCK')
457 self
.visit(node
.else_
)
458 self
.nextBlock(after
)
460 def visitFor(self
, node
):
461 start
= self
.newBlock()
462 anchor
= self
.newBlock()
463 after
= self
.newBlock()
464 self
.setups
.push((LOOP
, start
))
466 self
.set_lineno(node
)
467 self
.emit('SETUP_LOOP', after
)
468 self
.visit(node
.list)
469 self
.emit('GET_ITER')
471 self
.nextBlock(start
)
472 self
.set_lineno(node
, force
=1)
473 self
.emit('FOR_ITER', anchor
)
474 self
.visit(node
.assign
)
475 self
.visit(node
.body
)
476 self
.emit('JUMP_ABSOLUTE', start
)
477 self
.nextBlock(anchor
)
478 self
.emit('POP_BLOCK')
481 self
.visit(node
.else_
)
482 self
.nextBlock(after
)
484 def visitBreak(self
, node
):
486 raise SyntaxError, "'break' outside loop (%s, %d)" % \
487 (node
.filename
, node
.lineno
)
488 self
.set_lineno(node
)
489 self
.emit('BREAK_LOOP')
491 def visitContinue(self
, node
):
493 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
494 (node
.filename
, node
.lineno
)
495 kind
, block
= self
.setups
.top()
497 self
.set_lineno(node
)
498 self
.emit('JUMP_ABSOLUTE', block
)
500 elif kind
== EXCEPT
or kind
== TRY_FINALLY
:
501 self
.set_lineno(node
)
502 # find the block that starts the loop
503 top
= len(self
.setups
)
506 kind
, loop_block
= self
.setups
[top
]
510 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
511 (node
.filename
, node
.lineno
)
512 self
.emit('CONTINUE_LOOP', loop_block
)
514 elif kind
== END_FINALLY
:
515 msg
= "'continue' not allowed inside 'finally' clause (%s, %d)"
516 raise SyntaxError, msg
% (node
.filename
, node
.lineno
)
518 def visitTest(self
, node
, jump
):
519 end
= self
.newBlock()
520 for child
in node
.nodes
[:-1]:
524 self
.visit(node
.nodes
[-1])
527 def visitAnd(self
, node
):
528 self
.visitTest(node
, 'JUMP_IF_FALSE_OR_POP')
530 def visitOr(self
, node
):
531 self
.visitTest(node
, 'JUMP_IF_TRUE_OR_POP')
533 def visitIfExp(self
, node
):
534 endblock
= self
.newBlock()
535 elseblock
= self
.newBlock()
536 self
.visit(node
.test
)
537 self
.emit('POP_JUMP_IF_FALSE', elseblock
)
538 self
.visit(node
.then
)
539 self
.emit('JUMP_FORWARD', endblock
)
540 self
.nextBlock(elseblock
)
541 self
.visit(node
.else_
)
542 self
.nextBlock(endblock
)
544 def visitCompare(self
, node
):
545 self
.visit(node
.expr
)
546 cleanup
= self
.newBlock()
547 for op
, code
in node
.ops
[:-1]:
550 self
.emit('ROT_THREE')
551 self
.emit('COMPARE_OP', op
)
552 self
.emit('JUMP_IF_FALSE_OR_POP', cleanup
)
554 # now do the last comparison
556 op
, code
= node
.ops
[-1]
558 self
.emit('COMPARE_OP', op
)
559 if len(node
.ops
) > 1:
560 end
= self
.newBlock()
561 self
.emit('JUMP_FORWARD', end
)
562 self
.startBlock(cleanup
)
567 # list comprehensions
568 def visitListComp(self
, node
):
569 self
.set_lineno(node
)
571 self
.emit('BUILD_LIST', 0)
574 for i
, for_
in zip(range(len(node
.quals
)), node
.quals
):
575 start
, anchor
= self
.visit(for_
)
579 cont
= self
.newBlock()
580 self
.visit(if_
, cont
)
581 stack
.insert(0, (start
, cont
, anchor
))
583 self
.visit(node
.expr
)
584 self
.emit('LIST_APPEND', len(node
.quals
) + 1)
586 for start
, cont
, anchor
in stack
:
589 self
.emit('JUMP_ABSOLUTE', start
)
590 self
.startBlock(anchor
)
592 def visitSetComp(self
, node
):
593 self
.set_lineno(node
)
595 self
.emit('BUILD_SET', 0)
598 for i
, for_
in zip(range(len(node
.quals
)), node
.quals
):
599 start
, anchor
= self
.visit(for_
)
603 cont
= self
.newBlock()
604 self
.visit(if_
, cont
)
605 stack
.insert(0, (start
, cont
, anchor
))
607 self
.visit(node
.expr
)
608 self
.emit('SET_ADD', len(node
.quals
) + 1)
610 for start
, cont
, anchor
in stack
:
613 self
.emit('JUMP_ABSOLUTE', start
)
614 self
.startBlock(anchor
)
616 def visitDictComp(self
, node
):
617 self
.set_lineno(node
)
619 self
.emit('BUILD_MAP', 0)
622 for i
, for_
in zip(range(len(node
.quals
)), node
.quals
):
623 start
, anchor
= self
.visit(for_
)
627 cont
= self
.newBlock()
628 self
.visit(if_
, cont
)
629 stack
.insert(0, (start
, cont
, anchor
))
631 self
.visit(node
.value
)
633 self
.emit('MAP_ADD', len(node
.quals
) + 1)
635 for start
, cont
, anchor
in stack
:
638 self
.emit('JUMP_ABSOLUTE', start
)
639 self
.startBlock(anchor
)
641 def visitListCompFor(self
, node
):
642 start
= self
.newBlock()
643 anchor
= self
.newBlock()
645 self
.visit(node
.list)
646 self
.emit('GET_ITER')
647 self
.nextBlock(start
)
648 self
.set_lineno(node
, force
=True)
649 self
.emit('FOR_ITER', anchor
)
651 self
.visit(node
.assign
)
654 def visitListCompIf(self
, node
, branch
):
655 self
.set_lineno(node
, force
=True)
656 self
.visit(node
.test
)
657 self
.emit('POP_JUMP_IF_FALSE', branch
)
660 def _makeClosure(self
, gen
, args
):
661 frees
= gen
.scope
.get_free_vars()
664 self
.emit('LOAD_CLOSURE', name
)
665 self
.emit('BUILD_TUPLE', len(frees
))
666 self
.emit('LOAD_CONST', gen
)
667 self
.emit('MAKE_CLOSURE', args
)
669 self
.emit('LOAD_CONST', gen
)
670 self
.emit('MAKE_FUNCTION', args
)
672 def visitGenExpr(self
, node
):
673 gen
= GenExprCodeGenerator(node
, self
.scopes
, self
.class_name
,
677 self
.set_lineno(node
)
678 self
._makeClosure
(gen
, 0)
679 # precomputation of outmost iterable
680 self
.visit(node
.code
.quals
[0].iter)
681 self
.emit('GET_ITER')
682 self
.emit('CALL_FUNCTION', 1)
684 def visitGenExprInner(self
, node
):
685 self
.set_lineno(node
)
689 for i
, for_
in zip(range(len(node
.quals
)), node
.quals
):
690 start
, anchor
, end
= self
.visit(for_
)
694 cont
= self
.newBlock()
695 self
.visit(if_
, cont
)
696 stack
.insert(0, (start
, cont
, anchor
, end
))
698 self
.visit(node
.expr
)
699 self
.emit('YIELD_VALUE')
702 for start
, cont
, anchor
, end
in stack
:
705 self
.emit('JUMP_ABSOLUTE', start
)
706 self
.startBlock(anchor
)
707 self
.emit('POP_BLOCK')
711 self
.emit('LOAD_CONST', None)
713 def visitGenExprFor(self
, node
):
714 start
= self
.newBlock()
715 anchor
= self
.newBlock()
716 end
= self
.newBlock()
718 self
.setups
.push((LOOP
, start
))
719 self
.emit('SETUP_LOOP', end
)
724 self
.visit(node
.iter)
725 self
.emit('GET_ITER')
727 self
.nextBlock(start
)
728 self
.set_lineno(node
, force
=True)
729 self
.emit('FOR_ITER', anchor
)
731 self
.visit(node
.assign
)
732 return start
, anchor
, end
734 def visitGenExprIf(self
, node
, branch
):
735 self
.set_lineno(node
, force
=True)
736 self
.visit(node
.test
)
737 self
.emit('POP_JUMP_IF_FALSE', branch
)
742 def visitAssert(self
, node
):
743 # XXX would be interesting to implement this via a
744 # transformation of the AST before this stage
746 end
= self
.newBlock()
747 self
.set_lineno(node
)
748 # XXX AssertionError appears to be special case -- it is always
749 # loaded as a global even if there is a local name. I guess this
750 # is a sort of renaming op.
752 self
.visit(node
.test
)
753 self
.emit('POP_JUMP_IF_TRUE', end
)
755 self
.emit('LOAD_GLOBAL', 'AssertionError')
757 self
.visit(node
.fail
)
758 self
.emit('RAISE_VARARGS', 2)
760 self
.emit('RAISE_VARARGS', 1)
763 def visitRaise(self
, node
):
764 self
.set_lineno(node
)
767 self
.visit(node
.expr1
)
770 self
.visit(node
.expr2
)
773 self
.visit(node
.expr3
)
775 self
.emit('RAISE_VARARGS', n
)
777 def visitTryExcept(self
, node
):
778 body
= self
.newBlock()
779 handlers
= self
.newBlock()
780 end
= self
.newBlock()
782 lElse
= self
.newBlock()
785 self
.set_lineno(node
)
786 self
.emit('SETUP_EXCEPT', handlers
)
788 self
.setups
.push((EXCEPT
, body
))
789 self
.visit(node
.body
)
790 self
.emit('POP_BLOCK')
792 self
.emit('JUMP_FORWARD', lElse
)
793 self
.startBlock(handlers
)
795 last
= len(node
.handlers
) - 1
796 for i
in range(len(node
.handlers
)):
797 expr
, target
, body
= node
.handlers
[i
]
798 self
.set_lineno(expr
)
802 self
.emit('COMPARE_OP', 'exception match')
803 next
= self
.newBlock()
804 self
.emit('POP_JUMP_IF_FALSE', next
)
813 self
.emit('JUMP_FORWARD', end
)
818 self
.emit('END_FINALLY')
820 self
.nextBlock(lElse
)
821 self
.visit(node
.else_
)
824 def visitTryFinally(self
, node
):
825 body
= self
.newBlock()
826 final
= self
.newBlock()
827 self
.set_lineno(node
)
828 self
.emit('SETUP_FINALLY', final
)
830 self
.setups
.push((TRY_FINALLY
, body
))
831 self
.visit(node
.body
)
832 self
.emit('POP_BLOCK')
834 self
.emit('LOAD_CONST', None)
835 self
.nextBlock(final
)
836 self
.setups
.push((END_FINALLY
, final
))
837 self
.visit(node
.final
)
838 self
.emit('END_FINALLY')
843 def visitWith(self
, node
):
844 body
= self
.newBlock()
845 final
= self
.newBlock()
846 self
.__with
_count
+= 1
847 valuevar
= "_[%d]" % self
.__with
_count
848 self
.set_lineno(node
)
849 self
.visit(node
.expr
)
851 self
.emit('LOAD_ATTR', '__exit__')
853 self
.emit('LOAD_ATTR', '__enter__')
854 self
.emit('CALL_FUNCTION', 0)
855 if node
.vars is None:
858 self
._implicitNameOp
('STORE', valuevar
)
859 self
.emit('SETUP_FINALLY', final
)
861 self
.setups
.push((TRY_FINALLY
, body
))
862 if node
.vars is not None:
863 self
._implicitNameOp
('LOAD', valuevar
)
864 self
._implicitNameOp
('DELETE', valuevar
)
865 self
.visit(node
.vars)
866 self
.visit(node
.body
)
867 self
.emit('POP_BLOCK')
869 self
.emit('LOAD_CONST', None)
870 self
.nextBlock(final
)
871 self
.setups
.push((END_FINALLY
, final
))
872 self
.emit('WITH_CLEANUP')
873 self
.emit('END_FINALLY')
875 self
.__with
_count
-= 1
879 def visitDiscard(self
, node
):
880 self
.set_lineno(node
)
881 self
.visit(node
.expr
)
884 def visitConst(self
, node
):
885 self
.emit('LOAD_CONST', node
.value
)
887 def visitKeyword(self
, node
):
888 self
.emit('LOAD_CONST', node
.name
)
889 self
.visit(node
.expr
)
891 def visitGlobal(self
, node
):
892 # no code to generate
895 def visitName(self
, node
):
896 self
.set_lineno(node
)
897 self
.loadName(node
.name
)
899 def visitPass(self
, node
):
900 self
.set_lineno(node
)
902 def visitImport(self
, node
):
903 self
.set_lineno(node
)
904 level
= 0 if self
.graph
.checkFlag(CO_FUTURE_ABSIMPORT
) else -1
905 for name
, alias
in node
.names
:
907 self
.emit('LOAD_CONST', level
)
908 self
.emit('LOAD_CONST', None)
909 self
.emit('IMPORT_NAME', name
)
910 mod
= name
.split(".")[0]
912 self
._resolveDots
(name
)
913 self
.storeName(alias
)
917 def visitFrom(self
, node
):
918 self
.set_lineno(node
)
920 if level
== 0 and not self
.graph
.checkFlag(CO_FUTURE_ABSIMPORT
):
922 fromlist
= tuple(name
for (name
, alias
) in node
.names
)
924 self
.emit('LOAD_CONST', level
)
925 self
.emit('LOAD_CONST', fromlist
)
926 self
.emit('IMPORT_NAME', node
.modname
)
927 for name
, alias
in node
.names
:
931 self
.emit('IMPORT_STAR')
932 # There can only be one name w/ from ... import *
933 assert len(node
.names
) == 1
936 self
.emit('IMPORT_FROM', name
)
937 self
._resolveDots
(name
)
938 self
.storeName(alias
or name
)
940 self
.emit('IMPORT_FROM', name
)
943 def _resolveDots(self
, name
):
944 elts
= name
.split(".")
948 self
.emit('LOAD_ATTR', elt
)
950 def visitGetattr(self
, node
):
951 self
.visit(node
.expr
)
952 self
.emit('LOAD_ATTR', self
.mangle(node
.attrname
))
954 # next five implement assignments
956 def visitAssign(self
, node
):
957 self
.set_lineno(node
)
958 self
.visit(node
.expr
)
959 dups
= len(node
.nodes
) - 1
960 for i
in range(len(node
.nodes
)):
964 if isinstance(elt
, ast
.Node
):
967 def visitAssName(self
, node
):
968 if node
.flags
== 'OP_ASSIGN':
969 self
.storeName(node
.name
)
970 elif node
.flags
== 'OP_DELETE':
971 self
.set_lineno(node
)
972 self
.delName(node
.name
)
974 print "oops", node
.flags
976 def visitAssAttr(self
, node
):
977 self
.visit(node
.expr
)
978 if node
.flags
== 'OP_ASSIGN':
979 self
.emit('STORE_ATTR', self
.mangle(node
.attrname
))
980 elif node
.flags
== 'OP_DELETE':
981 self
.emit('DELETE_ATTR', self
.mangle(node
.attrname
))
983 print "warning: unexpected flags:", node
.flags
986 def _visitAssSequence(self
, node
, op
='UNPACK_SEQUENCE'):
987 if findOp(node
) != 'OP_DELETE':
988 self
.emit(op
, len(node
.nodes
))
989 for child
in node
.nodes
:
993 visitAssTuple
= _visitAssSequence
994 visitAssList
= _visitAssSequence
996 def visitAssTuple(self
, node
):
997 self
._visitAssSequence
(node
, 'UNPACK_TUPLE')
999 def visitAssList(self
, node
):
1000 self
._visitAssSequence
(node
, 'UNPACK_LIST')
1002 # augmented assignment
1004 def visitAugAssign(self
, node
):
1005 self
.set_lineno(node
)
1006 aug_node
= wrap_aug(node
.node
)
1007 self
.visit(aug_node
, "load")
1008 self
.visit(node
.expr
)
1009 self
.emit(self
._augmented
_opcode
[node
.op
])
1010 self
.visit(aug_node
, "store")
1012 _augmented_opcode
= {
1013 '+=' : 'INPLACE_ADD',
1014 '-=' : 'INPLACE_SUBTRACT',
1015 '*=' : 'INPLACE_MULTIPLY',
1016 '/=' : 'INPLACE_DIVIDE',
1017 '//=': 'INPLACE_FLOOR_DIVIDE',
1018 '%=' : 'INPLACE_MODULO',
1019 '**=': 'INPLACE_POWER',
1020 '>>=': 'INPLACE_RSHIFT',
1021 '<<=': 'INPLACE_LSHIFT',
1022 '&=' : 'INPLACE_AND',
1023 '^=' : 'INPLACE_XOR',
1024 '|=' : 'INPLACE_OR',
1027 def visitAugName(self
, node
, mode
):
1029 self
.loadName(node
.name
)
1030 elif mode
== "store":
1031 self
.storeName(node
.name
)
1033 def visitAugGetattr(self
, node
, mode
):
1035 self
.visit(node
.expr
)
1036 self
.emit('DUP_TOP')
1037 self
.emit('LOAD_ATTR', self
.mangle(node
.attrname
))
1038 elif mode
== "store":
1039 self
.emit('ROT_TWO')
1040 self
.emit('STORE_ATTR', self
.mangle(node
.attrname
))
1042 def visitAugSlice(self
, node
, mode
):
1044 self
.visitSlice(node
, 1)
1045 elif mode
== "store":
1052 self
.emit('ROT_TWO')
1054 self
.emit('ROT_FOUR')
1056 self
.emit('ROT_THREE')
1057 self
.emit('STORE_SLICE+%d' % slice)
1059 def visitAugSubscript(self
, node
, mode
):
1061 self
.visitSubscript(node
, 1)
1062 elif mode
== "store":
1063 self
.emit('ROT_THREE')
1064 self
.emit('STORE_SUBSCR')
1066 def visitExec(self
, node
):
1067 self
.visit(node
.expr
)
1068 if node
.locals is None:
1069 self
.emit('LOAD_CONST', None)
1071 self
.visit(node
.locals)
1072 if node
.globals is None:
1073 self
.emit('DUP_TOP')
1075 self
.visit(node
.globals)
1076 self
.emit('EXEC_STMT')
1078 def visitCallFunc(self
, node
):
1081 self
.set_lineno(node
)
1082 self
.visit(node
.node
)
1083 for arg
in node
.args
:
1085 if isinstance(arg
, ast
.Keyword
):
1089 if node
.star_args
is not None:
1090 self
.visit(node
.star_args
)
1091 if node
.dstar_args
is not None:
1092 self
.visit(node
.dstar_args
)
1093 have_star
= node
.star_args
is not None
1094 have_dstar
= node
.dstar_args
is not None
1095 opcode
= callfunc_opcode_info
[have_star
, have_dstar
]
1096 self
.emit(opcode
, kw
<< 8 | pos
)
1098 def visitPrint(self
, node
, newline
=0):
1099 self
.set_lineno(node
)
1101 self
.visit(node
.dest
)
1102 for child
in node
.nodes
:
1104 self
.emit('DUP_TOP')
1107 self
.emit('ROT_TWO')
1108 self
.emit('PRINT_ITEM_TO')
1110 self
.emit('PRINT_ITEM')
1111 if node
.dest
and not newline
:
1112 self
.emit('POP_TOP')
1114 def visitPrintnl(self
, node
):
1115 self
.visitPrint(node
, newline
=1)
1117 self
.emit('PRINT_NEWLINE_TO')
1119 self
.emit('PRINT_NEWLINE')
1121 def visitReturn(self
, node
):
1122 self
.set_lineno(node
)
1123 self
.visit(node
.value
)
1124 self
.emit('RETURN_VALUE')
1126 def visitYield(self
, node
):
1127 self
.set_lineno(node
)
1128 self
.visit(node
.value
)
1129 self
.emit('YIELD_VALUE')
1131 # slice and subscript stuff
1133 def visitSlice(self
, node
, aug_flag
=None):
1134 # aug_flag is used by visitAugSlice
1135 self
.visit(node
.expr
)
1138 self
.visit(node
.lower
)
1141 self
.visit(node
.upper
)
1145 self
.emit('DUP_TOP')
1147 self
.emit('DUP_TOPX', 3)
1149 self
.emit('DUP_TOPX', 2)
1150 if node
.flags
== 'OP_APPLY':
1151 self
.emit('SLICE+%d' % slice)
1152 elif node
.flags
== 'OP_ASSIGN':
1153 self
.emit('STORE_SLICE+%d' % slice)
1154 elif node
.flags
== 'OP_DELETE':
1155 self
.emit('DELETE_SLICE+%d' % slice)
1157 print "weird slice", node
.flags
1160 def visitSubscript(self
, node
, aug_flag
=None):
1161 self
.visit(node
.expr
)
1162 for sub
in node
.subs
:
1164 if len(node
.subs
) > 1:
1165 self
.emit('BUILD_TUPLE', len(node
.subs
))
1167 self
.emit('DUP_TOPX', 2)
1168 if node
.flags
== 'OP_APPLY':
1169 self
.emit('BINARY_SUBSCR')
1170 elif node
.flags
== 'OP_ASSIGN':
1171 self
.emit('STORE_SUBSCR')
1172 elif node
.flags
== 'OP_DELETE':
1173 self
.emit('DELETE_SUBSCR')
1177 def binaryOp(self
, node
, op
):
1178 self
.visit(node
.left
)
1179 self
.visit(node
.right
)
1182 def visitAdd(self
, node
):
1183 return self
.binaryOp(node
, 'BINARY_ADD')
1185 def visitSub(self
, node
):
1186 return self
.binaryOp(node
, 'BINARY_SUBTRACT')
1188 def visitMul(self
, node
):
1189 return self
.binaryOp(node
, 'BINARY_MULTIPLY')
1191 def visitDiv(self
, node
):
1192 return self
.binaryOp(node
, self
._div
_op
)
1194 def visitFloorDiv(self
, node
):
1195 return self
.binaryOp(node
, 'BINARY_FLOOR_DIVIDE')
1197 def visitMod(self
, node
):
1198 return self
.binaryOp(node
, 'BINARY_MODULO')
1200 def visitPower(self
, node
):
1201 return self
.binaryOp(node
, 'BINARY_POWER')
1203 def visitLeftShift(self
, node
):
1204 return self
.binaryOp(node
, 'BINARY_LSHIFT')
1206 def visitRightShift(self
, node
):
1207 return self
.binaryOp(node
, 'BINARY_RSHIFT')
1211 def unaryOp(self
, node
, op
):
1212 self
.visit(node
.expr
)
1215 def visitInvert(self
, node
):
1216 return self
.unaryOp(node
, 'UNARY_INVERT')
1218 def visitUnarySub(self
, node
):
1219 return self
.unaryOp(node
, 'UNARY_NEGATIVE')
1221 def visitUnaryAdd(self
, node
):
1222 return self
.unaryOp(node
, 'UNARY_POSITIVE')
1224 def visitUnaryInvert(self
, node
):
1225 return self
.unaryOp(node
, 'UNARY_INVERT')
1227 def visitNot(self
, node
):
1228 return self
.unaryOp(node
, 'UNARY_NOT')
1230 def visitBackquote(self
, node
):
1231 return self
.unaryOp(node
, 'UNARY_CONVERT')
1235 def bitOp(self
, nodes
, op
):
1236 self
.visit(nodes
[0])
1237 for node
in nodes
[1:]:
1241 def visitBitand(self
, node
):
1242 return self
.bitOp(node
.nodes
, 'BINARY_AND')
1244 def visitBitor(self
, node
):
1245 return self
.bitOp(node
.nodes
, 'BINARY_OR')
1247 def visitBitxor(self
, node
):
1248 return self
.bitOp(node
.nodes
, 'BINARY_XOR')
1250 # object constructors
1252 def visitEllipsis(self
, node
):
1253 self
.emit('LOAD_CONST', Ellipsis)
1255 def visitTuple(self
, node
):
1256 self
.set_lineno(node
)
1257 for elt
in node
.nodes
:
1259 self
.emit('BUILD_TUPLE', len(node
.nodes
))
1261 def visitList(self
, node
):
1262 self
.set_lineno(node
)
1263 for elt
in node
.nodes
:
1265 self
.emit('BUILD_LIST', len(node
.nodes
))
1267 def visitSet(self
, node
):
1268 self
.set_lineno(node
)
1269 for elt
in node
.nodes
:
1271 self
.emit('BUILD_SET', len(node
.nodes
))
1273 def visitSliceobj(self
, node
):
1274 for child
in node
.nodes
:
1276 self
.emit('BUILD_SLICE', len(node
.nodes
))
1278 def visitDict(self
, node
):
1279 self
.set_lineno(node
)
1280 self
.emit('BUILD_MAP', 0)
1281 for k
, v
in node
.items
:
1282 self
.emit('DUP_TOP')
1285 self
.emit('ROT_THREE')
1286 self
.emit('STORE_SUBSCR')
1288 class NestedScopeMixin
:
1289 """Defines initClass() for nested scoping (Python 2.2-compatible)"""
1290 def initClass(self
):
1291 self
.__class
__.NameFinder
= LocalNameFinder
1292 self
.__class
__.FunctionGen
= FunctionCodeGenerator
1293 self
.__class
__.ClassGen
= ClassCodeGenerator
1295 class ModuleCodeGenerator(NestedScopeMixin
, CodeGenerator
):
1296 __super_init
= CodeGenerator
.__init
__
1300 def __init__(self
, tree
):
1301 self
.graph
= pyassem
.PyFlowGraph("<module>", tree
.filename
)
1302 self
.futures
= future
.find_futures(tree
)
1306 def get_module(self
):
1309 class ExpressionCodeGenerator(NestedScopeMixin
, CodeGenerator
):
1310 __super_init
= CodeGenerator
.__init
__
1315 def __init__(self
, tree
):
1316 self
.graph
= pyassem
.PyFlowGraph("<expression>", tree
.filename
)
1320 def get_module(self
):
1323 class InteractiveCodeGenerator(NestedScopeMixin
, CodeGenerator
):
1325 __super_init
= CodeGenerator
.__init
__
1330 def __init__(self
, tree
):
1331 self
.graph
= pyassem
.PyFlowGraph("<interactive>", tree
.filename
)
1333 self
.set_lineno(tree
)
1335 self
.emit('RETURN_VALUE')
1337 def get_module(self
):
1340 def visitDiscard(self
, node
):
1341 # XXX Discard means it's an expression. Perhaps this is a bad
1343 self
.visit(node
.expr
)
1344 self
.emit('PRINT_EXPR')
1346 class AbstractFunctionCode
:
1350 def __init__(self
, func
, scopes
, isLambda
, class_name
, mod
):
1351 self
.class_name
= class_name
1354 klass
= FunctionCodeGenerator
1355 name
= "<lambda.%d>" % klass
.lambdaCount
1356 klass
.lambdaCount
= klass
.lambdaCount
+ 1
1360 args
, hasTupleArg
= generateArgList(func
.argnames
)
1361 self
.graph
= pyassem
.PyFlowGraph(name
, func
.filename
, args
,
1363 self
.isLambda
= isLambda
1366 if not isLambda
and func
.doc
:
1367 self
.setDocstring(func
.doc
)
1369 lnf
= walk(func
.code
, self
.NameFinder(args
), verbose
=0)
1370 self
.locals.push(lnf
.getLocals())
1372 self
.graph
.setFlag(CO_VARARGS
)
1374 self
.graph
.setFlag(CO_VARKEYWORDS
)
1375 self
.set_lineno(func
)
1377 self
.generateArgUnpack(func
.argnames
)
1379 def get_module(self
):
1383 self
.graph
.startExitBlock()
1384 if not self
.isLambda
:
1385 self
.emit('LOAD_CONST', None)
1386 self
.emit('RETURN_VALUE')
1388 def generateArgUnpack(self
, args
):
1389 for i
in range(len(args
)):
1391 if isinstance(arg
, tuple):
1392 self
.emit('LOAD_FAST', '.%d' % (i
* 2))
1393 self
.unpackSequence(arg
)
1395 def unpackSequence(self
, tup
):
1397 self
.emit('UNPACK_SEQUENCE', len(tup
))
1399 self
.emit('UNPACK_TUPLE', len(tup
))
1401 if isinstance(elt
, tuple):
1402 self
.unpackSequence(elt
)
1404 self
._nameOp
('STORE', elt
)
1406 unpackTuple
= unpackSequence
1408 class FunctionCodeGenerator(NestedScopeMixin
, AbstractFunctionCode
,
1410 super_init
= CodeGenerator
.__init
__ # call be other init
1413 __super_init
= AbstractFunctionCode
.__init
__
1415 def __init__(self
, func
, scopes
, isLambda
, class_name
, mod
):
1416 self
.scopes
= scopes
1417 self
.scope
= scopes
[func
]
1418 self
.__super
_init
(func
, scopes
, isLambda
, class_name
, mod
)
1419 self
.graph
.setFreeVars(self
.scope
.get_free_vars())
1420 self
.graph
.setCellVars(self
.scope
.get_cell_vars())
1421 if self
.scope
.generator
is not None:
1422 self
.graph
.setFlag(CO_GENERATOR
)
1424 class GenExprCodeGenerator(NestedScopeMixin
, AbstractFunctionCode
,
1426 super_init
= CodeGenerator
.__init
__ # call be other init
1429 __super_init
= AbstractFunctionCode
.__init
__
1431 def __init__(self
, gexp
, scopes
, class_name
, mod
):
1432 self
.scopes
= scopes
1433 self
.scope
= scopes
[gexp
]
1434 self
.__super
_init
(gexp
, scopes
, 1, class_name
, mod
)
1435 self
.graph
.setFreeVars(self
.scope
.get_free_vars())
1436 self
.graph
.setCellVars(self
.scope
.get_cell_vars())
1437 self
.graph
.setFlag(CO_GENERATOR
)
1439 class AbstractClassCode
:
1441 def __init__(self
, klass
, scopes
, module
):
1442 self
.class_name
= klass
.name
1443 self
.module
= module
1444 self
.graph
= pyassem
.PyFlowGraph(klass
.name
, klass
.filename
,
1445 optimized
=0, klass
=1)
1447 lnf
= walk(klass
.code
, self
.NameFinder(), verbose
=0)
1448 self
.locals.push(lnf
.getLocals())
1449 self
.graph
.setFlag(CO_NEWLOCALS
)
1451 self
.setDocstring(klass
.doc
)
1453 def get_module(self
):
1457 self
.graph
.startExitBlock()
1458 self
.emit('LOAD_LOCALS')
1459 self
.emit('RETURN_VALUE')
1461 class ClassCodeGenerator(NestedScopeMixin
, AbstractClassCode
, CodeGenerator
):
1462 super_init
= CodeGenerator
.__init
__
1465 __super_init
= AbstractClassCode
.__init
__
1467 def __init__(self
, klass
, scopes
, module
):
1468 self
.scopes
= scopes
1469 self
.scope
= scopes
[klass
]
1470 self
.__super
_init
(klass
, scopes
, module
)
1471 self
.graph
.setFreeVars(self
.scope
.get_free_vars())
1472 self
.graph
.setCellVars(self
.scope
.get_cell_vars())
1473 self
.set_lineno(klass
)
1474 self
.emit("LOAD_GLOBAL", "__name__")
1475 self
.storeName("__module__")
1477 self
.emit("LOAD_CONST", klass
.doc
)
1478 self
.storeName('__doc__')
1480 def generateArgList(arglist
):
1481 """Generate an arg list marking TupleArgs"""
1485 for i
in range(len(arglist
)):
1487 if isinstance(elt
, str):
1489 elif isinstance(elt
, tuple):
1490 args
.append(TupleArg(i
* 2, elt
))
1491 extra
.extend(misc
.flatten(elt
))
1494 raise ValueError, "unexpect argument type:", elt
1495 return args
+ extra
, count
1498 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
1500 walk(node
, v
, verbose
=0)
1506 def visitAssName(self
, node
):
1508 self
.op
= node
.flags
1509 elif self
.op
!= node
.flags
:
1510 raise ValueError, "mixed ops in stmt"
1511 visitAssAttr
= visitAssName
1512 visitSubscript
= visitAssName
1515 """Base class to support delegation for augmented assignment nodes
1517 To generator code for augmented assignments, we use the following
1518 wrapper classes. In visitAugAssign, the left-hand expression node
1519 is visited twice. The first time the visit uses the normal method
1520 for that node . The second time the visit uses a different method
1521 that generates the appropriate code to perform the assignment.
1522 These delegator classes wrap the original AST nodes in order to
1523 support the variant visit methods.
1525 def __init__(self
, obj
):
1528 def __getattr__(self
, attr
):
1529 return getattr(self
.obj
, attr
)
1531 class AugGetattr(Delegator
):
1534 class AugName(Delegator
):
1537 class AugSlice(Delegator
):
1540 class AugSubscript(Delegator
):
1544 ast
.Getattr
: AugGetattr
,
1546 ast
.Slice
: AugSlice
,
1547 ast
.Subscript
: AugSubscript
,
1551 return wrapper
[node
.__class
__](node
)
1553 if __name__
== "__main__":
1554 for file in sys
.argv
[1:]: