]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/compiler/pycodegen.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / compiler / pycodegen.py
1 import imp
2 import os
3 import marshal
4 import struct
5 import sys
6 from cStringIO import StringIO
7
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, \
11 SC_FREE, SC_CELL
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
16
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?
19 try:
20 VERSION = sys.version_info[0]
21 except AttributeError:
22 VERSION = 1
23
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",
30 }
31
32 LOOP = 1
33 EXCEPT = 2
34 TRY_FINALLY = 3
35 END_FINALLY = 4
36
37 def compileFile(filename, display=0):
38 f = open(filename, 'U')
39 buf = f.read()
40 f.close()
41 mod = Module(buf, filename)
42 try:
43 mod.compile(display)
44 except SyntaxError:
45 raise
46 else:
47 f = open(filename + "c", "wb")
48 mod.dump(f)
49 f.close()
50
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"
55
56 if mode == "single":
57 gen = Interactive(source, filename)
58 elif mode == "exec":
59 gen = Module(source, filename)
60 elif mode == "eval":
61 gen = Expression(source, filename)
62 else:
63 raise ValueError("compile() 3rd arg must be 'exec' or "
64 "'eval' or 'single'")
65 gen.compile()
66 return gen.code
67
68 class AbstractCompileMode:
69
70 mode = None # defined by subclass
71
72 def __init__(self, source, filename):
73 self.source = source
74 self.filename = filename
75 self.code = None
76
77 def _get_tree(self):
78 tree = parse(self.source, self.mode)
79 misc.set_filename(self.filename, tree)
80 syntax.check(tree)
81 return tree
82
83 def compile(self):
84 pass # implemented by subclass
85
86 def getCode(self):
87 return self.code
88
89 class Expression(AbstractCompileMode):
90
91 mode = "eval"
92
93 def compile(self):
94 tree = self._get_tree()
95 gen = ExpressionCodeGenerator(tree)
96 self.code = gen.getCode()
97
98 class Interactive(AbstractCompileMode):
99
100 mode = "single"
101
102 def compile(self):
103 tree = self._get_tree()
104 gen = InteractiveCodeGenerator(tree)
105 self.code = gen.getCode()
106
107 class Module(AbstractCompileMode):
108
109 mode = "exec"
110
111 def compile(self, display=0):
112 tree = self._get_tree()
113 gen = ModuleCodeGenerator(tree)
114 if display:
115 import pprint
116 print pprint.pprint(tree)
117 self.code = gen.getCode()
118
119 def dump(self, f):
120 f.write(self.getPycHeader())
121 marshal.dump(self.code, f)
122
123 MAGIC = imp.get_magic()
124
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
133
134 class LocalNameFinder:
135 """Find local names in scope"""
136 def __init__(self, names=()):
137 self.names = misc.Set()
138 self.globals = misc.Set()
139 for name in names:
140 self.names.add(name)
141
142 # XXX list comprehensions and for loops
143
144 def getLocals(self):
145 for elt in self.globals.elements():
146 if self.names.has_elt(elt):
147 self.names.remove(elt)
148 return self.names
149
150 def visitDict(self, node):
151 pass
152
153 def visitGlobal(self, node):
154 for name in node.names:
155 self.globals.add(name)
156
157 def visitFunction(self, node):
158 self.names.add(node.name)
159
160 def visitLambda(self, node):
161 pass
162
163 def visitImport(self, node):
164 for name, alias in node.names:
165 self.names.add(alias or name)
166
167 def visitFrom(self, node):
168 for name, alias in node.names:
169 self.names.add(alias or name)
170
171 def visitClass(self, node):
172 self.names.add(node.name)
173
174 def visitAssName(self, node):
175 self.names.add(node.name)
176
177 def is_constant_false(node):
178 if isinstance(node, ast.Const):
179 if not node.value:
180 return 1
181 return 0
182
183 class CodeGenerator:
184 """Defines basic code generator for Python bytecode
185
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.
189
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
194 defined.
195 """
196
197 optimized = 0 # is namespace access optimized?
198 __initialized = None
199 class_name = None # provide default for instance variable
200
201 def __init__(self):
202 if self.__initialized is None:
203 self.initClass()
204 self.__class__.__initialized = 1
205 self.checkClass()
206 self.locals = misc.Stack()
207 self.setups = misc.Stack()
208 self.last_lineno = None
209 self._setupGraphDelegation()
210 self._div_op = "BINARY_DIVIDE"
211
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)
224
225 def initClass(self):
226 """This method is called once for each class"""
227
228 def checkClass(self):
229 """Verify that class is constructed correctly"""
230 try:
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
238
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
245
246 def getCode(self):
247 """Return a code object"""
248 return self.graph.getCode()
249
250 def mangle(self, name):
251 if self.class_name is not None:
252 return misc.mangle(name, self.class_name)
253 else:
254 return name
255
256 def parseSymbols(self, tree):
257 s = symbols.SymbolVisitor()
258 walk(tree, s)
259 return s.scopes
260
261 def get_module(self):
262 raise RuntimeError, "should be implemented by subclasses"
263
264 # Next five methods handle name access
265
266 def isLocalName(self, name):
267 return self.locals.top().has_elt(name)
268
269 def storeName(self, name):
270 self._nameOp('STORE', name)
271
272 def loadName(self, name):
273 self._nameOp('LOAD', name)
274
275 def delName(self, name):
276 self._nameOp('DELETE', name)
277
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)
284 else:
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)
291 else:
292 self.emit(prefix + '_GLOBAL', name)
293 elif scope == SC_FREE or scope == SC_CELL:
294 self.emit(prefix + '_DEREF', name)
295 else:
296 raise RuntimeError, "unsupported scope for var %s: %d" % \
297 (name, scope)
298
299 def _implicitNameOp(self, prefix, name):
300 """Emit name ops for names generated implicitly by for loops
301
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.
305 """
306 if self.optimized:
307 self.emit(prefix + '_FAST', name)
308 else:
309 self.emit(prefix + '_NAME', name)
310
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.
315
316 def set_lineno(self, node, force=False):
317 """Emit SET_LINENO if necessary.
318
319 The instruction is considered necessary if the node has a
320 lineno attribute and it is different than the last lineno
321 emitted.
322
323 Returns true if SET_LINENO was emitted.
324
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.
329 """
330 lineno = getattr(node, 'lineno', None)
331 if lineno is not None and (lineno != self.last_lineno
332 or force):
333 self.emit('SET_LINENO', lineno)
334 self.last_lineno = lineno
335 return True
336 return False
337
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.
341
342 NameFinder = LocalNameFinder
343 FunctionGen = None
344 ClassGen = None
345
346 def visitModule(self, node):
347 self.scopes = self.parseSymbols(node)
348 self.scope = self.scopes[node]
349 self.emit('SET_LINENO', 0)
350 if node.doc:
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')
358
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')
365
366 def visitFunction(self, node):
367 self._visitFuncOrLambda(node, isLambda=0)
368 if node.doc:
369 self.setDocstring(node.doc)
370 self.storeName(node.name)
371
372 def visitLambda(self, node):
373 self._visitFuncOrLambda(node, isLambda=1)
374
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)
380 else:
381 ndecorators = 0
382
383 gen = self.FunctionGen(node, self.scopes, isLambda,
384 self.class_name, self.get_module())
385 walk(node.code, gen)
386 gen.finish()
387 self.set_lineno(node)
388 for default in node.defaults:
389 self.visit(default)
390 self._makeClosure(gen, len(node.defaults))
391 for i in range(ndecorators):
392 self.emit('CALL_FUNCTION', 1)
393
394 def visitClass(self, node):
395 gen = self.ClassGen(node, self.scopes,
396 self.get_module())
397 walk(node.code, gen)
398 gen.finish()
399 self.set_lineno(node)
400 self.emit('LOAD_CONST', node.name)
401 for base in node.bases:
402 self.visit(base)
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)
408
409 # The rest are standard visitor methods
410
411 # The next few implement control-flow statements
412
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
420 continue
421 self.set_lineno(test)
422 self.visit(test)
423 nextTest = self.newBlock()
424 self.emit('POP_JUMP_IF_FALSE', nextTest)
425 self.nextBlock()
426 self.visit(suite)
427 self.emit('JUMP_FORWARD', end)
428 self.startBlock(nextTest)
429 if node.else_:
430 self.visit(node.else_)
431 self.nextBlock(end)
432
433 def visitWhile(self, node):
434 self.set_lineno(node)
435
436 loop = self.newBlock()
437 else_ = self.newBlock()
438
439 after = self.newBlock()
440 self.emit('SETUP_LOOP', after)
441
442 self.nextBlock(loop)
443 self.setups.push((LOOP, loop))
444
445 self.set_lineno(node, force=True)
446 self.visit(node.test)
447 self.emit('POP_JUMP_IF_FALSE', else_ or after)
448
449 self.nextBlock()
450 self.visit(node.body)
451 self.emit('JUMP_ABSOLUTE', loop)
452
453 self.startBlock(else_) # or just the POPs if not else clause
454 self.emit('POP_BLOCK')
455 self.setups.pop()
456 if node.else_:
457 self.visit(node.else_)
458 self.nextBlock(after)
459
460 def visitFor(self, node):
461 start = self.newBlock()
462 anchor = self.newBlock()
463 after = self.newBlock()
464 self.setups.push((LOOP, start))
465
466 self.set_lineno(node)
467 self.emit('SETUP_LOOP', after)
468 self.visit(node.list)
469 self.emit('GET_ITER')
470
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')
479 self.setups.pop()
480 if node.else_:
481 self.visit(node.else_)
482 self.nextBlock(after)
483
484 def visitBreak(self, node):
485 if not self.setups:
486 raise SyntaxError, "'break' outside loop (%s, %d)" % \
487 (node.filename, node.lineno)
488 self.set_lineno(node)
489 self.emit('BREAK_LOOP')
490
491 def visitContinue(self, node):
492 if not self.setups:
493 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
494 (node.filename, node.lineno)
495 kind, block = self.setups.top()
496 if kind == LOOP:
497 self.set_lineno(node)
498 self.emit('JUMP_ABSOLUTE', block)
499 self.nextBlock()
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)
504 while top > 0:
505 top = top - 1
506 kind, loop_block = self.setups[top]
507 if kind == LOOP:
508 break
509 if kind != LOOP:
510 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
511 (node.filename, node.lineno)
512 self.emit('CONTINUE_LOOP', loop_block)
513 self.nextBlock()
514 elif kind == END_FINALLY:
515 msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
516 raise SyntaxError, msg % (node.filename, node.lineno)
517
518 def visitTest(self, node, jump):
519 end = self.newBlock()
520 for child in node.nodes[:-1]:
521 self.visit(child)
522 self.emit(jump, end)
523 self.nextBlock()
524 self.visit(node.nodes[-1])
525 self.nextBlock(end)
526
527 def visitAnd(self, node):
528 self.visitTest(node, 'JUMP_IF_FALSE_OR_POP')
529
530 def visitOr(self, node):
531 self.visitTest(node, 'JUMP_IF_TRUE_OR_POP')
532
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)
543
544 def visitCompare(self, node):
545 self.visit(node.expr)
546 cleanup = self.newBlock()
547 for op, code in node.ops[:-1]:
548 self.visit(code)
549 self.emit('DUP_TOP')
550 self.emit('ROT_THREE')
551 self.emit('COMPARE_OP', op)
552 self.emit('JUMP_IF_FALSE_OR_POP', cleanup)
553 self.nextBlock()
554 # now do the last comparison
555 if node.ops:
556 op, code = node.ops[-1]
557 self.visit(code)
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)
563 self.emit('ROT_TWO')
564 self.emit('POP_TOP')
565 self.nextBlock(end)
566
567 # list comprehensions
568 def visitListComp(self, node):
569 self.set_lineno(node)
570 # setup list
571 self.emit('BUILD_LIST', 0)
572
573 stack = []
574 for i, for_ in zip(range(len(node.quals)), node.quals):
575 start, anchor = self.visit(for_)
576 cont = None
577 for if_ in for_.ifs:
578 if cont is None:
579 cont = self.newBlock()
580 self.visit(if_, cont)
581 stack.insert(0, (start, cont, anchor))
582
583 self.visit(node.expr)
584 self.emit('LIST_APPEND', len(node.quals) + 1)
585
586 for start, cont, anchor in stack:
587 if cont:
588 self.nextBlock(cont)
589 self.emit('JUMP_ABSOLUTE', start)
590 self.startBlock(anchor)
591
592 def visitSetComp(self, node):
593 self.set_lineno(node)
594 # setup list
595 self.emit('BUILD_SET', 0)
596
597 stack = []
598 for i, for_ in zip(range(len(node.quals)), node.quals):
599 start, anchor = self.visit(for_)
600 cont = None
601 for if_ in for_.ifs:
602 if cont is None:
603 cont = self.newBlock()
604 self.visit(if_, cont)
605 stack.insert(0, (start, cont, anchor))
606
607 self.visit(node.expr)
608 self.emit('SET_ADD', len(node.quals) + 1)
609
610 for start, cont, anchor in stack:
611 if cont:
612 self.nextBlock(cont)
613 self.emit('JUMP_ABSOLUTE', start)
614 self.startBlock(anchor)
615
616 def visitDictComp(self, node):
617 self.set_lineno(node)
618 # setup list
619 self.emit('BUILD_MAP', 0)
620
621 stack = []
622 for i, for_ in zip(range(len(node.quals)), node.quals):
623 start, anchor = self.visit(for_)
624 cont = None
625 for if_ in for_.ifs:
626 if cont is None:
627 cont = self.newBlock()
628 self.visit(if_, cont)
629 stack.insert(0, (start, cont, anchor))
630
631 self.visit(node.value)
632 self.visit(node.key)
633 self.emit('MAP_ADD', len(node.quals) + 1)
634
635 for start, cont, anchor in stack:
636 if cont:
637 self.nextBlock(cont)
638 self.emit('JUMP_ABSOLUTE', start)
639 self.startBlock(anchor)
640
641 def visitListCompFor(self, node):
642 start = self.newBlock()
643 anchor = self.newBlock()
644
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)
650 self.nextBlock()
651 self.visit(node.assign)
652 return start, anchor
653
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)
658 self.newBlock()
659
660 def _makeClosure(self, gen, args):
661 frees = gen.scope.get_free_vars()
662 if frees:
663 for name in frees:
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)
668 else:
669 self.emit('LOAD_CONST', gen)
670 self.emit('MAKE_FUNCTION', args)
671
672 def visitGenExpr(self, node):
673 gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
674 self.get_module())
675 walk(node.code, gen)
676 gen.finish()
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)
683
684 def visitGenExprInner(self, node):
685 self.set_lineno(node)
686 # setup list
687
688 stack = []
689 for i, for_ in zip(range(len(node.quals)), node.quals):
690 start, anchor, end = self.visit(for_)
691 cont = None
692 for if_ in for_.ifs:
693 if cont is None:
694 cont = self.newBlock()
695 self.visit(if_, cont)
696 stack.insert(0, (start, cont, anchor, end))
697
698 self.visit(node.expr)
699 self.emit('YIELD_VALUE')
700 self.emit('POP_TOP')
701
702 for start, cont, anchor, end in stack:
703 if cont:
704 self.nextBlock(cont)
705 self.emit('JUMP_ABSOLUTE', start)
706 self.startBlock(anchor)
707 self.emit('POP_BLOCK')
708 self.setups.pop()
709 self.nextBlock(end)
710
711 self.emit('LOAD_CONST', None)
712
713 def visitGenExprFor(self, node):
714 start = self.newBlock()
715 anchor = self.newBlock()
716 end = self.newBlock()
717
718 self.setups.push((LOOP, start))
719 self.emit('SETUP_LOOP', end)
720
721 if node.is_outmost:
722 self.loadName('.0')
723 else:
724 self.visit(node.iter)
725 self.emit('GET_ITER')
726
727 self.nextBlock(start)
728 self.set_lineno(node, force=True)
729 self.emit('FOR_ITER', anchor)
730 self.nextBlock()
731 self.visit(node.assign)
732 return start, anchor, end
733
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)
738 self.newBlock()
739
740 # exception related
741
742 def visitAssert(self, node):
743 # XXX would be interesting to implement this via a
744 # transformation of the AST before this stage
745 if __debug__:
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.
751 self.nextBlock()
752 self.visit(node.test)
753 self.emit('POP_JUMP_IF_TRUE', end)
754 self.nextBlock()
755 self.emit('LOAD_GLOBAL', 'AssertionError')
756 if node.fail:
757 self.visit(node.fail)
758 self.emit('RAISE_VARARGS', 2)
759 else:
760 self.emit('RAISE_VARARGS', 1)
761 self.nextBlock(end)
762
763 def visitRaise(self, node):
764 self.set_lineno(node)
765 n = 0
766 if node.expr1:
767 self.visit(node.expr1)
768 n = n + 1
769 if node.expr2:
770 self.visit(node.expr2)
771 n = n + 1
772 if node.expr3:
773 self.visit(node.expr3)
774 n = n + 1
775 self.emit('RAISE_VARARGS', n)
776
777 def visitTryExcept(self, node):
778 body = self.newBlock()
779 handlers = self.newBlock()
780 end = self.newBlock()
781 if node.else_:
782 lElse = self.newBlock()
783 else:
784 lElse = end
785 self.set_lineno(node)
786 self.emit('SETUP_EXCEPT', handlers)
787 self.nextBlock(body)
788 self.setups.push((EXCEPT, body))
789 self.visit(node.body)
790 self.emit('POP_BLOCK')
791 self.setups.pop()
792 self.emit('JUMP_FORWARD', lElse)
793 self.startBlock(handlers)
794
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)
799 if expr:
800 self.emit('DUP_TOP')
801 self.visit(expr)
802 self.emit('COMPARE_OP', 'exception match')
803 next = self.newBlock()
804 self.emit('POP_JUMP_IF_FALSE', next)
805 self.nextBlock()
806 self.emit('POP_TOP')
807 if target:
808 self.visit(target)
809 else:
810 self.emit('POP_TOP')
811 self.emit('POP_TOP')
812 self.visit(body)
813 self.emit('JUMP_FORWARD', end)
814 if expr:
815 self.nextBlock(next)
816 else:
817 self.nextBlock()
818 self.emit('END_FINALLY')
819 if node.else_:
820 self.nextBlock(lElse)
821 self.visit(node.else_)
822 self.nextBlock(end)
823
824 def visitTryFinally(self, node):
825 body = self.newBlock()
826 final = self.newBlock()
827 self.set_lineno(node)
828 self.emit('SETUP_FINALLY', final)
829 self.nextBlock(body)
830 self.setups.push((TRY_FINALLY, body))
831 self.visit(node.body)
832 self.emit('POP_BLOCK')
833 self.setups.pop()
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')
839 self.setups.pop()
840
841 __with_count = 0
842
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)
850 self.emit('DUP_TOP')
851 self.emit('LOAD_ATTR', '__exit__')
852 self.emit('ROT_TWO')
853 self.emit('LOAD_ATTR', '__enter__')
854 self.emit('CALL_FUNCTION', 0)
855 if node.vars is None:
856 self.emit('POP_TOP')
857 else:
858 self._implicitNameOp('STORE', valuevar)
859 self.emit('SETUP_FINALLY', final)
860 self.nextBlock(body)
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')
868 self.setups.pop()
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')
874 self.setups.pop()
875 self.__with_count -= 1
876
877 # misc
878
879 def visitDiscard(self, node):
880 self.set_lineno(node)
881 self.visit(node.expr)
882 self.emit('POP_TOP')
883
884 def visitConst(self, node):
885 self.emit('LOAD_CONST', node.value)
886
887 def visitKeyword(self, node):
888 self.emit('LOAD_CONST', node.name)
889 self.visit(node.expr)
890
891 def visitGlobal(self, node):
892 # no code to generate
893 pass
894
895 def visitName(self, node):
896 self.set_lineno(node)
897 self.loadName(node.name)
898
899 def visitPass(self, node):
900 self.set_lineno(node)
901
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:
906 if VERSION > 1:
907 self.emit('LOAD_CONST', level)
908 self.emit('LOAD_CONST', None)
909 self.emit('IMPORT_NAME', name)
910 mod = name.split(".")[0]
911 if alias:
912 self._resolveDots(name)
913 self.storeName(alias)
914 else:
915 self.storeName(mod)
916
917 def visitFrom(self, node):
918 self.set_lineno(node)
919 level = node.level
920 if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
921 level = -1
922 fromlist = tuple(name for (name, alias) in node.names)
923 if VERSION > 1:
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:
928 if VERSION > 1:
929 if name == '*':
930 self.namespace = 0
931 self.emit('IMPORT_STAR')
932 # There can only be one name w/ from ... import *
933 assert len(node.names) == 1
934 return
935 else:
936 self.emit('IMPORT_FROM', name)
937 self._resolveDots(name)
938 self.storeName(alias or name)
939 else:
940 self.emit('IMPORT_FROM', name)
941 self.emit('POP_TOP')
942
943 def _resolveDots(self, name):
944 elts = name.split(".")
945 if len(elts) == 1:
946 return
947 for elt in elts[1:]:
948 self.emit('LOAD_ATTR', elt)
949
950 def visitGetattr(self, node):
951 self.visit(node.expr)
952 self.emit('LOAD_ATTR', self.mangle(node.attrname))
953
954 # next five implement assignments
955
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)):
961 elt = node.nodes[i]
962 if i < dups:
963 self.emit('DUP_TOP')
964 if isinstance(elt, ast.Node):
965 self.visit(elt)
966
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)
973 else:
974 print "oops", node.flags
975
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))
982 else:
983 print "warning: unexpected flags:", node.flags
984 print node
985
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:
990 self.visit(child)
991
992 if VERSION > 1:
993 visitAssTuple = _visitAssSequence
994 visitAssList = _visitAssSequence
995 else:
996 def visitAssTuple(self, node):
997 self._visitAssSequence(node, 'UNPACK_TUPLE')
998
999 def visitAssList(self, node):
1000 self._visitAssSequence(node, 'UNPACK_LIST')
1001
1002 # augmented assignment
1003
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")
1011
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',
1025 }
1026
1027 def visitAugName(self, node, mode):
1028 if mode == "load":
1029 self.loadName(node.name)
1030 elif mode == "store":
1031 self.storeName(node.name)
1032
1033 def visitAugGetattr(self, node, mode):
1034 if mode == "load":
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))
1041
1042 def visitAugSlice(self, node, mode):
1043 if mode == "load":
1044 self.visitSlice(node, 1)
1045 elif mode == "store":
1046 slice = 0
1047 if node.lower:
1048 slice = slice | 1
1049 if node.upper:
1050 slice = slice | 2
1051 if slice == 0:
1052 self.emit('ROT_TWO')
1053 elif slice == 3:
1054 self.emit('ROT_FOUR')
1055 else:
1056 self.emit('ROT_THREE')
1057 self.emit('STORE_SLICE+%d' % slice)
1058
1059 def visitAugSubscript(self, node, mode):
1060 if mode == "load":
1061 self.visitSubscript(node, 1)
1062 elif mode == "store":
1063 self.emit('ROT_THREE')
1064 self.emit('STORE_SUBSCR')
1065
1066 def visitExec(self, node):
1067 self.visit(node.expr)
1068 if node.locals is None:
1069 self.emit('LOAD_CONST', None)
1070 else:
1071 self.visit(node.locals)
1072 if node.globals is None:
1073 self.emit('DUP_TOP')
1074 else:
1075 self.visit(node.globals)
1076 self.emit('EXEC_STMT')
1077
1078 def visitCallFunc(self, node):
1079 pos = 0
1080 kw = 0
1081 self.set_lineno(node)
1082 self.visit(node.node)
1083 for arg in node.args:
1084 self.visit(arg)
1085 if isinstance(arg, ast.Keyword):
1086 kw = kw + 1
1087 else:
1088 pos = pos + 1
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)
1097
1098 def visitPrint(self, node, newline=0):
1099 self.set_lineno(node)
1100 if node.dest:
1101 self.visit(node.dest)
1102 for child in node.nodes:
1103 if node.dest:
1104 self.emit('DUP_TOP')
1105 self.visit(child)
1106 if node.dest:
1107 self.emit('ROT_TWO')
1108 self.emit('PRINT_ITEM_TO')
1109 else:
1110 self.emit('PRINT_ITEM')
1111 if node.dest and not newline:
1112 self.emit('POP_TOP')
1113
1114 def visitPrintnl(self, node):
1115 self.visitPrint(node, newline=1)
1116 if node.dest:
1117 self.emit('PRINT_NEWLINE_TO')
1118 else:
1119 self.emit('PRINT_NEWLINE')
1120
1121 def visitReturn(self, node):
1122 self.set_lineno(node)
1123 self.visit(node.value)
1124 self.emit('RETURN_VALUE')
1125
1126 def visitYield(self, node):
1127 self.set_lineno(node)
1128 self.visit(node.value)
1129 self.emit('YIELD_VALUE')
1130
1131 # slice and subscript stuff
1132
1133 def visitSlice(self, node, aug_flag=None):
1134 # aug_flag is used by visitAugSlice
1135 self.visit(node.expr)
1136 slice = 0
1137 if node.lower:
1138 self.visit(node.lower)
1139 slice = slice | 1
1140 if node.upper:
1141 self.visit(node.upper)
1142 slice = slice | 2
1143 if aug_flag:
1144 if slice == 0:
1145 self.emit('DUP_TOP')
1146 elif slice == 3:
1147 self.emit('DUP_TOPX', 3)
1148 else:
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)
1156 else:
1157 print "weird slice", node.flags
1158 raise
1159
1160 def visitSubscript(self, node, aug_flag=None):
1161 self.visit(node.expr)
1162 for sub in node.subs:
1163 self.visit(sub)
1164 if len(node.subs) > 1:
1165 self.emit('BUILD_TUPLE', len(node.subs))
1166 if aug_flag:
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')
1174
1175 # binary ops
1176
1177 def binaryOp(self, node, op):
1178 self.visit(node.left)
1179 self.visit(node.right)
1180 self.emit(op)
1181
1182 def visitAdd(self, node):
1183 return self.binaryOp(node, 'BINARY_ADD')
1184
1185 def visitSub(self, node):
1186 return self.binaryOp(node, 'BINARY_SUBTRACT')
1187
1188 def visitMul(self, node):
1189 return self.binaryOp(node, 'BINARY_MULTIPLY')
1190
1191 def visitDiv(self, node):
1192 return self.binaryOp(node, self._div_op)
1193
1194 def visitFloorDiv(self, node):
1195 return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
1196
1197 def visitMod(self, node):
1198 return self.binaryOp(node, 'BINARY_MODULO')
1199
1200 def visitPower(self, node):
1201 return self.binaryOp(node, 'BINARY_POWER')
1202
1203 def visitLeftShift(self, node):
1204 return self.binaryOp(node, 'BINARY_LSHIFT')
1205
1206 def visitRightShift(self, node):
1207 return self.binaryOp(node, 'BINARY_RSHIFT')
1208
1209 # unary ops
1210
1211 def unaryOp(self, node, op):
1212 self.visit(node.expr)
1213 self.emit(op)
1214
1215 def visitInvert(self, node):
1216 return self.unaryOp(node, 'UNARY_INVERT')
1217
1218 def visitUnarySub(self, node):
1219 return self.unaryOp(node, 'UNARY_NEGATIVE')
1220
1221 def visitUnaryAdd(self, node):
1222 return self.unaryOp(node, 'UNARY_POSITIVE')
1223
1224 def visitUnaryInvert(self, node):
1225 return self.unaryOp(node, 'UNARY_INVERT')
1226
1227 def visitNot(self, node):
1228 return self.unaryOp(node, 'UNARY_NOT')
1229
1230 def visitBackquote(self, node):
1231 return self.unaryOp(node, 'UNARY_CONVERT')
1232
1233 # bit ops
1234
1235 def bitOp(self, nodes, op):
1236 self.visit(nodes[0])
1237 for node in nodes[1:]:
1238 self.visit(node)
1239 self.emit(op)
1240
1241 def visitBitand(self, node):
1242 return self.bitOp(node.nodes, 'BINARY_AND')
1243
1244 def visitBitor(self, node):
1245 return self.bitOp(node.nodes, 'BINARY_OR')
1246
1247 def visitBitxor(self, node):
1248 return self.bitOp(node.nodes, 'BINARY_XOR')
1249
1250 # object constructors
1251
1252 def visitEllipsis(self, node):
1253 self.emit('LOAD_CONST', Ellipsis)
1254
1255 def visitTuple(self, node):
1256 self.set_lineno(node)
1257 for elt in node.nodes:
1258 self.visit(elt)
1259 self.emit('BUILD_TUPLE', len(node.nodes))
1260
1261 def visitList(self, node):
1262 self.set_lineno(node)
1263 for elt in node.nodes:
1264 self.visit(elt)
1265 self.emit('BUILD_LIST', len(node.nodes))
1266
1267 def visitSet(self, node):
1268 self.set_lineno(node)
1269 for elt in node.nodes:
1270 self.visit(elt)
1271 self.emit('BUILD_SET', len(node.nodes))
1272
1273 def visitSliceobj(self, node):
1274 for child in node.nodes:
1275 self.visit(child)
1276 self.emit('BUILD_SLICE', len(node.nodes))
1277
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')
1283 self.visit(k)
1284 self.visit(v)
1285 self.emit('ROT_THREE')
1286 self.emit('STORE_SUBSCR')
1287
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
1294
1295 class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
1296 __super_init = CodeGenerator.__init__
1297
1298 scopes = None
1299
1300 def __init__(self, tree):
1301 self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
1302 self.futures = future.find_futures(tree)
1303 self.__super_init()
1304 walk(tree, self)
1305
1306 def get_module(self):
1307 return self
1308
1309 class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
1310 __super_init = CodeGenerator.__init__
1311
1312 scopes = None
1313 futures = ()
1314
1315 def __init__(self, tree):
1316 self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
1317 self.__super_init()
1318 walk(tree, self)
1319
1320 def get_module(self):
1321 return self
1322
1323 class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
1324
1325 __super_init = CodeGenerator.__init__
1326
1327 scopes = None
1328 futures = ()
1329
1330 def __init__(self, tree):
1331 self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
1332 self.__super_init()
1333 self.set_lineno(tree)
1334 walk(tree, self)
1335 self.emit('RETURN_VALUE')
1336
1337 def get_module(self):
1338 return self
1339
1340 def visitDiscard(self, node):
1341 # XXX Discard means it's an expression. Perhaps this is a bad
1342 # name.
1343 self.visit(node.expr)
1344 self.emit('PRINT_EXPR')
1345
1346 class AbstractFunctionCode:
1347 optimized = 1
1348 lambdaCount = 0
1349
1350 def __init__(self, func, scopes, isLambda, class_name, mod):
1351 self.class_name = class_name
1352 self.module = mod
1353 if isLambda:
1354 klass = FunctionCodeGenerator
1355 name = "<lambda.%d>" % klass.lambdaCount
1356 klass.lambdaCount = klass.lambdaCount + 1
1357 else:
1358 name = func.name
1359
1360 args, hasTupleArg = generateArgList(func.argnames)
1361 self.graph = pyassem.PyFlowGraph(name, func.filename, args,
1362 optimized=1)
1363 self.isLambda = isLambda
1364 self.super_init()
1365
1366 if not isLambda and func.doc:
1367 self.setDocstring(func.doc)
1368
1369 lnf = walk(func.code, self.NameFinder(args), verbose=0)
1370 self.locals.push(lnf.getLocals())
1371 if func.varargs:
1372 self.graph.setFlag(CO_VARARGS)
1373 if func.kwargs:
1374 self.graph.setFlag(CO_VARKEYWORDS)
1375 self.set_lineno(func)
1376 if hasTupleArg:
1377 self.generateArgUnpack(func.argnames)
1378
1379 def get_module(self):
1380 return self.module
1381
1382 def finish(self):
1383 self.graph.startExitBlock()
1384 if not self.isLambda:
1385 self.emit('LOAD_CONST', None)
1386 self.emit('RETURN_VALUE')
1387
1388 def generateArgUnpack(self, args):
1389 for i in range(len(args)):
1390 arg = args[i]
1391 if isinstance(arg, tuple):
1392 self.emit('LOAD_FAST', '.%d' % (i * 2))
1393 self.unpackSequence(arg)
1394
1395 def unpackSequence(self, tup):
1396 if VERSION > 1:
1397 self.emit('UNPACK_SEQUENCE', len(tup))
1398 else:
1399 self.emit('UNPACK_TUPLE', len(tup))
1400 for elt in tup:
1401 if isinstance(elt, tuple):
1402 self.unpackSequence(elt)
1403 else:
1404 self._nameOp('STORE', elt)
1405
1406 unpackTuple = unpackSequence
1407
1408 class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1409 CodeGenerator):
1410 super_init = CodeGenerator.__init__ # call be other init
1411 scopes = None
1412
1413 __super_init = AbstractFunctionCode.__init__
1414
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)
1423
1424 class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1425 CodeGenerator):
1426 super_init = CodeGenerator.__init__ # call be other init
1427 scopes = None
1428
1429 __super_init = AbstractFunctionCode.__init__
1430
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)
1438
1439 class AbstractClassCode:
1440
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)
1446 self.super_init()
1447 lnf = walk(klass.code, self.NameFinder(), verbose=0)
1448 self.locals.push(lnf.getLocals())
1449 self.graph.setFlag(CO_NEWLOCALS)
1450 if klass.doc:
1451 self.setDocstring(klass.doc)
1452
1453 def get_module(self):
1454 return self.module
1455
1456 def finish(self):
1457 self.graph.startExitBlock()
1458 self.emit('LOAD_LOCALS')
1459 self.emit('RETURN_VALUE')
1460
1461 class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
1462 super_init = CodeGenerator.__init__
1463 scopes = None
1464
1465 __super_init = AbstractClassCode.__init__
1466
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__")
1476 if klass.doc:
1477 self.emit("LOAD_CONST", klass.doc)
1478 self.storeName('__doc__')
1479
1480 def generateArgList(arglist):
1481 """Generate an arg list marking TupleArgs"""
1482 args = []
1483 extra = []
1484 count = 0
1485 for i in range(len(arglist)):
1486 elt = arglist[i]
1487 if isinstance(elt, str):
1488 args.append(elt)
1489 elif isinstance(elt, tuple):
1490 args.append(TupleArg(i * 2, elt))
1491 extra.extend(misc.flatten(elt))
1492 count = count + 1
1493 else:
1494 raise ValueError, "unexpect argument type:", elt
1495 return args + extra, count
1496
1497 def findOp(node):
1498 """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
1499 v = OpFinder()
1500 walk(node, v, verbose=0)
1501 return v.op
1502
1503 class OpFinder:
1504 def __init__(self):
1505 self.op = None
1506 def visitAssName(self, node):
1507 if self.op is None:
1508 self.op = node.flags
1509 elif self.op != node.flags:
1510 raise ValueError, "mixed ops in stmt"
1511 visitAssAttr = visitAssName
1512 visitSubscript = visitAssName
1513
1514 class Delegator:
1515 """Base class to support delegation for augmented assignment nodes
1516
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.
1524 """
1525 def __init__(self, obj):
1526 self.obj = obj
1527
1528 def __getattr__(self, attr):
1529 return getattr(self.obj, attr)
1530
1531 class AugGetattr(Delegator):
1532 pass
1533
1534 class AugName(Delegator):
1535 pass
1536
1537 class AugSlice(Delegator):
1538 pass
1539
1540 class AugSubscript(Delegator):
1541 pass
1542
1543 wrapper = {
1544 ast.Getattr: AugGetattr,
1545 ast.Name: AugName,
1546 ast.Slice: AugSlice,
1547 ast.Subscript: AugSubscript,
1548 }
1549
1550 def wrap_aug(node):
1551 return wrapper[node.__class__](node)
1552
1553 if __name__ == "__main__":
1554 for file in sys.argv[1:]:
1555 compileFile(file)