# find the block that starts the loop top = len(self.setups) while top > 0: top = top - 1 kind, loop_block = self.setups[top] if kind == LOOP: break if kind != LOOP: raise SyntaxError, "'continue' outside loop (%s, %d)" % \ (node.filename, node.lineno) self.emit('CONTINUE_LOOP', loop_block) self.nextBlock() elif kind == END_FINALLY: msg = "'continue' not allowed inside 'finally' clause (%s, %d)" raise SyntaxError, msg % (node.filename, node.lineno) def visitTest(self, node, jump): end = self.newBlock() for child in node.nodes[:-1]: self.visit(child) self.emit(jump, end) self.nextBlock() self.emit('POP_TOP') self.visit(node.nodes[-1]) self.nextBlock(end) def visitAnd(self, node): self.visitTest(node, 'JUMP_IF_FALSE') def visitOr(self, node): self.visitTest(node, 'JUMP_IF_TRUE') def visitIfExp(self, node): endblock = self.newBlock() elseblock = self.newBlock() self.visit(node.test) self.emit('JUMP_IF_FALSE', elseblock) self.emit('POP_TOP') self.visit(node.then) self.emit('JUMP_FORWARD', endblock) self.nextBlock(elseblock) self.emit('POP_TOP') self.visit(node.else_) self.nextBlock(endblock) def visitCompare(self, node): self.visit(node.expr) cleanup = self.newBlock() for op, code in node.ops[:-1]: self.visit(code) self.emit('DUP_TOP') self.emit('ROT_THREE') self.emit('COMPARE_OP', op) self.emit('JUMP_IF_FALSE', cleanup) self.nextBlock() self.emit('POP_TOP') # now do the last comparison if node.ops: op, code = node.ops[-1] self.visit(code) self.emit('COMPARE_OP', op) if len(node.ops) > 1: end = self.newBlock() self.emit('JUMP_FORWARD', end) self.startBlock(cleanup) self.emit('ROT_TWO') self.emit('POP_TOP') self.nextBlock(end) # list comprehensions __list_count = 0 def visitListComp(self, node): self.set_lineno(node) # setup list append = "$append%d" % self.__list_count self.__list_count = self.__list_count + 1 self.emit('BUILD_LIST', 0) self.emit('DUP_TOP') self.emit('LOAD_ATTR', 'append') self._implicitNameOp('STORE', append) stack = [] for i, for_ in zip(range(len(node.quals)), node.quals): start, anchor = self.visit(for_) cont = None for if_ in for_.ifs: if cont is None: cont = self.newBlock() self.visit(if_, cont) stack.insert(0, (start, cont, anchor)) self._implicitNameOp('LOAD', append) self.visit(node.expr) self.emit('CALL_FUNCTION', 1) self.emit('POP_TOP') for start, cont, anchor in stack: if cont: skip_one = self.newBlock() self.emit('JUMP_FORWARD', skip_one) self.startBlock(cont) self.emit('POP_TOP') self.nextBlock(skip_one) self.emit('JUMP_ABSOLUTE', start) self.startBlock(anchor) self._implicitNameOp('DELETE', append) self.__list_count = self.__list_count - 1 def visitListCompFor(self, node): start = self.newBlock() anchor = self.newBlock() self.visit(node.list) self.emit('GET_ITER') self.nextBlock(start) self.set_lineno(node, force=True) self.emit('FOR_ITER', anchor) self.nextBlock() self.visit(node.assign) return start, anchor def visitListCompIf(self, node, branch): self.set_lineno(node, force=True) self.visit(node.test) self.emit('JUMP_IF_FALSE', branch) self.newBlock() self.emit('POP_TOP') def _makeClosure(self, gen, args): frees = gen.scope.get_free_vars() if frees: for name in frees: self.emit('LOAD_CLOSURE', name) self.emit('BUILD_TUPLE', len(frees)) self.emit('LOAD_CONST', gen) self.emit('MAKE_CLOSURE', args) else: self.emit('LOAD_CONST', gen) self.emit('MAKE_FUNCTION', args) def visitGenExpr(self, node): gen = GenExprCodeGenerator(node, self.scopes, self.class_name, self.get_module()) walk(node.code, gen) gen.finish() self.set_lineno(node) self._makeClosure(gen, 0) # precomputation of outmost iterable self.visit(node.code.quals[0].iter) self.emit('GET_ITER') self.emit('CALL_FUNCTION', 1) def visitGenExprInner(self, node): self.set_lineno(node) # setup list stack = [] for i, for_ in zip(range(len(node.quals)), node.quals): start, anchor, end = self.visit(for_) cont = None for if_ in for_.ifs: if cont is None: cont = self.newBlock() self.visit(if_, cont) stack.insert(0, (start, cont, anchor, end)) self.visit(node.expr) self.emit('YIELD_VALUE') self.emit('POP_TOP') for start, cont, anchor, end in stack: if cont: skip_one = self.newBlock() self.emit('JUMP_FORWARD', skip_one) self.startBlock(cont) self.emit('POP_TOP') self.nextBlock(skip_one) self.emit('JUMP_ABSOLUTE', start) self.startBlock(anchor) self.emit('POP_BLOCK') self.setups.pop() self.startBlock(end) self.emit('LOAD_CONST', None) def visitGenExprFor(self, node): start = self.newBlock() anchor = self.newBlock() end = self.newBlock() self.setups.push((LOOP, start)) self.emit('SETUP_LOOP', end) if node.is_outmost: self.loadName('.0') else: self.visit(node.iter) self.emit('GET_ITER') self.nextBlock(start) self.set_lineno(node, force=True) self.emit('FOR_ITER', anchor) self.nextBlock() self.visit(node.assign) return start, anchor, end def visitGenExprIf(self, node, branch): self.set_lineno(node, force=True) self.visit(node.test) self.emit('JUMP_IF_FALSE', branch) self.newBlock() self.emit('POP_TOP') # exception related def visitAssert(self, node): # XXX would be interesting to implement this via a # transformation of the AST before this stage if __debug__: end = self.newBlock() self.set_lineno(node) # XXX AssertionError appears to be special case -- it is always # loaded as a global even if there is a local name. I guess this # is a sort of renaming op. self.nextBlock() self.visit(node.test) self.emit('JUMP_IF_TRUE', end) self.nextBlock() self.emit('POP_TOP') self.emit('LOAD_GLOBAL', 'AssertionError') if node.fail: self.visit(node.fail) self.emit('RAISE_VARARGS', 2) else: self.emit('RAISE_VARARGS', 1) self.nextBlock(end) self.emit('POP_TOP') def visitRaise(self, node): self.set_lineno(node) n = 0 if node.expr1: self.visit(node.expr1) n = n + 1 if node.expr2: self.visit(node.expr2) n = n + 1 if node.expr3: self.visit(node.expr3) n = n + 1 self.emit('RAISE_VARARGS', n) def visitTryExcept(self, node): body = self.newBlock() handlers = self.newBlock() end = self.newBlock() if node.else_: lElse = self.newBlock() else: lElse = end self.set_lineno(node) self.emit('SETUP_EXCEPT', handlers) self.nextBlock(body) self.setups.push((EXCEPT, body)) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('JUMP_FORWARD', lElse) self.startBlock(handlers) last = len(node.handlers) - 1 for i in range(len(node.handlers)): expr, target, body = node.handlers[i] self.set_lineno(expr) if expr: self.emit('DUP_TOP') self.visit(expr) self.emit('COMPARE_OP', 'exception match') next = self.newBlock() self.emit('JUMP_IF_FALSE', next) self.nextBlock() self.emit('POP_TOP') self.emit('POP_TOP') if target: self.visit(target) else: self.emit('POP_TOP') self.emit('POP_TOP') self.visit(body) self.emit('JUMP_FORWARD', end) if expr: self.nextBlock(next) else: self.nextBlock() if expr: # XXX self.emit('POP_TOP') self.emit('END_FINALLY') if node.else_: self.nextBlock(lElse) self.visit(node.else_) self.nextBlock(end) def visitTryFinally(self, node): body = self.newBlock() final = self.newBlock() self.set_lineno(node) self.emit('SETUP_FINALLY', final) self.nextBlock(body) self.setups.push((TRY_FINALLY, body)) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('LOAD_CONST', None) self.nextBlock(final) self.setups.push((END_FINALLY, final)) self.visit(node.final) self.emit('END_FINALLY') self.setups.pop() __with_count = 0 def visitWith(self, node): body = self.newBlock() final = self.newBlock() exitvar = "$exit%d" % self.__with_count valuevar = "$value%d" % self.__with_count self.__with_count += 1 self.set_lineno(node) self.visit(node.expr) self.emit('DUP_TOP') self.emit('LOAD_ATTR', '__exit__') self._implicitNameOp('STORE', exitvar) self.emit('LOAD_ATTR', '__enter__') self.emit('CALL_FUNCTION', 0) if node.vars is None: self.emit('POP_TOP') else: self._implicitNameOp('STORE', valuevar) self.emit('SETUP_FINALLY', final) self.nextBlock(body) self.setups.push((TRY_FINALLY, body)) if node.vars is not None: self._implicitNameOp('LOAD', valuevar) self._implicitNameOp('DELETE', valuevar) self.visit(node.vars) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('LOAD_CONST', None) self.nextBlock(final) self.setups.push((END_FINALLY, final)) self._implicitNameOp('LOAD', exitvar) self._implicitNameOp('DELETE', exitvar) self.emit('WITH_CLEANUP') self.emit('END_FINALLY') self.setups.pop() self.__with_count -= 1 # misc def visitDiscard(self, node): self.set_lineno(node) self.visit(node.expr) self.emit('POP_TOP') def visitConst(self, node): self.emit('LOAD_CONST', node.value) def visitKeyword(self, node): self.emit('LOAD_CONST', node.name) self.visit(node.expr) def visitGlobal(self, node): # no code to generate pass def visitName(self, node): self.set_lineno(node) self.loadName(node.name) def visitPass(self, node): self.set_lineno(node) def visitImport(self, node): self.set_lineno(node) level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1 for name, alias in node.names: if VERSION > 1: self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', None) self.emit('IMPORT_NAME', name) mod = name.split(".")[0] if alias: self._resolveDots(name) self.storeName(alias) else: self.storeName(mod) def visitFrom(self, node): self.set_lineno(node) level = node.level if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT): level = -1 fromlist = map(lambda (name, alias): name, node.names) if VERSION > 1: self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', tuple(fromlist)) self.emit('IMPORT_NAME', node.modname) for name, alias in node.names: if VERSION > 1: if name == '*': self.namespace = 0 self.emit('IMPORT_STAR') # There can only be one name w/ from ... import * assert len(node.names) == 1 return else: self.emit('IMPORT_FROM', name) self._resolveDots(name) self.storeName(alias or name) else: self.emit('IMPORT_FROM', name) self.emit('POP_TOP') def _resolveDots(self, name): elts = name.split(".") if len(elts) == 1: return for elt in elts[1:]: self.emit('LOAD_ATTR', elt) def visitGetattr(self, node): self.visit(node.expr) self.emit('LOAD_ATTR', self.mangle(node.attrname)) # next five implement assignments def visitAssign(self, node): self.set_lineno(node) self.visit(node.expr) dups = len(node.nodes) - 1 for i in range(len(node.nodes)): elt = node.nodes[i] if i < dups: self.emit('DUP_TOP') if isinstance(elt, ast.Node): self.visit(elt) def visitAssName(self, node): if node.flags == 'OP_ASSIGN': self.storeName(node.name) elif node.flags == 'OP_DELETE': self.set_lineno(node) self.delName(node.name) else: print "oops", node.flags def visitAssAttr(self, node): self.visit(node.expr) if node.flags == 'OP_ASSIGN': self.emit('STORE_ATTR', self.mangle(node.attrname)) elif node.flags == 'OP_DELETE': self.emit('DELETE_ATTR', self.mangle(node.attrname)) else: print "warning: unexpected flags:", node.flags print node def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'): if findOp(node) != 'OP_DELETE': self.emit(op, len(node.nodes)) for child in node.nodes: self.visit(child) if VERSION > 1: visitAssTuple = _visitAssSequence visitAssList = _visitAssSequence else: def visitAssTuple(self, node): self._visitAssSequence(node, 'UNPACK_TUPLE') def visitAssList(self, node): self._visitAssSequence(node, 'UNPACK_LIST') # augmented assignment def visitAugAssign(self, node): self.set_lineno(node) aug_node = wrap_aug(node.node) self.visit(aug_node, "load") self.visit(node.expr) self.emit(self._augmented_opcode[node.op]) self.visit(aug_node, "store") _augmented_opcode = { '+=' : 'INPLACE_ADD', '-=' : 'INPLACE_SUBTRACT', '*=' : 'INPLACE_MULTIPLY', '/=' : 'INPLACE_DIVIDE',Lines 501–1000 of 1533. Previous lines Load more
# find the block that starts the loop top = len(self.setups) while top > 0: top = top - 1 kind, loop_block = self.setups[top] if kind == LOOP: break if kind != LOOP: raise SyntaxError, "'continue' outside loop (%s, %d)" % \ (node.filename, node.lineno) self.emit('CONTINUE_LOOP', loop_block) self.nextBlock() elif kind == END_FINALLY: msg = "'continue' not allowed inside 'finally' clause (%s, %d)" raise SyntaxError, msg % (node.filename, node.lineno) def visitTest(self, node, jump): end = self.newBlock() for child in node.nodes[:-1]: self.visit(child) self.emit(jump, end) self.nextBlock() self.emit('POP_TOP') self.visit(node.nodes[-1]) self.nextBlock(end) def visitAnd(self, node): self.visitTest(node, 'JUMP_IF_FALSE') def visitOr(self, node): self.visitTest(node, 'JUMP_IF_TRUE') def visitIfExp(self, node): endblock = self.newBlock() elseblock = self.newBlock() self.visit(node.test) self.emit('JUMP_IF_FALSE', elseblock) self.emit('POP_TOP') self.visit(node.then) self.emit('JUMP_FORWARD', endblock) self.nextBlock(elseblock) self.emit('POP_TOP') self.visit(node.else_) self.nextBlock(endblock) def visitCompare(self, node): self.visit(node.expr) cleanup = self.newBlock() for op, code in node.ops[:-1]: self.visit(code) self.emit('DUP_TOP') self.emit('ROT_THREE') self.emit('COMPARE_OP', op) self.emit('JUMP_IF_FALSE', cleanup) self.nextBlock() self.emit('POP_TOP') # now do the last comparison if node.ops: op, code = node.ops[-1] self.visit(code) self.emit('COMPARE_OP', op) if len(node.ops) > 1: end = self.newBlock() self.emit('JUMP_FORWARD', end) self.startBlock(cleanup) self.emit('ROT_TWO') self.emit('POP_TOP') self.nextBlock(end) # list comprehensions __list_count = 0 def visitListComp(self, node): self.set_lineno(node) # setup list append = "$append%d" % self.__list_count self.__list_count = self.__list_count + 1 self.emit('BUILD_LIST', 0) self.emit('DUP_TOP') self.emit('LOAD_ATTR', 'append') self._implicitNameOp('STORE', append) stack = [] for i, for_ in zip(range(len(node.quals)), node.quals): start, anchor = self.visit(for_) cont = None for if_ in for_.ifs: if cont is None: cont = self.newBlock() self.visit(if_, cont) stack.insert(0, (start, cont, anchor)) self._implicitNameOp('LOAD', append) self.visit(node.expr) self.emit('CALL_FUNCTION', 1) self.emit('POP_TOP') for start, cont, anchor in stack: if cont: skip_one = self.newBlock() self.emit('JUMP_FORWARD', skip_one) self.startBlock(cont) self.emit('POP_TOP') self.nextBlock(skip_one) self.emit('JUMP_ABSOLUTE', start) self.startBlock(anchor) self._implicitNameOp('DELETE', append) self.__list_count = self.__list_count - 1 def visitListCompFor(self, node): start = self.newBlock() anchor = self.newBlock() self.visit(node.list) self.emit('GET_ITER') self.nextBlock(start) self.set_lineno(node, force=True) self.emit('FOR_ITER', anchor) self.nextBlock() self.visit(node.assign) return start, anchor def visitListCompIf(self, node, branch): self.set_lineno(node, force=True) self.visit(node.test) self.emit('JUMP_IF_FALSE', branch) self.newBlock() self.emit('POP_TOP') def _makeClosure(self, gen, args): frees = gen.scope.get_free_vars() if frees: for name in frees: self.emit('LOAD_CLOSURE', name) self.emit('BUILD_TUPLE', len(frees)) self.emit('LOAD_CONST', gen) self.emit('MAKE_CLOSURE', args) else: self.emit('LOAD_CONST', gen) self.emit('MAKE_FUNCTION', args) def visitGenExpr(self, node): gen = GenExprCodeGenerator(node, self.scopes, self.class_name, self.get_module()) walk(node.code, gen) gen.finish() self.set_lineno(node) self._makeClosure(gen, 0) # precomputation of outmost iterable self.visit(node.code.quals[0].iter) self.emit('GET_ITER') self.emit('CALL_FUNCTION', 1) def visitGenExprInner(self, node): self.set_lineno(node) # setup list stack = [] for i, for_ in zip(range(len(node.quals)), node.quals): start, anchor, end = self.visit(for_) cont = None for if_ in for_.ifs: if cont is None: cont = self.newBlock() self.visit(if_, cont) stack.insert(0, (start, cont, anchor, end)) self.visit(node.expr) self.emit('YIELD_VALUE') self.emit('POP_TOP') for start, cont, anchor, end in stack: if cont: skip_one = self.newBlock() self.emit('JUMP_FORWARD', skip_one) self.startBlock(cont) self.emit('POP_TOP') self.nextBlock(skip_one) self.emit('JUMP_ABSOLUTE', start) self.startBlock(anchor) self.emit('POP_BLOCK') self.setups.pop() self.startBlock(end) self.emit('LOAD_CONST', None) def visitGenExprFor(self, node): start = self.newBlock() anchor = self.newBlock() end = self.newBlock() self.setups.push((LOOP, start)) self.emit('SETUP_LOOP', end) if node.is_outmost: self.loadName('.0') else: self.visit(node.iter) self.emit('GET_ITER') self.nextBlock(start) self.set_lineno(node, force=True) self.emit('FOR_ITER', anchor) self.nextBlock() self.visit(node.assign) return start, anchor, end def visitGenExprIf(self, node, branch): self.set_lineno(node, force=True) self.visit(node.test) self.emit('JUMP_IF_FALSE', branch) self.newBlock() self.emit('POP_TOP') # exception related def visitAssert(self, node): # XXX would be interesting to implement this via a # transformation of the AST before this stage if __debug__: end = self.newBlock() self.set_lineno(node) # XXX AssertionError appears to be special case -- it is always # loaded as a global even if there is a local name. I guess this # is a sort of renaming op. self.nextBlock() self.visit(node.test) self.emit('JUMP_IF_TRUE', end) self.nextBlock() self.emit('POP_TOP') self.emit('LOAD_GLOBAL', 'AssertionError') if node.fail: self.visit(node.fail) self.emit('RAISE_VARARGS', 2) else: self.emit('RAISE_VARARGS', 1) self.nextBlock(end) self.emit('POP_TOP') def visitRaise(self, node): self.set_lineno(node) n = 0 if node.expr1: self.visit(node.expr1) n = n + 1 if node.expr2: self.visit(node.expr2) n = n + 1 if node.expr3: self.visit(node.expr3) n = n + 1 self.emit('RAISE_VARARGS', n) def visitTryExcept(self, node): body = self.newBlock() handlers = self.newBlock() end = self.newBlock() if node.else_: lElse = self.newBlock() else: lElse = end self.set_lineno(node) self.emit('SETUP_EXCEPT', handlers) self.nextBlock(body) self.setups.push((EXCEPT, body)) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('JUMP_FORWARD', lElse) self.startBlock(handlers) last = len(node.handlers) - 1 for i in range(len(node.handlers)): expr, target, body = node.handlers[i] self.set_lineno(expr) if expr: self.emit('DUP_TOP') self.visit(expr) self.emit('COMPARE_OP', 'exception match') next = self.newBlock() self.emit('JUMP_IF_FALSE', next) self.nextBlock() self.emit('POP_TOP') self.emit('POP_TOP') if target: self.visit(target) else: self.emit('POP_TOP') self.emit('POP_TOP') self.visit(body) self.emit('JUMP_FORWARD', end) if expr: self.nextBlock(next) else: self.nextBlock() if expr: # XXX self.emit('POP_TOP') self.emit('END_FINALLY') if node.else_: self.nextBlock(lElse) self.visit(node.else_) self.nextBlock(end) def visitTryFinally(self, node): body = self.newBlock() final = self.newBlock() self.set_lineno(node) self.emit('SETUP_FINALLY', final) self.nextBlock(body) self.setups.push((TRY_FINALLY, body)) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('LOAD_CONST', None) self.nextBlock(final) self.setups.push((END_FINALLY, final)) self.visit(node.final) self.emit('END_FINALLY') self.setups.pop() __with_count = 0 def visitWith(self, node): body = self.newBlock() final = self.newBlock() exitvar = "$exit%d" % self.__with_count valuevar = "$value%d" % self.__with_count self.__with_count += 1 self.set_lineno(node) self.visit(node.expr) self.emit('DUP_TOP') self.emit('LOAD_ATTR', '__exit__') self._implicitNameOp('STORE', exitvar) self.emit('LOAD_ATTR', '__enter__') self.emit('CALL_FUNCTION', 0) if node.vars is None: self.emit('POP_TOP') else: self._implicitNameOp('STORE', valuevar) self.emit('SETUP_FINALLY', final) self.nextBlock(body) self.setups.push((TRY_FINALLY, body)) if node.vars is not None: self._implicitNameOp('LOAD', valuevar) self._implicitNameOp('DELETE', valuevar) self.visit(node.vars) self.visit(node.body) self.emit('POP_BLOCK') self.setups.pop() self.emit('LOAD_CONST', None) self.nextBlock(final) self.setups.push((END_FINALLY, final)) self._implicitNameOp('LOAD', exitvar) self._implicitNameOp('DELETE', exitvar) self.emit('WITH_CLEANUP') self.emit('END_FINALLY') self.setups.pop() self.__with_count -= 1 # misc def visitDiscard(self, node): self.set_lineno(node) self.visit(node.expr) self.emit('POP_TOP') def visitConst(self, node): self.emit('LOAD_CONST', node.value) def visitKeyword(self, node): self.emit('LOAD_CONST', node.name) self.visit(node.expr) def visitGlobal(self, node): # no code to generate pass def visitName(self, node): self.set_lineno(node) self.loadName(node.name) def visitPass(self, node): self.set_lineno(node) def visitImport(self, node): self.set_lineno(node) level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1 for name, alias in node.names: if VERSION > 1: self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', None) self.emit('IMPORT_NAME', name) mod = name.split(".")[0] if alias: self._resolveDots(name) self.storeName(alias) else: self.storeName(mod) def visitFrom(self, node): self.set_lineno(node) level = node.level if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT): level = -1 fromlist = map(lambda (name, alias): name, node.names) if VERSION > 1: self.emit('LOAD_CONST', level) self.emit('LOAD_CONST', tuple(fromlist)) self.emit('IMPORT_NAME', node.modname) for name, alias in node.names: if VERSION > 1: if name == '*': self.namespace = 0 self.emit('IMPORT_STAR') # There can only be one name w/ from ... import * assert len(node.names) == 1 return else: self.emit('IMPORT_FROM', name) self._resolveDots(name) self.storeName(alias or name) else: self.emit('IMPORT_FROM', name) self.emit('POP_TOP') def _resolveDots(self, name): elts = name.split(".") if len(elts) == 1: return for elt in elts[1:]: self.emit('LOAD_ATTR', elt) def visitGetattr(self, node): self.visit(node.expr) self.emit('LOAD_ATTR', self.mangle(node.attrname)) # next five implement assignments def visitAssign(self, node): self.set_lineno(node) self.visit(node.expr) dups = len(node.nodes) - 1 for i in range(len(node.nodes)): elt = node.nodes[i] if i < dups: self.emit('DUP_TOP') if isinstance(elt, ast.Node): self.visit(elt) def visitAssName(self, node): if node.flags == 'OP_ASSIGN': self.storeName(node.name) elif node.flags == 'OP_DELETE': self.set_lineno(node) self.delName(node.name) else: print "oops", node.flags def visitAssAttr(self, node): self.visit(node.expr) if node.flags == 'OP_ASSIGN': self.emit('STORE_ATTR', self.mangle(node.attrname)) elif node.flags == 'OP_DELETE': self.emit('DELETE_ATTR', self.mangle(node.attrname)) else: print "warning: unexpected flags:", node.flags print node def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'): if findOp(node) != 'OP_DELETE': self.emit(op, len(node.nodes)) for child in node.nodes: self.visit(child) if VERSION > 1: visitAssTuple = _visitAssSequence visitAssList = _visitAssSequence else: def visitAssTuple(self, node): self._visitAssSequence(node, 'UNPACK_TUPLE') def visitAssList(self, node): self._visitAssSequence(node, 'UNPACK_LIST') # augmented assignment def visitAugAssign(self, node): self.set_lineno(node) aug_node = wrap_aug(node.node) self.visit(aug_node, "load") self.visit(node.expr) self.emit(self._augmented_opcode[node.op]) self.visit(aug_node, "store") _augmented_opcode = { '+=' : 'INPLACE_ADD', '-=' : 'INPLACE_SUBTRACT', '*=' : 'INPLACE_MULTIPLY', '/=' : 'INPLACE_DIVIDE',