0001 import imp 0002 import os 0003 import marshal 0004 import struct 0005 import sys 0006 import types 0007 from cStringIO import StringIO 0008 0009 from compiler import ast, parse, walk, syntax 0010 from compiler import pyassem, misc, future, symbols 0011 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL 0012 from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\ 0013 CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION 0014 from compiler.pyassem import TupleArg 0015 0016 # XXX The version-specific code can go, since this code only works with 2.x. 0017 # Do we have Python 1.x or Python 2.x? 0018 try: 0019 VERSION = sys.version_info[0] 0020 except AttributeError: 0021 VERSION = 1 0022 0023 callfunc_opcode_info = { 0024 # (Have *args, Have **args) : opcode 0025 (0,0) : "CALL_FUNCTION", 0026 (1,0) : "CALL_FUNCTION_VAR", 0027 (0,1) : "CALL_FUNCTION_KW", 0028 (1,1) : "CALL_FUNCTION_VAR_KW", 0029 } 0030 0031 LOOP = 1 0032 EXCEPT = 2 0033 TRY_FINALLY = 3 0034 END_FINALLY = 4 0035 0036 def compileFile(filename, display=0): 0037 f = open(filename, 'U') 0038 buf = f.read() 0039 f.close() 0040 mod = Module(buf, filename) 0041 try: 0042 mod.compile(display) 0043 except SyntaxError: 0044 raise 0045 else: 0046 f = open(filename + "c", "wb") 0047 mod.dump(f) 0048 f.close() 0049 0050 def compile(source, filename, mode, flags=None, dont_inherit=None): 0051 """Replacement for builtin compile() function""" 0052 if flags is not None or dont_inherit is not None: 0053 raise RuntimeError, "not implemented yet" 0054 0055 if mode == "single": 0056 gen = Interactive(source, filename) 0057 elif mode == "exec": 0058 gen = Module(source, filename) 0059 elif mode == "eval": 0060 gen = Expression(source, filename) 0061 else: 0062 raise ValueError("compile() 3rd arg must be 'exec' or " 0063 "'eval' or 'single'") 0064 gen.compile() 0065 return gen.code 0066 0067 class AbstractCompileMode: 0068 0069 mode = None # defined by subclass 0070 0071 def __init__(self, source, filename): 0072 self.source = source 0073 self.filename = filename 0074 self.code = None 0075 0076 def _get_tree(self): 0077 tree = parse(self.source, self.mode) 0078 misc.set_filename(self.filename, tree) 0079 syntax.check(tree) 0080 return tree 0081 0082 def compile(self): 0083 pass # implemented by subclass 0084 0085 def getCode(self): 0086 return self.code 0087 0088 class Expression(AbstractCompileMode): 0089 0090 mode = "eval" 0091 0092 def compile(self): 0093 tree = self._get_tree() 0094 gen = ExpressionCodeGenerator(tree) 0095 self.code = gen.getCode() 0096 0097 class Interactive(AbstractCompileMode): 0098 0099 mode = "single" 0100 0101 def compile(self): 0102 tree = self._get_tree() 0103 gen = InteractiveCodeGenerator(tree) 0104 self.code = gen.getCode() 0105 0106 class Module(AbstractCompileMode): 0107 0108 mode = "exec" 0109 0110 def compile(self, display=0): 0111 tree = self._get_tree() 0112 gen = ModuleCodeGenerator(tree) 0113 if display: 0114 import pprint 0115 print pprint.pprint(tree) 0116 self.code = gen.getCode() 0117 0118 def dump(self, f): 0119 f.write(self.getPycHeader()) 0120 marshal.dump(self.code, f) 0121 0122 MAGIC = imp.get_magic() 0123 0124 def getPycHeader(self): 0125 # compile.c uses marshal to write a long directly, with 0126 # calling the interface that would also generate a 1-byte code 0127 # to indicate the type of the value. simplest way to get the 0128 # same effect is to call marshal and then skip the code. 0129 mtime = os.path.getmtime(self.filename) 0130 mtime = struct.pack('<i', mtime) 0131 return self.MAGIC + mtime 0132 0133 class LocalNameFinder: 0134 """Find local names in scope""" 0135 def __init__(self, names=()): 0136 self.names = misc.Set() 0137 self.globals = misc.Set() 0138 for name in names: 0139 self.names.add(name) 0140 0141 # XXX list comprehensions and for loops 0142 0143 def getLocals(self): 0144 for elt in self.globals.elements(): 0145 if self.names.has_elt(elt): 0146 self.names.remove(elt) 0147 return self.names 0148 0149 def visitDict(self, node): 0150 pass 0151 0152 def visitGlobal(self, node): 0153 for name in node.names: 0154 self.globals.add(name) 0155 0156 def visitFunction(self, node): 0157 self.names.add(node.name) 0158 0159 def visitLambda(self, node): 0160 pass 0161 0162 def visitImport(self, node): 0163 for name, alias in node.names: 0164 self.names.add(alias or name) 0165 0166 def visitFrom(self, node): 0167 for name, alias in node.names: 0168 self.names.add(alias or name) 0169 0170 def visitClass(self, node): 0171 self.names.add(node.name) 0172 0173 def visitAssName(self, node): 0174 self.names.add(node.name) 0175 0176 def is_constant_false(node): 0177 if isinstance(node, ast.Const): 0178 if not node.value: 0179 return 1 0180 return 0 0181 0182 class CodeGenerator: 0183 """Defines basic code generator for Python bytecode 0184 0185 This class is an abstract base class. Concrete subclasses must 0186 define an __init__() that defines self.graph and then calls the 0187 __init__() defined in this class. 0188 0189 The concrete class must also define the class attributes 0190 NameFinder, FunctionGen, and ClassGen. These attributes can be 0191 defined in the initClass() method, which is a hook for 0192 initializing these methods after all the classes have been 0193 defined. 0194 """ 0195 0196 optimized = 0 # is namespace access optimized? 0197 __initialized = None 0198 class_name = None # provide default for instance variable 0199 0200 def __init__(self): 0201 if self.__initialized is None: 0202 self.initClass() 0203 self.__class__.__initialized = 1 0204 self.checkClass() 0205 self.locals = misc.Stack() 0206 self.setups = misc.Stack() 0207 self.last_lineno = None 0208 self._setupGraphDelegation() 0209 self._div_op = "BINARY_DIVIDE" 0210 0211 # XXX set flags based on future features 0212 futures = self.get_module().futures 0213 for feature in futures: 0214 if feature == "division": 0215 self.graph.setFlag(CO_FUTURE_DIVISION) 0216 self._div_op = "BINARY_TRUE_DIVIDE" 0217 elif feature == "generators": 0218 self.graph.setFlag(CO_GENERATOR_ALLOWED) 0219 0220 def initClass(self): 0221 """This method is called once for each class""" 0222 0223 def checkClass(self): 0224 """Verify that class is constructed correctly""" 0225 try: 0226 assert hasattr(self, 'graph') 0227 assert getattr(self, 'NameFinder') 0228 assert getattr(self, 'FunctionGen') 0229 assert getattr(self, 'ClassGen') 0230 except AssertionError, msg: 0231 intro = "Bad class construction for %s" % self.__class__.__name__ 0232 raise AssertionError, intro 0233 0234 def _setupGraphDelegation(self): 0235 self.emit = self.graph.emit 0236 self.newBlock = self.graph.newBlock 0237 self.startBlock = self.graph.startBlock 0238 self.nextBlock = self.graph.nextBlock 0239 self.setDocstring = self.graph.setDocstring 0240 0241 def getCode(self): 0242 """Return a code object""" 0243 return self.graph.getCode() 0244 0245 def mangle(self, name): 0246 if self.class_name is not None: 0247 return misc.mangle(name, self.class_name) 0248 else: 0249 return name 0250 0251 def parseSymbols(self, tree): 0252 s = symbols.SymbolVisitor() 0253 walk(tree, s) 0254 return s.scopes 0255 0256 def get_module(self): 0257 raise RuntimeError, "should be implemented by subclasses" 0258 0259 # Next five methods handle name access 0260 0261 def isLocalName(self, name): 0262 return self.locals.top().has_elt(name) 0263 0264 def storeName(self, name): 0265 self._nameOp('STORE', name) 0266 0267 def loadName(self, name): 0268 self._nameOp('LOAD', name) 0269 0270 def delName(self, name): 0271 self._nameOp('DELETE', name) 0272 0273 def _nameOp(self, prefix, name): 0274 name = self.mangle(name) 0275 scope = self.scope.check_name(name) 0276 if scope == SC_LOCAL: 0277 if not self.optimized: 0278 self.emit(prefix + '_NAME', name) 0279 else: 0280 self.emit(prefix + '_FAST', name) 0281 elif scope == SC_GLOBAL: 0282 if not self.optimized: 0283 self.emit(prefix + '_NAME', name) 0284 else: 0285 self.emit(prefix + '_GLOBAL', name) 0286 elif scope == SC_FREE or scope == SC_CELL: 0287 self.emit(prefix + '_DEREF', name) 0288 else: 0289 raise RuntimeError, "unsupported scope for var %s: %d" % \ 0290 (name, scope) 0291 0292 def _implicitNameOp(self, prefix, name): 0293 """Emit name ops for names generated implicitly by for loops 0294 0295 The interpreter generates names that start with a period or 0296 dollar sign. The symbol table ignores these names because 0297 they aren't present in the program text. 0298 """ 0299 if self.optimized: 0300 self.emit(prefix + '_FAST', name) 0301 else: 0302 self.emit(prefix + '_NAME', name) 0303 0304 # The set_lineno() function and the explicit emit() calls for 0305 # SET_LINENO below are only used to generate the line number table. 0306 # As of Python 2.3, the interpreter does not have a SET_LINENO 0307 # instruction. pyassem treats SET_LINENO opcodes as a special case. 0308 0309 def set_lineno(self, node, force=False): 0310 """Emit SET_LINENO if necessary. 0311 0312 The instruction is considered necessary if the node has a 0313 lineno attribute and it is different than the last lineno 0314 emitted. 0315 0316 Returns true if SET_LINENO was emitted. 0317 0318 There are no rules for when an AST node should have a lineno 0319 attribute. The transformer and AST code need to be reviewed 0320 and a consistent policy implemented and documented. Until 0321 then, this method works around missing line numbers. 0322 """ 0323 lineno = getattr(node, 'lineno', None) 0324 if lineno is not None and (lineno != self.last_lineno 0325 or force): 0326 self.emit('SET_LINENO', lineno) 0327 self.last_lineno = lineno 0328 return True 0329 return False 0330 0331 # The first few visitor methods handle nodes that generator new 0332 # code objects. They use class attributes to determine what 0333 # specialized code generators to use. 0334 0335 NameFinder = LocalNameFinder 0336 FunctionGen = None 0337 ClassGen = None 0338 0339 def visitModule(self, node): 0340 self.scopes = self.parseSymbols(node) 0341 self.scope = self.scopes[node] 0342 self.emit('SET_LINENO', 0) 0343 if node.doc: 0344 self.emit('LOAD_CONST', node.doc) 0345 self.storeName('__doc__') 0346 lnf = walk(node.node, self.NameFinder(), verbose=0) 0347 self.locals.push(lnf.getLocals()) 0348 self.visit(node.node) 0349 self.emit('LOAD_CONST', None) 0350 self.emit('RETURN_VALUE') 0351 0352 def visitExpression(self, node): 0353 self.set_lineno(node) 0354 self.scopes = self.parseSymbols(node) 0355 self.scope = self.scopes[node] 0356 self.visit(node.node) 0357 self.emit('RETURN_VALUE') 0358 0359 def visitFunction(self, node): 0360 self._visitFuncOrLambda(node, isLambda=0) 0361 if node.doc: 0362 self.setDocstring(node.doc) 0363 self.storeName(node.name) 0364 0365 def visitLambda(self, node): 0366 self._visitFuncOrLambda(node, isLambda=1) 0367 0368 def _visitFuncOrLambda(self, node, isLambda=0): 0369 if not isLambda and node.decorators: 0370 for decorator in node.decorators.nodes: 0371 self.visit(decorator) 0372 ndecorators = len(node.decorators.nodes) 0373 else: 0374 ndecorators = 0 0375 0376 gen = self.FunctionGen(node, self.scopes, isLambda, 0377 self.class_name, self.get_module()) 0378 walk(node.code, gen) 0379 gen.finish() 0380 self.set_lineno(node) 0381 for default in node.defaults: 0382 self.visit(default) 0383 frees = gen.scope.get_free_vars() 0384 if frees: 0385 for name in frees: 0386 self.emit('LOAD_CLOSURE', name) 0387 self.emit('LOAD_CONST', gen) 0388 self.emit('MAKE_CLOSURE', len(node.defaults)) 0389 else: 0390 self.emit('LOAD_CONST', gen) 0391 self.emit('MAKE_FUNCTION', len(node.defaults)) 0392 0393 for i in range(ndecorators): 0394 self.emit('CALL_FUNCTION', 1) 0395 0396 def visitClass(self, node): 0397 gen = self.ClassGen(node, self.scopes, 0398 self.get_module()) 0399 walk(node.code, gen) 0400 gen.finish() 0401 self.set_lineno(node) 0402 self.emit('LOAD_CONST', node.name) 0403 for base in node.bases: 0404 self.visit(base) 0405 self.emit('BUILD_TUPLE', len(node.bases)) 0406 frees = gen.scope.get_free_vars() 0407 for name in frees: 0408 self.emit('LOAD_CLOSURE', name) 0409 self.emit('LOAD_CONST', gen) 0410 if frees: 0411 self.emit('MAKE_CLOSURE', 0) 0412 else: 0413 self.emit('MAKE_FUNCTION', 0) 0414 self.emit('CALL_FUNCTION', 0) 0415 self.emit('BUILD_CLASS') 0416 self.storeName(node.name) 0417 0418 # The rest are standard visitor methods 0419 0420 # The next few implement control-flow statements 0421 0422 def visitIf(self, node): 0423 end = self.newBlock() 0424 numtests = len(node.tests) 0425 for i in range(numtests): 0426 test, suite = node.tests[i] 0427 if is_constant_false(test): 0428 # XXX will need to check generator stuff here 0429 continue 0430 self.set_lineno(test) 0431 self.visit(test) 0432 nextTest = self.newBlock() 0433 self.emit('JUMP_IF_FALSE', nextTest) 0434 self.nextBlock() 0435 self.emit('POP_TOP') 0436 self.visit(suite) 0437 self.emit('JUMP_FORWARD', end) 0438 self.startBlock(nextTest) 0439 self.emit('POP_TOP') 0440 if node.else_: 0441 self.visit(node.else_) 0442 self.nextBlock(end) 0443 0444 def visitWhile(self, node): 0445 self.set_lineno(node) 0446 0447 loop = self.newBlock() 0448 else_ = self.newBlock() 0449 0450 after = self.newBlock() 0451 self.emit('SETUP_LOOP', after) 0452 0453 self.nextBlock(loop) 0454 self.setups.push((LOOP, loop)) 0455 0456 self.set_lineno(node, force=True) 0457 self.visit(node.test) 0458 self.emit('JUMP_IF_FALSE', else_ or after) 0459 0460 self.nextBlock() 0461 self.emit('POP_TOP') 0462 self.visit(node.body) 0463 self.emit('JUMP_ABSOLUTE', loop) 0464 0465 self.startBlock(else_) # or just the POPs if not else clause 0466 self.emit('POP_TOP') 0467 self.emit('POP_BLOCK') 0468 self.setups.pop() 0469 if node.else_: 0470 self.visit(node.else_) 0471 self.nextBlock(after) 0472 0473 def visitFor(self, node): 0474 start = self.newBlock() 0475 anchor = self.newBlock() 0476 after = self.newBlock() 0477 self.setups.push((LOOP, start)) 0478 0479 self.set_lineno(node) 0480 self.emit('SETUP_LOOP', after) 0481 self.visit(node.list) 0482 self.emit('GET_ITER') 0483 0484 self.nextBlock(start) 0485 self.set_lineno(node, force=1) 0486 self.emit('FOR_ITER', anchor) 0487 self.visit(node.assign) 0488 self.visit(node.body) 0489 self.emit('JUMP_ABSOLUTE', start) 0490 self.nextBlock(anchor) 0491 self.emit('POP_BLOCK') 0492 self.setups.pop() 0493 if node.else_: 0494 self.visit(node.else_) 0495 self.nextBlock(after) 0496 0497 def visitBreak(self, node): 0498 if not self.setups: 0499 raise SyntaxError, "'break' outside loop (%s, %d)" % \ 0500 (node.filename, node.lineno) 0501 self.set_lineno(node) 0502 self.emit('BREAK_LOOP') 0503 0504 def visitContinue(self, node): 0505 if not self.setups: 0506 raise SyntaxError, "'continue' outside loop (%s, %d)" % \ 0507 (node.filename, node.lineno) 0508 kind, block = self.setups.top() 0509 if kind == LOOP: 0510 self.set_lineno(node) 0511 self.emit('JUMP_ABSOLUTE', block) 0512 self.nextBlock() 0513 elif kind == EXCEPT or kind == TRY_FINALLY: 0514 self.set_lineno(node) 0515 # find the block that starts the loop 0516 top = len(self.setups) 0517 while top > 0: 0518 top = top - 1 0519 kind, loop_block = self.setups[top] 0520 if kind == LOOP: 0521 break 0522 if kind != LOOP: 0523 raise SyntaxError, "'continue' outside loop (%s, %d)" % \ 0524 (node.filename, node.lineno) 0525 self.emit('CONTINUE_LOOP', loop_block) 0526 self.nextBlock() 0527 elif kind == END_FINALLY: 0528 msg = "'continue' not allowed inside 'finally' clause (%s, %d)" 0529 raise SyntaxError, msg % (node.filename, node.lineno) 0530 0531 def visitTest(self, node, jump): 0532 end = self.newBlock() 0533 for child in node.nodes[:-1]: 0534 self.visit(child) 0535 self.emit(jump, end) 0536 self.nextBlock() 0537 self.emit('POP_TOP') 0538 self.visit(node.nodes[-1]) 0539 self.nextBlock(end) 0540 0541 def visitAnd(self, node): 0542 self.visitTest(node, 'JUMP_IF_FALSE') 0543 0544 def visitOr(self, node): 0545 self.visitTest(node, 'JUMP_IF_TRUE') 0546 0547 def visitCompare(self, node): 0548 self.visit(node.expr) 0549 cleanup = self.newBlock() 0550 for op, code in node.ops[:-1]: 0551 self.visit(code) 0552 self.emit('DUP_TOP') 0553 self.emit('ROT_THREE') 0554 self.emit('COMPARE_OP', op) 0555 self.emit('JUMP_IF_FALSE', cleanup) 0556 self.nextBlock() 0557 self.emit('POP_TOP') 0558 # now do the last comparison 0559 if node.ops: 0560 op, code = node.ops[-1] 0561 self.visit(code) 0562 self.emit('COMPARE_OP', op) 0563 if len(node.ops) > 1: 0564 end = self.newBlock() 0565 self.emit('JUMP_FORWARD', end) 0566 self.startBlock(cleanup) 0567 self.emit('ROT_TWO') 0568 self.emit('POP_TOP') 0569 self.nextBlock(end) 0570 0571 # list comprehensions 0572 __list_count = 0 0573 0574 def visitListComp(self, node): 0575 self.set_lineno(node) 0576 # setup list 0577 append = "$append%d" % self.__list_count 0578 self.__list_count = self.__list_count + 1 0579 self.emit('BUILD_LIST', 0) 0580 self.emit('DUP_TOP') 0581 self.emit('LOAD_ATTR', 'append') 0582 self._implicitNameOp('STORE', append) 0583 0584 stack = [] 0585 for i, for_ in zip(range(len(node.quals)), node.quals): 0586 start, anchor = self.visit(for_) 0587 cont = None 0588 for if_ in for_.ifs: 0589 if cont is None: 0590 cont = self.newBlock() 0591 self.visit(if_, cont) 0592 stack.insert(0, (start, cont, anchor)) 0593 0594 self._implicitNameOp('LOAD', append) 0595 self.visit(node.expr) 0596 self.emit('CALL_FUNCTION', 1) 0597 self.emit('POP_TOP') 0598 0599 for start, cont, anchor in stack: 0600 if cont: 0601 skip_one = self.newBlock() 0602 self.emit('JUMP_FORWARD', skip_one) 0603 self.startBlock(cont) 0604 self.emit('POP_TOP') 0605 self.nextBlock(skip_one) 0606 self.emit('JUMP_ABSOLUTE', start) 0607 self.startBlock(anchor) 0608 self._implicitNameOp('DELETE', append) 0609 0610 self.__list_count = self.__list_count - 1 0611 0612 def visitListCompFor(self, node): 0613 start = self.newBlock() 0614 anchor = self.newBlock() 0615 0616 self.visit(node.list) 0617 self.emit('GET_ITER') 0618 self.nextBlock(start) 0619 self.set_lineno(node, force=True) 0620 self.emit('FOR_ITER', anchor) 0621 self.nextBlock() 0622 self.visit(node.assign) 0623 return start, anchor 0624 0625 def visitListCompIf(self, node, branch): 0626 self.set_lineno(node, force=True) 0627 self.visit(node.test) 0628 self.emit('JUMP_IF_FALSE', branch) 0629 self.newBlock() 0630 self.emit('POP_TOP') 0631 0632 def visitGenExpr(self, node): 0633 gen = GenExprCodeGenerator(node, self.scopes, self.class_name, 0634 self.get_module()) 0635 walk(node.code, gen) 0636 gen.finish() 0637 self.set_lineno(node) 0638 frees = gen.scope.get_free_vars() 0639 if frees: 0640 for name in frees: 0641 self.emit('LOAD_CLOSURE', name) 0642 self.emit('LOAD_CONST', gen) 0643 self.emit('MAKE_CLOSURE', 0) 0644 else: 0645 self.emit('LOAD_CONST', gen) 0646 self.emit('MAKE_FUNCTION', 0) 0647 0648 # precomputation of outmost iterable 0649 self.visit(node.code.quals[0].iter) 0650 self.emit('GET_ITER') 0651 self.emit('CALL_FUNCTION', 1) 0652 0653 def visitGenExprInner(self, node): 0654 self.set_lineno(node) 0655 # setup list 0656 0657 stack = [] 0658 for i, for_ in zip(range(len(node.quals)), node.quals): 0659 start, anchor = self.visit(for_) 0660 cont = None 0661 for if_ in for_.ifs: 0662 if cont is None: 0663 cont = self.newBlock() 0664 self.visit(if_, cont) 0665 stack.insert(0, (start, cont, anchor)) 0666 0667 self.visit(node.expr) 0668 self.emit('YIELD_VALUE') 0669 0670 for start, cont, anchor in stack: 0671 if cont: 0672 skip_one = self.newBlock() 0673 self.emit('JUMP_FORWARD', skip_one) 0674 self.startBlock(cont) 0675 self.emit('POP_TOP') 0676 self.nextBlock(skip_one) 0677 self.emit('JUMP_ABSOLUTE', start) 0678 self.startBlock(anchor) 0679 self.emit('LOAD_CONST', None) 0680 0681 def visitGenExprFor(self, node): 0682 start = self.newBlock() 0683 anchor = self.newBlock() 0684 0685 if node.is_outmost: 0686 self.loadName('[outmost-iterable]') 0687 else: 0688 self.visit(node.iter) 0689 self.emit('GET_ITER') 0690 0691 self.nextBlock(start) 0692 self.set_lineno(node, force=True) 0693 self.emit('FOR_ITER', anchor) 0694 self.nextBlock() 0695 self.visit(node.assign) 0696 return start, anchor 0697 0698 def visitGenExprIf(self, node, branch): 0699 self.set_lineno(node, force=True) 0700 self.visit(node.test) 0701 self.emit('JUMP_IF_FALSE', branch) 0702 self.newBlock() 0703 self.emit('POP_TOP') 0704 0705 # exception related 0706 0707 def visitAssert(self, node): 0708 # XXX would be interesting to implement this via a 0709 # transformation of the AST before this stage 0710 if __debug__: 0711 end = self.newBlock() 0712 self.set_lineno(node) 0713 # XXX AssertionError appears to be special case -- it is always 0714 # loaded as a global even if there is a local name. I guess this 0715 # is a sort of renaming op. 0716 self.nextBlock() 0717 self.visit(node.test) 0718 self.emit('JUMP_IF_TRUE', end) 0719 self.nextBlock() 0720 self.emit('POP_TOP') 0721 self.emit('LOAD_GLOBAL', 'AssertionError') 0722 if node.fail: 0723 self.visit(node.fail) 0724 self.emit('RAISE_VARARGS', 2) 0725 else: 0726 self.emit('RAISE_VARARGS', 1) 0727 self.nextBlock(end) 0728 self.emit('POP_TOP') 0729 0730 def visitRaise(self, node): 0731 self.set_lineno(node) 0732 n = 0 0733 if node.expr1: 0734 self.visit(node.expr1) 0735 n = n + 1 0736 if node.expr2: 0737 self.visit(node.expr2) 0738 n = n + 1 0739 if node.expr3: 0740 self.visit(node.expr3) 0741 n = n + 1 0742 self.emit('RAISE_VARARGS', n) 0743 0744 def visitTryExcept(self, node): 0745 body = self.newBlock() 0746 handlers = self.newBlock() 0747 end = self.newBlock() 0748 if node.else_: 0749 lElse = self.newBlock() 0750 else: 0751 lElse = end 0752 self.set_lineno(node) 0753 self.emit('SETUP_EXCEPT', handlers) 0754 self.nextBlock(body) 0755 self.setups.push((EXCEPT, body)) 0756 self.visit(node.body) 0757 self.emit('POP_BLOCK') 0758 self.setups.pop() 0759 self.emit('JUMP_FORWARD', lElse) 0760 self.startBlock(handlers) 0761 0762 last = len(node.handlers) - 1 0763 for i in range(len(node.handlers)): 0764 expr, target, body = node.handlers[i] 0765 self.set_lineno(expr) 0766 if expr: 0767 self.emit('DUP_TOP') 0768 self.visit(expr) 0769 self.emit('COMPARE_OP', 'exception match') 0770 next = self.newBlock() 0771 self.emit('JUMP_IF_FALSE', next) 0772 self.nextBlock() 0773 self.emit('POP_TOP') 0774 self.emit('POP_TOP') 0775 if target: 0776 self.visit(target) 0777 else: 0778 self.emit('POP_TOP') 0779 self.emit('POP_TOP') 0780 self.visit(body) 0781 self.emit('JUMP_FORWARD', end) 0782 if expr: 0783 self.nextBlock(next) 0784 else: 0785 self.nextBlock() 0786 if expr: # XXX 0787 self.emit('POP_TOP') 0788 self.emit('END_FINALLY') 0789 if node.else_: 0790 self.nextBlock(lElse) 0791 self.visit(node.else_) 0792 self.nextBlock(end) 0793 0794 def visitTryFinally(self, node): 0795 body = self.newBlock() 0796 final = self.newBlock() 0797 self.set_lineno(node) 0798 self.emit('SETUP_FINALLY', final) 0799 self.nextBlock(body) 0800 self.setups.push((TRY_FINALLY, body)) 0801 self.visit(node.body) 0802 self.emit('POP_BLOCK') 0803 self.setups.pop() 0804 self.emit('LOAD_CONST', None) 0805 self.nextBlock(final) 0806 self.setups.push((END_FINALLY, final)) 0807 self.visit(node.final) 0808 self.emit('END_FINALLY') 0809 self.setups.pop() 0810 0811 # misc 0812 0813 def visitDiscard(self, node): 0814 self.set_lineno(node) 0815 self.visit(node.expr) 0816 self.emit('POP_TOP') 0817 0818 def visitConst(self, node): 0819 self.emit('LOAD_CONST', node.value) 0820 0821 def visitKeyword(self, node): 0822 self.emit('LOAD_CONST', node.name) 0823 self.visit(node.expr) 0824 0825 def visitGlobal(self, node): 0826 # no code to generate 0827 pass 0828 0829 def visitName(self, node): 0830 self.set_lineno(node) 0831 self.loadName(node.name) 0832 0833 def visitPass(self, node): 0834 self.set_lineno(node) 0835 0836 def visitImport(self, node): 0837 self.set_lineno(node) 0838 for name, alias in node.names: 0839 if VERSION > 1: 0840 self.emit('LOAD_CONST', None) 0841 self.emit('IMPORT_NAME', name) 0842 mod = name.split(".")[0] 0843 if alias: 0844 self._resolveDots(name) 0845 self.storeName(alias) 0846 else: 0847 self.storeName(mod) 0848 0849 def visitFrom(self, node): 0850 self.set_lineno(node) 0851 fromlist = map(lambda (name, alias): name, node.names) 0852 if VERSION > 1: 0853 self.emit('LOAD_CONST', tuple(fromlist)) 0854 self.emit('IMPORT_NAME', node.modname) 0855 for name, alias in node.names: 0856 if VERSION > 1: 0857 if name == '*': 0858 self.namespace = 0 0859 self.emit('IMPORT_STAR') 0860 # There can only be one name w/ from ... import * 0861 assert len(node.names) == 1 0862 return 0863 else: 0864 self.emit('IMPORT_FROM', name) 0865 self._resolveDots(name) 0866 self.storeName(alias or name) 0867 else: 0868 self.emit('IMPORT_FROM', name) 0869 self.emit('POP_TOP') 0870 0871 def _resolveDots(self, name): 0872 elts = name.split(".") 0873 if len(elts) == 1: 0874 return 0875 for elt in elts[1:]: 0876 self.emit('LOAD_ATTR', elt) 0877 0878 def visitGetattr(self, node): 0879 self.visit(node.expr) 0880 self.emit('LOAD_ATTR', self.mangle(node.attrname)) 0881 0882 # next five implement assignments 0883 0884 def visitAssign(self, node): 0885 self.set_lineno(node) 0886 self.visit(node.expr) 0887 dups = len(node.nodes) - 1 0888 for i in range(len(node.nodes)): 0889 elt = node.nodes[i] 0890 if i < dups: 0891 self.emit('DUP_TOP') 0892 if isinstance(elt, ast.Node): 0893 self.visit(elt) 0894 0895 def visitAssName(self, node): 0896 if node.flags == 'OP_ASSIGN': 0897 self.storeName(node.name) 0898 elif node.flags == 'OP_DELETE': 0899 self.set_lineno(node) 0900 self.delName(node.name) 0901 else: 0902 print "oops", node.flags 0903 0904 def visitAssAttr(self, node): 0905 self.visit(node.expr) 0906 if node.flags == 'OP_ASSIGN': 0907 self.emit('STORE_ATTR', self.mangle(node.attrname)) 0908 elif node.flags == 'OP_DELETE': 0909 self.emit('DELETE_ATTR', self.mangle(node.attrname)) 0910 else: 0911 print "warning: unexpected flags:", node.flags 0912 print node 0913 0914 def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'): 0915 if findOp(node) != 'OP_DELETE': 0916 self.emit(op, len(node.nodes)) 0917 for child in node.nodes: 0918 self.visit(child) 0919 0920 if VERSION > 1: 0921 visitAssTuple = _visitAssSequence 0922 visitAssList = _visitAssSequence 0923 else: 0924 def visitAssTuple(self, node): 0925 self._visitAssSequence(node, 'UNPACK_TUPLE') 0926 0927 def visitAssList(self, node): 0928 self._visitAssSequence(node, 'UNPACK_LIST') 0929 0930 # augmented assignment 0931 0932 def visitAugAssign(self, node): 0933 self.set_lineno(node) 0934 aug_node = wrap_aug(node.node) 0935 self.visit(aug_node, "load") 0936 self.visit(node.expr) 0937 self.emit(self._augmented_opcode[node.op]) 0938 self.visit(aug_node, "store") 0939 0940 _augmented_opcode = { 0941 '+=' : 'INPLACE_ADD', 0942 '-=' : 'INPLACE_SUBTRACT', 0943 '*=' : 'INPLACE_MULTIPLY', 0944 '/=' : 'INPLACE_DIVIDE', 0945 '//=': 'INPLACE_FLOOR_DIVIDE', 0946 '%=' : 'INPLACE_MODULO', 0947 '**=': 'INPLACE_POWER', 0948 '>>=': 'INPLACE_RSHIFT', 0949 '<<=': 'INPLACE_LSHIFT', 0950 '&=' : 'INPLACE_AND', 0951 '^=' : 'INPLACE_XOR', 0952 '|=' : 'INPLACE_OR', 0953 } 0954 0955 def visitAugName(self, node, mode): 0956 if mode == "load": 0957 self.loadName(node.name) 0958 elif mode == "store": 0959 self.storeName(node.name) 0960 0961 def visitAugGetattr(self, node, mode): 0962 if mode == "load": 0963 self.visit(node.expr) 0964 self.emit('DUP_TOP') 0965 self.emit('LOAD_ATTR', self.mangle(node.attrname)) 0966 elif mode == "store": 0967 self.emit('ROT_TWO') 0968 self.emit('STORE_ATTR', self.mangle(node.attrname)) 0969 0970 def visitAugSlice(self, node, mode): 0971 if mode == "load": 0972 self.visitSlice(node, 1) 0973 elif mode == "store": 0974 slice = 0 0975 if node.lower: 0976 slice = slice | 1 0977 if node.upper: 0978 slice = slice | 2 0979 if slice == 0: 0980 self.emit('ROT_TWO') 0981 elif slice == 3: 0982 self.emit('ROT_FOUR') 0983 else: 0984 self.emit('ROT_THREE') 0985 self.emit('STORE_SLICE+%d' % slice) 0986 0987 def visitAugSubscript(self, node, mode): 0988 if len(node.subs) > 1: 0989 raise SyntaxError, "augmented assignment to tuple is not possible" 0990 if mode == "load": 0991 self.visitSubscript(node, 1) 0992 elif mode == "store": 0993 self.emit('ROT_THREE') 0994 self.emit('STORE_SUBSCR') 0995 0996 def visitExec(self, node): 0997 self.visit(node.expr) 0998 if node.locals is None: 0999 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 1212 class 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 1219 class 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 1233 class 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 1247 class 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 1270 class 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 1332 class 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 1348 class 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 1363 class 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 1385 class 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 1404 def 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 1421 def 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 1427 class 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 1438 class 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 1455 class AugGetattr(Delegator): 1456 pass 1457 1458 class AugName(Delegator): 1459 pass 1460 1461 class AugSlice(Delegator): 1462 pass 1463 1464 class AugSubscript(Delegator): 1465 pass 1466 1467 wrapper = { 1468 ast.Getattr: AugGetattr, 1469 ast.Name: AugName, 1470 ast.Slice: AugSlice, 1471 ast.Subscript: AugSubscript, 1472 } 1473 1474 def wrap_aug(node): 1475 return wrapper[node.__class__](node) 1476 1477 if __name__ == "__main__": 1478 for file in sys.argv[1:]: 1479 compileFile(file) 1480
Generated by PyXR 0.9.4