Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / devtools / v9 / lib / python2.4 / compiler / pycodegen.py
CommitLineData
920dae64
AT
1import imp
2import os
3import marshal
4import struct
5import sys
6import types
7from cStringIO import StringIO
8
9from compiler import ast, parse, walk, syntax
10from compiler import pyassem, misc, future, symbols
11from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
12from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
13 CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
14from compiler.pyassem import TupleArg
15
16# XXX The version-specific code can go, since this code only works with 2.x.
17# Do we have Python 1.x or Python 2.x?
18try:
19 VERSION = sys.version_info[0]
20except AttributeError:
21 VERSION = 1
22
23callfunc_opcode_info = {
24 # (Have *args, Have **args) : opcode
25 (0,0) : "CALL_FUNCTION",
26 (1,0) : "CALL_FUNCTION_VAR",
27 (0,1) : "CALL_FUNCTION_KW",
28 (1,1) : "CALL_FUNCTION_VAR_KW",
29}
30
31LOOP = 1
32EXCEPT = 2
33TRY_FINALLY = 3
34END_FINALLY = 4
35
36def compileFile(filename, display=0):
37 f = open(filename, 'U')
38 buf = f.read()
39 f.close()
40 mod = Module(buf, filename)
41 try:
42 mod.compile(display)
43 except SyntaxError:
44 raise
45 else:
46 f = open(filename + "c", "wb")
47 mod.dump(f)
48 f.close()
49
50def compile(source, filename, mode, flags=None, dont_inherit=None):
51 """Replacement for builtin compile() function"""
52 if flags is not None or dont_inherit is not None:
53 raise RuntimeError, "not implemented yet"
54
55 if mode == "single":
56 gen = Interactive(source, filename)
57 elif mode == "exec":
58 gen = Module(source, filename)
59 elif mode == "eval":
60 gen = Expression(source, filename)
61 else:
62 raise ValueError("compile() 3rd arg must be 'exec' or "
63 "'eval' or 'single'")
64 gen.compile()
65 return gen.code
66
67class AbstractCompileMode:
68
69 mode = None # defined by subclass
70
71 def __init__(self, source, filename):
72 self.source = source
73 self.filename = filename
74 self.code = None
75
76 def _get_tree(self):
77 tree = parse(self.source, self.mode)
78 misc.set_filename(self.filename, tree)
79 syntax.check(tree)
80 return tree
81
82 def compile(self):
83 pass # implemented by subclass
84
85 def getCode(self):
86 return self.code
87
88class Expression(AbstractCompileMode):
89
90 mode = "eval"
91
92 def compile(self):
93 tree = self._get_tree()
94 gen = ExpressionCodeGenerator(tree)
95 self.code = gen.getCode()
96
97class Interactive(AbstractCompileMode):
98
99 mode = "single"
100
101 def compile(self):
102 tree = self._get_tree()
103 gen = InteractiveCodeGenerator(tree)
104 self.code = gen.getCode()
105
106class Module(AbstractCompileMode):
107
108 mode = "exec"
109
110 def compile(self, display=0):
111 tree = self._get_tree()
112 gen = ModuleCodeGenerator(tree)
113 if display:
114 import pprint
115 print pprint.pprint(tree)
116 self.code = gen.getCode()
117
118 def dump(self, f):
119 f.write(self.getPycHeader())
120 marshal.dump(self.code, f)
121
122 MAGIC = imp.get_magic()
123
124 def getPycHeader(self):
125 # compile.c uses marshal to write a long directly, with
126 # calling the interface that would also generate a 1-byte code
127 # to indicate the type of the value. simplest way to get the
128 # same effect is to call marshal and then skip the code.
129 mtime = os.path.getmtime(self.filename)
130 mtime = struct.pack('<i', mtime)
131 return self.MAGIC + mtime
132
133class LocalNameFinder:
134 """Find local names in scope"""
135 def __init__(self, names=()):
136 self.names = misc.Set()
137 self.globals = misc.Set()
138 for name in names:
139 self.names.add(name)
140
141 # XXX list comprehensions and for loops
142
143 def getLocals(self):
144 for elt in self.globals.elements():
145 if self.names.has_elt(elt):
146 self.names.remove(elt)
147 return self.names
148
149 def visitDict(self, node):
150 pass
151
152 def visitGlobal(self, node):
153 for name in node.names:
154 self.globals.add(name)
155
156 def visitFunction(self, node):
157 self.names.add(node.name)
158
159 def visitLambda(self, node):
160 pass
161
162 def visitImport(self, node):
163 for name, alias in node.names:
164 self.names.add(alias or name)
165
166 def visitFrom(self, node):
167 for name, alias in node.names:
168 self.names.add(alias or name)
169
170 def visitClass(self, node):
171 self.names.add(node.name)
172
173 def visitAssName(self, node):
174 self.names.add(node.name)
175
176def is_constant_false(node):
177 if isinstance(node, ast.Const):
178 if not node.value:
179 return 1
180 return 0
181
182class CodeGenerator:
183 """Defines basic code generator for Python bytecode
184
185 This class is an abstract base class. Concrete subclasses must
186 define an __init__() that defines self.graph and then calls the
187 __init__() defined in this class.
188
189 The concrete class must also define the class attributes
190 NameFinder, FunctionGen, and ClassGen. These attributes can be
191 defined in the initClass() method, which is a hook for
192 initializing these methods after all the classes have been
193 defined.
194 """
195
196 optimized = 0 # is namespace access optimized?
197 __initialized = None
198 class_name = None # provide default for instance variable
199
200 def __init__(self):
201 if self.__initialized is None:
202 self.initClass()
203 self.__class__.__initialized = 1
204 self.checkClass()
205 self.locals = misc.Stack()
206 self.setups = misc.Stack()
207 self.last_lineno = None
208 self._setupGraphDelegation()
209 self._div_op = "BINARY_DIVIDE"
210
211 # XXX set flags based on future features
212 futures = self.get_module().futures
213 for feature in futures:
214 if feature == "division":
215 self.graph.setFlag(CO_FUTURE_DIVISION)
216 self._div_op = "BINARY_TRUE_DIVIDE"
217 elif feature == "generators":
218 self.graph.setFlag(CO_GENERATOR_ALLOWED)
219
220 def initClass(self):
221 """This method is called once for each class"""
222
223 def checkClass(self):
224 """Verify that class is constructed correctly"""
225 try:
226 assert hasattr(self, 'graph')
227 assert getattr(self, 'NameFinder')
228 assert getattr(self, 'FunctionGen')
229 assert getattr(self, 'ClassGen')
230 except AssertionError, msg:
231 intro = "Bad class construction for %s" % self.__class__.__name__
232 raise AssertionError, intro
233
234 def _setupGraphDelegation(self):
235 self.emit = self.graph.emit
236 self.newBlock = self.graph.newBlock
237 self.startBlock = self.graph.startBlock
238 self.nextBlock = self.graph.nextBlock
239 self.setDocstring = self.graph.setDocstring
240
241 def getCode(self):
242 """Return a code object"""
243 return self.graph.getCode()
244
245 def mangle(self, name):
246 if self.class_name is not None:
247 return misc.mangle(name, self.class_name)
248 else:
249 return name
250
251 def parseSymbols(self, tree):
252 s = symbols.SymbolVisitor()
253 walk(tree, s)
254 return s.scopes
255
256 def get_module(self):
257 raise RuntimeError, "should be implemented by subclasses"
258
259 # Next five methods handle name access
260
261 def isLocalName(self, name):
262 return self.locals.top().has_elt(name)
263
264 def storeName(self, name):
265 self._nameOp('STORE', name)
266
267 def loadName(self, name):
268 self._nameOp('LOAD', name)
269
270 def delName(self, name):
271 self._nameOp('DELETE', name)
272
273 def _nameOp(self, prefix, name):
274 name = self.mangle(name)
275 scope = self.scope.check_name(name)
276 if scope == SC_LOCAL:
277 if not self.optimized:
278 self.emit(prefix + '_NAME', name)
279 else:
280 self.emit(prefix + '_FAST', name)
281 elif scope == SC_GLOBAL:
282 if not self.optimized:
283 self.emit(prefix + '_NAME', name)
284 else:
285 self.emit(prefix + '_GLOBAL', name)
286 elif scope == SC_FREE or scope == SC_CELL:
287 self.emit(prefix + '_DEREF', name)
288 else:
289 raise RuntimeError, "unsupported scope for var %s: %d" % \
290 (name, scope)
291
292 def _implicitNameOp(self, prefix, name):
293 """Emit name ops for names generated implicitly by for loops
294
295 The interpreter generates names that start with a period or
296 dollar sign. The symbol table ignores these names because
297 they aren't present in the program text.
298 """
299 if self.optimized:
300 self.emit(prefix + '_FAST', name)
301 else:
302 self.emit(prefix + '_NAME', name)
303
304 # The set_lineno() function and the explicit emit() calls for
305 # SET_LINENO below are only used to generate the line number table.
306 # As of Python 2.3, the interpreter does not have a SET_LINENO
307 # instruction. pyassem treats SET_LINENO opcodes as a special case.
308
309 def set_lineno(self, node, force=False):
310 """Emit SET_LINENO if necessary.
311
312 The instruction is considered necessary if the node has a
313 lineno attribute and it is different than the last lineno
314 emitted.
315
316 Returns true if SET_LINENO was emitted.
317
318 There are no rules for when an AST node should have a lineno
319 attribute. The transformer and AST code need to be reviewed
320 and a consistent policy implemented and documented. Until
321 then, this method works around missing line numbers.
322 """
323 lineno = getattr(node, 'lineno', None)
324 if lineno is not None and (lineno != self.last_lineno
325 or force):
326 self.emit('SET_LINENO', lineno)
327 self.last_lineno = lineno
328 return True
329 return False
330
331 # The first few visitor methods handle nodes that generator new
332 # code objects. They use class attributes to determine what
333 # specialized code generators to use.
334
335 NameFinder = LocalNameFinder
336 FunctionGen = None
337 ClassGen = None
338
339 def visitModule(self, node):
340 self.scopes = self.parseSymbols(node)
341 self.scope = self.scopes[node]
342 self.emit('SET_LINENO', 0)
343 if node.doc:
344 self.emit('LOAD_CONST', node.doc)
345 self.storeName('__doc__')
346 lnf = walk(node.node, self.NameFinder(), verbose=0)
347 self.locals.push(lnf.getLocals())
348 self.visit(node.node)
349 self.emit('LOAD_CONST', None)
350 self.emit('RETURN_VALUE')
351
352 def visitExpression(self, node):
353 self.set_lineno(node)
354 self.scopes = self.parseSymbols(node)
355 self.scope = self.scopes[node]
356 self.visit(node.node)
357 self.emit('RETURN_VALUE')
358
359 def visitFunction(self, node):
360 self._visitFuncOrLambda(node, isLambda=0)
361 if node.doc:
362 self.setDocstring(node.doc)
363 self.storeName(node.name)
364
365 def visitLambda(self, node):
366 self._visitFuncOrLambda(node, isLambda=1)
367
368 def _visitFuncOrLambda(self, node, isLambda=0):
369 if not isLambda and node.decorators:
370 for decorator in node.decorators.nodes:
371 self.visit(decorator)
372 ndecorators = len(node.decorators.nodes)
373 else:
374 ndecorators = 0
375
376 gen = self.FunctionGen(node, self.scopes, isLambda,
377 self.class_name, self.get_module())
378 walk(node.code, gen)
379 gen.finish()
380 self.set_lineno(node)
381 for default in node.defaults:
382 self.visit(default)
383 frees = gen.scope.get_free_vars()
384 if frees:
385 for name in frees:
386 self.emit('LOAD_CLOSURE', name)
387 self.emit('LOAD_CONST', gen)
388 self.emit('MAKE_CLOSURE', len(node.defaults))
389 else:
390 self.emit('LOAD_CONST', gen)
391 self.emit('MAKE_FUNCTION', len(node.defaults))
392
393 for i in range(ndecorators):
394 self.emit('CALL_FUNCTION', 1)
395
396 def visitClass(self, node):
397 gen = self.ClassGen(node, self.scopes,
398 self.get_module())
399 walk(node.code, gen)
400 gen.finish()
401 self.set_lineno(node)
402 self.emit('LOAD_CONST', node.name)
403 for base in node.bases:
404 self.visit(base)
405 self.emit('BUILD_TUPLE', len(node.bases))
406 frees = gen.scope.get_free_vars()
407 for name in frees:
408 self.emit('LOAD_CLOSURE', name)
409 self.emit('LOAD_CONST', gen)
410 if frees:
411 self.emit('MAKE_CLOSURE', 0)
412 else:
413 self.emit('MAKE_FUNCTION', 0)
414 self.emit('CALL_FUNCTION', 0)
415 self.emit('BUILD_CLASS')
416 self.storeName(node.name)
417
418 # The rest are standard visitor methods
419
420 # The next few implement control-flow statements
421
422 def visitIf(self, node):
423 end = self.newBlock()
424 numtests = len(node.tests)
425 for i in range(numtests):
426 test, suite = node.tests[i]
427 if is_constant_false(test):
428 # XXX will need to check generator stuff here
429 continue
430 self.set_lineno(test)
431 self.visit(test)
432 nextTest = self.newBlock()
433 self.emit('JUMP_IF_FALSE', nextTest)
434 self.nextBlock()
435 self.emit('POP_TOP')
436 self.visit(suite)
437 self.emit('JUMP_FORWARD', end)
438 self.startBlock(nextTest)
439 self.emit('POP_TOP')
440 if node.else_:
441 self.visit(node.else_)
442 self.nextBlock(end)
443
444 def visitWhile(self, node):
445 self.set_lineno(node)
446
447 loop = self.newBlock()
448 else_ = self.newBlock()
449
450 after = self.newBlock()
451 self.emit('SETUP_LOOP', after)
452
453 self.nextBlock(loop)
454 self.setups.push((LOOP, loop))
455
456 self.set_lineno(node, force=True)
457 self.visit(node.test)
458 self.emit('JUMP_IF_FALSE', else_ or after)
459
460 self.nextBlock()
461 self.emit('POP_TOP')
462 self.visit(node.body)
463 self.emit('JUMP_ABSOLUTE', loop)
464
465 self.startBlock(else_) # or just the POPs if not else clause
466 self.emit('POP_TOP')
467 self.emit('POP_BLOCK')
468 self.setups.pop()
469 if node.else_:
470 self.visit(node.else_)
471 self.nextBlock(after)
472
473 def visitFor(self, node):
474 start = self.newBlock()
475 anchor = self.newBlock()
476 after = self.newBlock()
477 self.setups.push((LOOP, start))
478
479 self.set_lineno(node)
480 self.emit('SETUP_LOOP', after)
481 self.visit(node.list)
482 self.emit('GET_ITER')
483
484 self.nextBlock(start)
485 self.set_lineno(node, force=1)
486 self.emit('FOR_ITER', anchor)
487 self.visit(node.assign)
488 self.visit(node.body)
489 self.emit('JUMP_ABSOLUTE', start)
490 self.nextBlock(anchor)
491 self.emit('POP_BLOCK')
492 self.setups.pop()
493 if node.else_:
494 self.visit(node.else_)
495 self.nextBlock(after)
496
497 def visitBreak(self, node):
498 if not self.setups:
499 raise SyntaxError, "'break' outside loop (%s, %d)" % \
500 (node.filename, node.lineno)
501 self.set_lineno(node)
502 self.emit('BREAK_LOOP')
503
504 def visitContinue(self, node):
505 if not self.setups:
506 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
507 (node.filename, node.lineno)
508 kind, block = self.setups.top()
509 if kind == LOOP:
510 self.set_lineno(node)
511 self.emit('JUMP_ABSOLUTE', block)
512 self.nextBlock()
513 elif kind == EXCEPT or kind == TRY_FINALLY:
514 self.set_lineno(node)
515 # find the block that starts the loop
516 top = len(self.setups)
517 while top > 0:
518 top = top - 1
519 kind, loop_block = self.setups[top]
520 if kind == LOOP:
521 break
522 if kind != LOOP:
523 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
524 (node.filename, node.lineno)
525 self.emit('CONTINUE_LOOP', loop_block)
526 self.nextBlock()
527 elif kind == END_FINALLY:
528 msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
529 raise SyntaxError, msg % (node.filename, node.lineno)
530
531 def visitTest(self, node, jump):
532 end = self.newBlock()
533 for child in node.nodes[:-1]:
534 self.visit(child)
535 self.emit(jump, end)
536 self.nextBlock()
537 self.emit('POP_TOP')
538 self.visit(node.nodes[-1])
539 self.nextBlock(end)
540
541 def visitAnd(self, node):
542 self.visitTest(node, 'JUMP_IF_FALSE')
543
544 def visitOr(self, node):
545 self.visitTest(node, 'JUMP_IF_TRUE')
546
547 def visitCompare(self, node):
548 self.visit(node.expr)
549 cleanup = self.newBlock()
550 for op, code in node.ops[:-1]:
551 self.visit(code)
552 self.emit('DUP_TOP')
553 self.emit('ROT_THREE')
554 self.emit('COMPARE_OP', op)
555 self.emit('JUMP_IF_FALSE', cleanup)
556 self.nextBlock()
557 self.emit('POP_TOP')
558 # now do the last comparison
559 if node.ops:
560 op, code = node.ops[-1]
561 self.visit(code)
562 self.emit('COMPARE_OP', op)
563 if len(node.ops) > 1:
564 end = self.newBlock()
565 self.emit('JUMP_FORWARD', end)
566 self.startBlock(cleanup)
567 self.emit('ROT_TWO')
568 self.emit('POP_TOP')
569 self.nextBlock(end)
570
571 # list comprehensions
572 __list_count = 0
573
574 def visitListComp(self, node):
575 self.set_lineno(node)
576 # setup list
577 append = "$append%d" % self.__list_count
578 self.__list_count = self.__list_count + 1
579 self.emit('BUILD_LIST', 0)
580 self.emit('DUP_TOP')
581 self.emit('LOAD_ATTR', 'append')
582 self._implicitNameOp('STORE', append)
583
584 stack = []
585 for i, for_ in zip(range(len(node.quals)), node.quals):
586 start, anchor = self.visit(for_)
587 cont = None
588 for if_ in for_.ifs:
589 if cont is None:
590 cont = self.newBlock()
591 self.visit(if_, cont)
592 stack.insert(0, (start, cont, anchor))
593
594 self._implicitNameOp('LOAD', append)
595 self.visit(node.expr)
596 self.emit('CALL_FUNCTION', 1)
597 self.emit('POP_TOP')
598
599 for start, cont, anchor in stack:
600 if cont:
601 skip_one = self.newBlock()
602 self.emit('JUMP_FORWARD', skip_one)
603 self.startBlock(cont)
604 self.emit('POP_TOP')
605 self.nextBlock(skip_one)
606 self.emit('JUMP_ABSOLUTE', start)
607 self.startBlock(anchor)
608 self._implicitNameOp('DELETE', append)
609
610 self.__list_count = self.__list_count - 1
611
612 def visitListCompFor(self, node):
613 start = self.newBlock()
614 anchor = self.newBlock()
615
616 self.visit(node.list)
617 self.emit('GET_ITER')
618 self.nextBlock(start)
619 self.set_lineno(node, force=True)
620 self.emit('FOR_ITER', anchor)
621 self.nextBlock()
622 self.visit(node.assign)
623 return start, anchor
624
625 def visitListCompIf(self, node, branch):
626 self.set_lineno(node, force=True)
627 self.visit(node.test)
628 self.emit('JUMP_IF_FALSE', branch)
629 self.newBlock()
630 self.emit('POP_TOP')
631
632 def visitGenExpr(self, node):
633 gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
634 self.get_module())
635 walk(node.code, gen)
636 gen.finish()
637 self.set_lineno(node)
638 frees = gen.scope.get_free_vars()
639 if frees:
640 for name in frees:
641 self.emit('LOAD_CLOSURE', name)
642 self.emit('LOAD_CONST', gen)
643 self.emit('MAKE_CLOSURE', 0)
644 else:
645 self.emit('LOAD_CONST', gen)
646 self.emit('MAKE_FUNCTION', 0)
647
648 # precomputation of outmost iterable
649 self.visit(node.code.quals[0].iter)
650 self.emit('GET_ITER')
651 self.emit('CALL_FUNCTION', 1)
652
653 def visitGenExprInner(self, node):
654 self.set_lineno(node)
655 # setup list
656
657 stack = []
658 for i, for_ in zip(range(len(node.quals)), node.quals):
659 start, anchor = self.visit(for_)
660 cont = None
661 for if_ in for_.ifs:
662 if cont is None:
663 cont = self.newBlock()
664 self.visit(if_, cont)
665 stack.insert(0, (start, cont, anchor))
666
667 self.visit(node.expr)
668 self.emit('YIELD_VALUE')
669
670 for start, cont, anchor in stack:
671 if cont:
672 skip_one = self.newBlock()
673 self.emit('JUMP_FORWARD', skip_one)
674 self.startBlock(cont)
675 self.emit('POP_TOP')
676 self.nextBlock(skip_one)
677 self.emit('JUMP_ABSOLUTE', start)
678 self.startBlock(anchor)
679 self.emit('LOAD_CONST', None)
680
681 def visitGenExprFor(self, node):
682 start = self.newBlock()
683 anchor = self.newBlock()
684
685 if node.is_outmost:
686 self.loadName('[outmost-iterable]')
687 else:
688 self.visit(node.iter)
689 self.emit('GET_ITER')
690
691 self.nextBlock(start)
692 self.set_lineno(node, force=True)
693 self.emit('FOR_ITER', anchor)
694 self.nextBlock()
695 self.visit(node.assign)
696 return start, anchor
697
698 def visitGenExprIf(self, node, branch):
699 self.set_lineno(node, force=True)
700 self.visit(node.test)
701 self.emit('JUMP_IF_FALSE', branch)
702 self.newBlock()
703 self.emit('POP_TOP')
704
705 # exception related
706
707 def visitAssert(self, node):
708 # XXX would be interesting to implement this via a
709 # transformation of the AST before this stage
710 if __debug__:
711 end = self.newBlock()
712 self.set_lineno(node)
713 # XXX AssertionError appears to be special case -- it is always
714 # loaded as a global even if there is a local name. I guess this
715 # is a sort of renaming op.
716 self.nextBlock()
717 self.visit(node.test)
718 self.emit('JUMP_IF_TRUE', end)
719 self.nextBlock()
720 self.emit('POP_TOP')
721 self.emit('LOAD_GLOBAL', 'AssertionError')
722 if node.fail:
723 self.visit(node.fail)
724 self.emit('RAISE_VARARGS', 2)
725 else:
726 self.emit('RAISE_VARARGS', 1)
727 self.nextBlock(end)
728 self.emit('POP_TOP')
729
730 def visitRaise(self, node):
731 self.set_lineno(node)
732 n = 0
733 if node.expr1:
734 self.visit(node.expr1)
735 n = n + 1
736 if node.expr2:
737 self.visit(node.expr2)
738 n = n + 1
739 if node.expr3:
740 self.visit(node.expr3)
741 n = n + 1
742 self.emit('RAISE_VARARGS', n)
743
744 def visitTryExcept(self, node):
745 body = self.newBlock()
746 handlers = self.newBlock()
747 end = self.newBlock()
748 if node.else_:
749 lElse = self.newBlock()
750 else:
751 lElse = end
752 self.set_lineno(node)
753 self.emit('SETUP_EXCEPT', handlers)
754 self.nextBlock(body)
755 self.setups.push((EXCEPT, body))
756 self.visit(node.body)
757 self.emit('POP_BLOCK')
758 self.setups.pop()
759 self.emit('JUMP_FORWARD', lElse)
760 self.startBlock(handlers)
761
762 last = len(node.handlers) - 1
763 for i in range(len(node.handlers)):
764 expr, target, body = node.handlers[i]
765 self.set_lineno(expr)
766 if expr:
767 self.emit('DUP_TOP')
768 self.visit(expr)
769 self.emit('COMPARE_OP', 'exception match')
770 next = self.newBlock()
771 self.emit('JUMP_IF_FALSE', next)
772 self.nextBlock()
773 self.emit('POP_TOP')
774 self.emit('POP_TOP')
775 if target:
776 self.visit(target)
777 else:
778 self.emit('POP_TOP')
779 self.emit('POP_TOP')
780 self.visit(body)
781 self.emit('JUMP_FORWARD', end)
782 if expr:
783 self.nextBlock(next)
784 else:
785 self.nextBlock()
786 if expr: # XXX
787 self.emit('POP_TOP')
788 self.emit('END_FINALLY')
789 if node.else_:
790 self.nextBlock(lElse)
791 self.visit(node.else_)
792 self.nextBlock(end)
793
794 def visitTryFinally(self, node):
795 body = self.newBlock()
796 final = self.newBlock()
797 self.set_lineno(node)
798 self.emit('SETUP_FINALLY', final)
799 self.nextBlock(body)
800 self.setups.push((TRY_FINALLY, body))
801 self.visit(node.body)
802 self.emit('POP_BLOCK')
803 self.setups.pop()
804 self.emit('LOAD_CONST', None)
805 self.nextBlock(final)
806 self.setups.push((END_FINALLY, final))
807 self.visit(node.final)
808 self.emit('END_FINALLY')
809 self.setups.pop()
810
811 # misc
812
813 def visitDiscard(self, node):
814 self.set_lineno(node)
815 self.visit(node.expr)
816 self.emit('POP_TOP')
817
818 def visitConst(self, node):
819 self.emit('LOAD_CONST', node.value)
820
821 def visitKeyword(self, node):
822 self.emit('LOAD_CONST', node.name)
823 self.visit(node.expr)
824
825 def visitGlobal(self, node):
826 # no code to generate
827 pass
828
829 def visitName(self, node):
830 self.set_lineno(node)
831 self.loadName(node.name)
832
833 def visitPass(self, node):
834 self.set_lineno(node)
835
836 def visitImport(self, node):
837 self.set_lineno(node)
838 for name, alias in node.names:
839 if VERSION > 1:
840 self.emit('LOAD_CONST', None)
841 self.emit('IMPORT_NAME', name)
842 mod = name.split(".")[0]
843 if alias:
844 self._resolveDots(name)
845 self.storeName(alias)
846 else:
847 self.storeName(mod)
848
849 def visitFrom(self, node):
850 self.set_lineno(node)
851 fromlist = map(lambda (name, alias): name, node.names)
852 if VERSION > 1:
853 self.emit('LOAD_CONST', tuple(fromlist))
854 self.emit('IMPORT_NAME', node.modname)
855 for name, alias in node.names:
856 if VERSION > 1:
857 if name == '*':
858 self.namespace = 0
859 self.emit('IMPORT_STAR')
860 # There can only be one name w/ from ... import *
861 assert len(node.names) == 1
862 return
863 else:
864 self.emit('IMPORT_FROM', name)
865 self._resolveDots(name)
866 self.storeName(alias or name)
867 else:
868 self.emit('IMPORT_FROM', name)
869 self.emit('POP_TOP')
870
871 def _resolveDots(self, name):
872 elts = name.split(".")
873 if len(elts) == 1:
874 return
875 for elt in elts[1:]:
876 self.emit('LOAD_ATTR', elt)
877
878 def visitGetattr(self, node):
879 self.visit(node.expr)
880 self.emit('LOAD_ATTR', self.mangle(node.attrname))
881
882 # next five implement assignments
883
884 def visitAssign(self, node):
885 self.set_lineno(node)
886 self.visit(node.expr)
887 dups = len(node.nodes) - 1
888 for i in range(len(node.nodes)):
889 elt = node.nodes[i]
890 if i < dups:
891 self.emit('DUP_TOP')
892 if isinstance(elt, ast.Node):
893 self.visit(elt)
894
895 def visitAssName(self, node):
896 if node.flags == 'OP_ASSIGN':
897 self.storeName(node.name)
898 elif node.flags == 'OP_DELETE':
899 self.set_lineno(node)
900 self.delName(node.name)
901 else:
902 print "oops", node.flags
903
904 def visitAssAttr(self, node):
905 self.visit(node.expr)
906 if node.flags == 'OP_ASSIGN':
907 self.emit('STORE_ATTR', self.mangle(node.attrname))
908 elif node.flags == 'OP_DELETE':
909 self.emit('DELETE_ATTR', self.mangle(node.attrname))
910 else:
911 print "warning: unexpected flags:", node.flags
912 print node
913
914 def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
915 if findOp(node) != 'OP_DELETE':
916 self.emit(op, len(node.nodes))
917 for child in node.nodes:
918 self.visit(child)
919
920 if VERSION > 1:
921 visitAssTuple = _visitAssSequence
922 visitAssList = _visitAssSequence
923 else:
924 def visitAssTuple(self, node):
925 self._visitAssSequence(node, 'UNPACK_TUPLE')
926
927 def visitAssList(self, node):
928 self._visitAssSequence(node, 'UNPACK_LIST')
929
930 # augmented assignment
931
932 def visitAugAssign(self, node):
933 self.set_lineno(node)
934 aug_node = wrap_aug(node.node)
935 self.visit(aug_node, "load")
936 self.visit(node.expr)
937 self.emit(self._augmented_opcode[node.op])
938 self.visit(aug_node, "store")
939
940 _augmented_opcode = {
941 '+=' : 'INPLACE_ADD',
942 '-=' : 'INPLACE_SUBTRACT',
943 '*=' : 'INPLACE_MULTIPLY',
944 '/=' : 'INPLACE_DIVIDE',
945 '//=': 'INPLACE_FLOOR_DIVIDE',
946 '%=' : 'INPLACE_MODULO',
947 '**=': 'INPLACE_POWER',
948 '>>=': 'INPLACE_RSHIFT',
949 '<<=': 'INPLACE_LSHIFT',
950 '&=' : 'INPLACE_AND',
951 '^=' : 'INPLACE_XOR',
952 '|=' : 'INPLACE_OR',
953 }
954
955 def visitAugName(self, node, mode):
956 if mode == "load":
957 self.loadName(node.name)
958 elif mode == "store":
959 self.storeName(node.name)
960
961 def visitAugGetattr(self, node, mode):
962 if mode == "load":
963 self.visit(node.expr)
964 self.emit('DUP_TOP')
965 self.emit('LOAD_ATTR', self.mangle(node.attrname))
966 elif mode == "store":
967 self.emit('ROT_TWO')
968 self.emit('STORE_ATTR', self.mangle(node.attrname))
969
970 def visitAugSlice(self, node, mode):
971 if mode == "load":
972 self.visitSlice(node, 1)
973 elif mode == "store":
974 slice = 0
975 if node.lower:
976 slice = slice | 1
977 if node.upper:
978 slice = slice | 2
979 if slice == 0:
980 self.emit('ROT_TWO')
981 elif slice == 3:
982 self.emit('ROT_FOUR')
983 else:
984 self.emit('ROT_THREE')
985 self.emit('STORE_SLICE+%d' % slice)
986
987 def visitAugSubscript(self, node, mode):
988 if len(node.subs) > 1:
989 raise SyntaxError, "augmented assignment to tuple is not possible"
990 if mode == "load":
991 self.visitSubscript(node, 1)
992 elif mode == "store":
993 self.emit('ROT_THREE')
994 self.emit('STORE_SUBSCR')
995
996 def visitExec(self, node):
997 self.visit(node.expr)
998 if node.locals is None:
999 self.emit('LOAD_CONST', None)
1000 else:
1001 self.visit(node.locals)
1002 if node.globals is None:
1003 self.emit('DUP_TOP')
1004 else:
1005 self.visit(node.globals)
1006 self.emit('EXEC_STMT')
1007
1008 def visitCallFunc(self, node):
1009 pos = 0
1010 kw = 0
1011 self.set_lineno(node)
1012 self.visit(node.node)
1013 for arg in node.args:
1014 self.visit(arg)
1015 if isinstance(arg, ast.Keyword):
1016 kw = kw + 1
1017 else:
1018 pos = pos + 1
1019 if node.star_args is not None:
1020 self.visit(node.star_args)
1021 if node.dstar_args is not None:
1022 self.visit(node.dstar_args)
1023 have_star = node.star_args is not None
1024 have_dstar = node.dstar_args is not None
1025 opcode = callfunc_opcode_info[have_star, have_dstar]
1026 self.emit(opcode, kw << 8 | pos)
1027
1028 def visitPrint(self, node, newline=0):
1029 self.set_lineno(node)
1030 if node.dest:
1031 self.visit(node.dest)
1032 for child in node.nodes:
1033 if node.dest:
1034 self.emit('DUP_TOP')
1035 self.visit(child)
1036 if node.dest:
1037 self.emit('ROT_TWO')
1038 self.emit('PRINT_ITEM_TO')
1039 else:
1040 self.emit('PRINT_ITEM')
1041 if node.dest and not newline:
1042 self.emit('POP_TOP')
1043
1044 def visitPrintnl(self, node):
1045 self.visitPrint(node, newline=1)
1046 if node.dest:
1047 self.emit('PRINT_NEWLINE_TO')
1048 else:
1049 self.emit('PRINT_NEWLINE')
1050
1051 def visitReturn(self, node):
1052 self.set_lineno(node)
1053 self.visit(node.value)
1054 self.emit('RETURN_VALUE')
1055
1056 def visitYield(self, node):
1057 self.set_lineno(node)
1058 self.visit(node.value)
1059 self.emit('YIELD_VALUE')
1060
1061 # slice and subscript stuff
1062
1063 def visitSlice(self, node, aug_flag=None):
1064 # aug_flag is used by visitAugSlice
1065 self.visit(node.expr)
1066 slice = 0
1067 if node.lower:
1068 self.visit(node.lower)
1069 slice = slice | 1
1070 if node.upper:
1071 self.visit(node.upper)
1072 slice = slice | 2
1073 if aug_flag:
1074 if slice == 0:
1075 self.emit('DUP_TOP')
1076 elif slice == 3:
1077 self.emit('DUP_TOPX', 3)
1078 else:
1079 self.emit('DUP_TOPX', 2)
1080 if node.flags == 'OP_APPLY':
1081 self.emit('SLICE+%d' % slice)
1082 elif node.flags == 'OP_ASSIGN':
1083 self.emit('STORE_SLICE+%d' % slice)
1084 elif node.flags == 'OP_DELETE':
1085 self.emit('DELETE_SLICE+%d' % slice)
1086 else:
1087 print "weird slice", node.flags
1088 raise
1089
1090 def visitSubscript(self, node, aug_flag=None):
1091 self.visit(node.expr)
1092 for sub in node.subs:
1093 self.visit(sub)
1094 if aug_flag:
1095 self.emit('DUP_TOPX', 2)
1096 if len(node.subs) > 1:
1097 self.emit('BUILD_TUPLE', len(node.subs))
1098 if node.flags == 'OP_APPLY':
1099 self.emit('BINARY_SUBSCR')
1100 elif node.flags == 'OP_ASSIGN':
1101 self.emit('STORE_SUBSCR')
1102 elif node.flags == 'OP_DELETE':
1103 self.emit('DELETE_SUBSCR')
1104
1105 # binary ops
1106
1107 def binaryOp(self, node, op):
1108 self.visit(node.left)
1109 self.visit(node.right)
1110 self.emit(op)
1111
1112 def visitAdd(self, node):
1113 return self.binaryOp(node, 'BINARY_ADD')
1114
1115 def visitSub(self, node):
1116 return self.binaryOp(node, 'BINARY_SUBTRACT')
1117
1118 def visitMul(self, node):
1119 return self.binaryOp(node, 'BINARY_MULTIPLY')
1120
1121 def visitDiv(self, node):
1122 return self.binaryOp(node, self._div_op)
1123
1124 def visitFloorDiv(self, node):
1125 return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
1126
1127 def visitMod(self, node):
1128 return self.binaryOp(node, 'BINARY_MODULO')
1129
1130 def visitPower(self, node):
1131 return self.binaryOp(node, 'BINARY_POWER')
1132
1133 def visitLeftShift(self, node):
1134 return self.binaryOp(node, 'BINARY_LSHIFT')
1135
1136 def visitRightShift(self, node):
1137 return self.binaryOp(node, 'BINARY_RSHIFT')
1138
1139 # unary ops
1140
1141 def unaryOp(self, node, op):
1142 self.visit(node.expr)
1143 self.emit(op)
1144
1145 def visitInvert(self, node):
1146 return self.unaryOp(node, 'UNARY_INVERT')
1147
1148 def visitUnarySub(self, node):
1149 return self.unaryOp(node, 'UNARY_NEGATIVE')
1150
1151 def visitUnaryAdd(self, node):
1152 return self.unaryOp(node, 'UNARY_POSITIVE')
1153
1154 def visitUnaryInvert(self, node):
1155 return self.unaryOp(node, 'UNARY_INVERT')
1156
1157 def visitNot(self, node):
1158 return self.unaryOp(node, 'UNARY_NOT')
1159
1160 def visitBackquote(self, node):
1161 return self.unaryOp(node, 'UNARY_CONVERT')
1162
1163 # bit ops
1164
1165 def bitOp(self, nodes, op):
1166 self.visit(nodes[0])
1167 for node in nodes[1:]:
1168 self.visit(node)
1169 self.emit(op)
1170
1171 def visitBitand(self, node):
1172 return self.bitOp(node.nodes, 'BINARY_AND')
1173
1174 def visitBitor(self, node):
1175 return self.bitOp(node.nodes, 'BINARY_OR')
1176
1177 def visitBitxor(self, node):
1178 return self.bitOp(node.nodes, 'BINARY_XOR')
1179
1180 # object constructors
1181
1182 def visitEllipsis(self, node):
1183 self.emit('LOAD_CONST', Ellipsis)
1184
1185 def visitTuple(self, node):
1186 self.set_lineno(node)
1187 for elt in node.nodes:
1188 self.visit(elt)
1189 self.emit('BUILD_TUPLE', len(node.nodes))
1190
1191 def visitList(self, node):
1192 self.set_lineno(node)
1193 for elt in node.nodes:
1194 self.visit(elt)
1195 self.emit('BUILD_LIST', len(node.nodes))
1196
1197 def visitSliceobj(self, node):
1198 for child in node.nodes:
1199 self.visit(child)
1200 self.emit('BUILD_SLICE', len(node.nodes))
1201
1202 def visitDict(self, node):
1203 self.set_lineno(node)
1204 self.emit('BUILD_MAP', 0)
1205 for k, v in node.items:
1206 self.emit('DUP_TOP')
1207 self.visit(k)
1208 self.visit(v)
1209 self.emit('ROT_THREE')
1210 self.emit('STORE_SUBSCR')
1211
1212class NestedScopeMixin:
1213 """Defines initClass() for nested scoping (Python 2.2-compatible)"""
1214 def initClass(self):
1215 self.__class__.NameFinder = LocalNameFinder
1216 self.__class__.FunctionGen = FunctionCodeGenerator
1217 self.__class__.ClassGen = ClassCodeGenerator
1218
1219class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
1220 __super_init = CodeGenerator.__init__
1221
1222 scopes = None
1223
1224 def __init__(self, tree):
1225 self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
1226 self.futures = future.find_futures(tree)
1227 self.__super_init()
1228 walk(tree, self)
1229
1230 def get_module(self):
1231 return self
1232
1233class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
1234 __super_init = CodeGenerator.__init__
1235
1236 scopes = None
1237 futures = ()
1238
1239 def __init__(self, tree):
1240 self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
1241 self.__super_init()
1242 walk(tree, self)
1243
1244 def get_module(self):
1245 return self
1246
1247class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
1248
1249 __super_init = CodeGenerator.__init__
1250
1251 scopes = None
1252 futures = ()
1253
1254 def __init__(self, tree):
1255 self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
1256 self.__super_init()
1257 self.set_lineno(tree)
1258 walk(tree, self)
1259 self.emit('RETURN_VALUE')
1260
1261 def get_module(self):
1262 return self
1263
1264 def visitDiscard(self, node):
1265 # XXX Discard means it's an expression. Perhaps this is a bad
1266 # name.
1267 self.visit(node.expr)
1268 self.emit('PRINT_EXPR')
1269
1270class AbstractFunctionCode:
1271 optimized = 1
1272 lambdaCount = 0
1273
1274 def __init__(self, func, scopes, isLambda, class_name, mod):
1275 self.class_name = class_name
1276 self.module = mod
1277 if isLambda:
1278 klass = FunctionCodeGenerator
1279 name = "<lambda.%d>" % klass.lambdaCount
1280 klass.lambdaCount = klass.lambdaCount + 1
1281 else:
1282 name = func.name
1283
1284 args, hasTupleArg = generateArgList(func.argnames)
1285 self.graph = pyassem.PyFlowGraph(name, func.filename, args,
1286 optimized=1)
1287 self.isLambda = isLambda
1288 self.super_init()
1289
1290 if not isLambda and func.doc:
1291 self.setDocstring(func.doc)
1292
1293 lnf = walk(func.code, self.NameFinder(args), verbose=0)
1294 self.locals.push(lnf.getLocals())
1295 if func.varargs:
1296 self.graph.setFlag(CO_VARARGS)
1297 if func.kwargs:
1298 self.graph.setFlag(CO_VARKEYWORDS)
1299 self.set_lineno(func)
1300 if hasTupleArg:
1301 self.generateArgUnpack(func.argnames)
1302
1303 def get_module(self):
1304 return self.module
1305
1306 def finish(self):
1307 self.graph.startExitBlock()
1308 if not self.isLambda:
1309 self.emit('LOAD_CONST', None)
1310 self.emit('RETURN_VALUE')
1311
1312 def generateArgUnpack(self, args):
1313 for i in range(len(args)):
1314 arg = args[i]
1315 if type(arg) == types.TupleType:
1316 self.emit('LOAD_FAST', '.%d' % (i * 2))
1317 self.unpackSequence(arg)
1318
1319 def unpackSequence(self, tup):
1320 if VERSION > 1:
1321 self.emit('UNPACK_SEQUENCE', len(tup))
1322 else:
1323 self.emit('UNPACK_TUPLE', len(tup))
1324 for elt in tup:
1325 if type(elt) == types.TupleType:
1326 self.unpackSequence(elt)
1327 else:
1328 self._nameOp('STORE', elt)
1329
1330 unpackTuple = unpackSequence
1331
1332class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1333 CodeGenerator):
1334 super_init = CodeGenerator.__init__ # call be other init
1335 scopes = None
1336
1337 __super_init = AbstractFunctionCode.__init__
1338
1339 def __init__(self, func, scopes, isLambda, class_name, mod):
1340 self.scopes = scopes
1341 self.scope = scopes[func]
1342 self.__super_init(func, scopes, isLambda, class_name, mod)
1343 self.graph.setFreeVars(self.scope.get_free_vars())
1344 self.graph.setCellVars(self.scope.get_cell_vars())
1345 if self.scope.generator is not None:
1346 self.graph.setFlag(CO_GENERATOR)
1347
1348class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1349 CodeGenerator):
1350 super_init = CodeGenerator.__init__ # call be other init
1351 scopes = None
1352
1353 __super_init = AbstractFunctionCode.__init__
1354
1355 def __init__(self, gexp, scopes, class_name, mod):
1356 self.scopes = scopes
1357 self.scope = scopes[gexp]
1358 self.__super_init(gexp, scopes, 1, class_name, mod)
1359 self.graph.setFreeVars(self.scope.get_free_vars())
1360 self.graph.setCellVars(self.scope.get_cell_vars())
1361 self.graph.setFlag(CO_GENERATOR)
1362
1363class AbstractClassCode:
1364
1365 def __init__(self, klass, scopes, module):
1366 self.class_name = klass.name
1367 self.module = module
1368 self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
1369 optimized=0, klass=1)
1370 self.super_init()
1371 lnf = walk(klass.code, self.NameFinder(), verbose=0)
1372 self.locals.push(lnf.getLocals())
1373 self.graph.setFlag(CO_NEWLOCALS)
1374 if klass.doc:
1375 self.setDocstring(klass.doc)
1376
1377 def get_module(self):
1378 return self.module
1379
1380 def finish(self):
1381 self.graph.startExitBlock()
1382 self.emit('LOAD_LOCALS')
1383 self.emit('RETURN_VALUE')
1384
1385class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
1386 super_init = CodeGenerator.__init__
1387 scopes = None
1388
1389 __super_init = AbstractClassCode.__init__
1390
1391 def __init__(self, klass, scopes, module):
1392 self.scopes = scopes
1393 self.scope = scopes[klass]
1394 self.__super_init(klass, scopes, module)
1395 self.graph.setFreeVars(self.scope.get_free_vars())
1396 self.graph.setCellVars(self.scope.get_cell_vars())
1397 self.set_lineno(klass)
1398 self.emit("LOAD_GLOBAL", "__name__")
1399 self.storeName("__module__")
1400 if klass.doc:
1401 self.emit("LOAD_CONST", klass.doc)
1402 self.storeName('__doc__')
1403
1404def generateArgList(arglist):
1405 """Generate an arg list marking TupleArgs"""
1406 args = []
1407 extra = []
1408 count = 0
1409 for i in range(len(arglist)):
1410 elt = arglist[i]
1411 if type(elt) == types.StringType:
1412 args.append(elt)
1413 elif type(elt) == types.TupleType:
1414 args.append(TupleArg(i * 2, elt))
1415 extra.extend(misc.flatten(elt))
1416 count = count + 1
1417 else:
1418 raise ValueError, "unexpect argument type:", elt
1419 return args + extra, count
1420
1421def findOp(node):
1422 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
1423 v = OpFinder()
1424 walk(node, v, verbose=0)
1425 return v.op
1426
1427class OpFinder:
1428 def __init__(self):
1429 self.op = None
1430 def visitAssName(self, node):
1431 if self.op is None:
1432 self.op = node.flags
1433 elif self.op != node.flags:
1434 raise ValueError, "mixed ops in stmt"
1435 visitAssAttr = visitAssName
1436 visitSubscript = visitAssName
1437
1438class Delegator:
1439 """Base class to support delegation for augmented assignment nodes
1440
1441 To generator code for augmented assignments, we use the following
1442 wrapper classes. In visitAugAssign, the left-hand expression node
1443 is visited twice. The first time the visit uses the normal method
1444 for that node . The second time the visit uses a different method
1445 that generates the appropriate code to perform the assignment.
1446 These delegator classes wrap the original AST nodes in order to
1447 support the variant visit methods.
1448 """
1449 def __init__(self, obj):
1450 self.obj = obj
1451
1452 def __getattr__(self, attr):
1453 return getattr(self.obj, attr)
1454
1455class AugGetattr(Delegator):
1456 pass
1457
1458class AugName(Delegator):
1459 pass
1460
1461class AugSlice(Delegator):
1462 pass
1463
1464class AugSubscript(Delegator):
1465 pass
1466
1467wrapper = {
1468 ast.Getattr: AugGetattr,
1469 ast.Name: AugName,
1470 ast.Slice: AugSlice,
1471 ast.Subscript: AugSubscript,
1472 }
1473
1474def wrap_aug(node):
1475 return wrapper[node.__class__](node)
1476
1477if __name__ == "__main__":
1478 for file in sys.argv[1:]:
1479 compileFile(file)