From arigo at codespeak.net Thu Nov 11 11:17:40 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 11 Nov 2004 11:17:40 +0100 (MET) Subject: [pypy-svn] r7207 - pypy/trunk/src/pypy/annotation Message-ID: <20041111101740.EADD85AB59@thoth.codespeak.net> Author: arigo Date: Thu Nov 11 11:17:39 2004 New Revision: 7207 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Added SomeChar annotation for strings of length 1. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 11 11:17:39 2004 @@ -4,7 +4,7 @@ from pypy.annotation.pairtype import pair, pairtype from pypy.annotation.model import SomeObject, SomeInteger, SomeBool -from pypy.annotation.model import SomeString, SomeList, SomeDict +from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod from pypy.annotation.model import SomeBuiltin, SomeIterator @@ -154,6 +154,12 @@ generalize(lst1.factories, s_value) +class __extend__(pairtype(SomeString, SomeInteger)): + + def getitem((str1, int2)): + return SomeChar() + + class __extend__(pairtype(SomeInteger, SomeList)): def mul((int1, lst2)): Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 11 11:17:39 2004 @@ -2,7 +2,7 @@ Built-in functions. """ -from pypy.annotation.model import SomeInteger, SomeObject +from pypy.annotation.model import SomeInteger, SomeObject, SomeChar from pypy.annotation.factory import ListFactory, getbookkeeper import pypy.objspace.std.restricted_int @@ -27,6 +27,9 @@ def restricted_uint(s_obj): # for r_uint return SomeInteger(nonneg=True, unsigned=True) +def builtin_chr(s_int): + return SomeChar() + # collect all functions import __builtin__ Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 11 11:17:39 2004 @@ -69,6 +69,9 @@ "Stands for an object which is known to be a string." knowntype = str +class SomeChar(SomeString): + "Stands for an object known to be a string of length 1." + class SomeList(SomeObject): "Stands for a homogenous list of any length." knowntype = list Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu Nov 11 11:17:39 2004 @@ -5,7 +5,7 @@ from types import FunctionType from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeObject, SomeInteger, SomeBool -from pypy.annotation.model import SomeString, SomeList, SomeDict +from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass from pypy.annotation.model import SomeFunction, SomeMethod, SomeIterator @@ -68,6 +68,18 @@ return SomeIterator(lst.s_item) +class __extend__(SomeString): + + def iter(str): + return SomeIterator(SomeChar()) + + +class __extend__(SomeChar): + + def len(chr): + return immutablevalue(1) + + class __extend__(SomeIterator): def next(itr): From arigo at codespeak.net Thu Nov 11 11:20:50 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 11 Nov 2004 11:20:50 +0100 (MET) Subject: [pypy-svn] r7208 - pypy/trunk/src/pypy/translator Message-ID: <20041111102050.7B03A5B16B@thoth.codespeak.net> Author: arigo Date: Thu Nov 11 11:20:49 2004 New Revision: 7208 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/transform.py Log: - disabled the list_extend transformation; it should be done differently. - record in the annotator from which function each block comes from. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Thu Nov 11 11:20:49 2004 @@ -232,7 +232,7 @@ # * self.annotated[block] == False: # the input variables of the block are in self.bindings but we # still have to consider all the operations in the block. - # * self.annotated[block] == True: + # * self.annotated[block] == : # analysis done (at least until we find we must generalize the # input variables). @@ -242,7 +242,7 @@ elif cells is not None: self.mergeinputargs(block, cells) if not self.annotated[block]: - self.annotated[block] = True + self.annotated[block] = fn try: self.flowin(fn, block) except BlockedInference, e: Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Thu Nov 11 11:20:49 2004 @@ -193,108 +193,108 @@ # | | # `-----' (pass all variables, with i=i1) # -def transform_listextend(self): - allblocks = list(self.annotated) - for block in allblocks: - for j in range(len(block.operations)): - op = block.operations[j] - if op.opname != 'inplace_add': - continue - a = op.result - b, c = op.args - s_list = self.bindings.get(b) - if not isinstance(s_list, annmodel.SomeList): - continue - - # new variables - clen = Variable() - i = Variable() - i1 = Variable() - z = Variable() - x = Variable() - dummy = Variable() - self.setbinding(clen, annmodel.SomeInteger(nonneg=True)) - self.setbinding(i, annmodel.SomeInteger(nonneg=True)) - self.setbinding(i1, annmodel.SomeInteger(nonneg=True)) - self.setbinding(z, annmodel.SomeBool()) - self.setbinding(x, s_list.s_item) - self.setbinding(dummy, annmodel.SomeImpossibleValue()) - - sequel_operations = block.operations[j+1:] - sequel_exitswitch = block.exitswitch - sequel_exits = block.exits - - del block.operations[j:] - block.operations += [ - SpaceOperation('len', [c], clen), - SpaceOperation('growlist', [b, clen], dummy), - ] - block.exitswitch = None - allvars = block.getvariables() - - condition_block = Block(allvars+[i]) - condition_block.operations += [ - SpaceOperation('lt', [i, clen], z), - ] - condition_block.exitswitch = z - - loopbody_block = Block(allvars+[i]) - loopbody_block.operations += [ - SpaceOperation('getitem', [c, i], x), - SpaceOperation('fastappend', [b, x], dummy), - SpaceOperation('add', [i, Constant(1)], i1), - ] - - sequel_block = Block(allvars+[a]) - sequel_block.operations = sequel_operations - sequel_block.exitswitch = sequel_exitswitch - - # link the blocks together - block.recloseblock( - Link(allvars+[Constant(0)], condition_block), - ) - condition_block.closeblock( - Link(allvars+[i], loopbody_block, exitcase=True), - Link(allvars+[b], sequel_block, exitcase=False), - ) - loopbody_block.closeblock( - Link(allvars+[i1], condition_block), - ) - sequel_block.closeblock(*sequel_exits) - - # now rename the variables -- so far all blocks use the - # same variables, which is forbidden - renamevariables(self, condition_block) - renamevariables(self, loopbody_block) - renamevariables(self, sequel_block) - - allblocks.append(sequel_block) - break - -def renamevariables(self, block): - """Utility to rename the variables in a block to fresh variables. - The annotations are carried over from the old to the new vars.""" - varmap = {} - block.inputargs = [varmap.setdefault(a, Variable()) - for a in block.inputargs] - operations = [] - for op in block.operations: - result = varmap.setdefault(op.result, Variable()) - args = [varmap.get(a, a) for a in op.args] - op = SpaceOperation(op.opname, args, result) - operations.append(op) - block.operations = operations - block.exitswitch = varmap.get(block.exitswitch, block.exitswitch) - exits = [] - for exit in block.exits: - args = [varmap.get(a, a) for a in exit.args] - exits.append(Link(args, exit.target, exit.exitcase)) - block.recloseblock(*exits) - # carry over the annotations - for a1, a2 in varmap.items(): - if a1 in self.bindings: - self.setbinding(a2, self.bindings[a1]) - self.annotated[block] = True +##def transform_listextend(self): +## allblocks = list(self.annotated) +## for block in allblocks: +## for j in range(len(block.operations)): +## op = block.operations[j] +## if op.opname != 'inplace_add': +## continue +## a = op.result +## b, c = op.args +## s_list = self.bindings.get(b) +## if not isinstance(s_list, annmodel.SomeList): +## continue + +## # new variables +## clen = Variable() +## i = Variable() +## i1 = Variable() +## z = Variable() +## x = Variable() +## dummy = Variable() +## self.setbinding(clen, annmodel.SomeInteger(nonneg=True)) +## self.setbinding(i, annmodel.SomeInteger(nonneg=True)) +## self.setbinding(i1, annmodel.SomeInteger(nonneg=True)) +## self.setbinding(z, annmodel.SomeBool()) +## self.setbinding(x, s_list.s_item) +## self.setbinding(dummy, annmodel.SomeImpossibleValue()) + +## sequel_operations = block.operations[j+1:] +## sequel_exitswitch = block.exitswitch +## sequel_exits = block.exits + +## del block.operations[j:] +## block.operations += [ +## SpaceOperation('len', [c], clen), +## SpaceOperation('growlist', [b, clen], dummy), +## ] +## block.exitswitch = None +## allvars = block.getvariables() + +## condition_block = Block(allvars+[i]) +## condition_block.operations += [ +## SpaceOperation('lt', [i, clen], z), +## ] +## condition_block.exitswitch = z + +## loopbody_block = Block(allvars+[i]) +## loopbody_block.operations += [ +## SpaceOperation('getitem', [c, i], x), +## SpaceOperation('fastappend', [b, x], dummy), +## SpaceOperation('add', [i, Constant(1)], i1), +## ] + +## sequel_block = Block(allvars+[a]) +## sequel_block.operations = sequel_operations +## sequel_block.exitswitch = sequel_exitswitch + +## # link the blocks together +## block.recloseblock( +## Link(allvars+[Constant(0)], condition_block), +## ) +## condition_block.closeblock( +## Link(allvars+[i], loopbody_block, exitcase=True), +## Link(allvars+[b], sequel_block, exitcase=False), +## ) +## loopbody_block.closeblock( +## Link(allvars+[i1], condition_block), +## ) +## sequel_block.closeblock(*sequel_exits) + +## # now rename the variables -- so far all blocks use the +## # same variables, which is forbidden +## renamevariables(self, condition_block) +## renamevariables(self, loopbody_block) +## renamevariables(self, sequel_block) + +## allblocks.append(sequel_block) +## break + +##def renamevariables(self, block): +## """Utility to rename the variables in a block to fresh variables. +## The annotations are carried over from the old to the new vars.""" +## varmap = {} +## block.inputargs = [varmap.setdefault(a, Variable()) +## for a in block.inputargs] +## operations = [] +## for op in block.operations: +## result = varmap.setdefault(op.result, Variable()) +## args = [varmap.get(a, a) for a in op.args] +## op = SpaceOperation(op.opname, args, result) +## operations.append(op) +## block.operations = operations +## block.exitswitch = varmap.get(block.exitswitch, block.exitswitch) +## exits = [] +## for exit in block.exits: +## args = [varmap.get(a, a) for a in exit.args] +## exits.append(Link(args, exit.target, exit.exitcase)) +## block.recloseblock(*exits) +## # carry over the annotations +## for a1, a2 in varmap.items(): +## if a1 in self.bindings: +## self.setbinding(a2, self.bindings[a1]) +## self.annotated[block] = True def transform_graph(ann): @@ -303,7 +303,7 @@ ann.translator.checkgraphs() transform_allocate(ann) transform_slice(ann) - transform_listextend(ann) + ##transform_listextend(ann) # do this last, after the previous transformations had a # chance to remove dependency on certain variables transform_dead_op_vars(ann) From arigo at codespeak.net Thu Nov 11 11:24:28 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 11 Nov 2004 11:24:28 +0100 (MET) Subject: [pypy-svn] r7209 - in pypy/trunk/src/pypy: interpreter objspace objspace/flow Message-ID: <20041111102428.AD0AC5AF00@thoth.codespeak.net> Author: arigo Date: Thu Nov 11 11:24:28 2004 New Revision: 7209 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/descroperation.py pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: - we were using 'space.id' to implement 'space.is_', but it's really getting in the way of the flow objspace, because the 'id' of a constant object is not constant in general, but the 'is_' of two constant objects has a known answer. Introduced a primitive 'is_' operation and removed the default kind-of-broken implementation. - debugging support for translate_pypy in checkgraph(). - we need to populate more extensively the implicit_exceptions dict. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Thu Nov 11 11:24:28 2004 @@ -110,11 +110,11 @@ # that can be defined in term of more primitive ones. Subclasses # may also override specific functions for performance. - def is_(self, w_x, w_y): - "'x is y'." - w_id_x = self.id(w_x) - w_id_y = self.id(w_y) - return self.eq(w_id_x, w_id_y) + #def is_(self, w_x, w_y): -- not really useful. Must be subclassed + # "'x is y'." + # w_id_x = self.id(w_x) + # w_id_y = self.id(w_y) + # return self.eq(w_id_x, w_id_y) def not_(self, w_obj): return self.wrap(not self.is_true(w_obj)) @@ -238,6 +238,7 @@ ObjSpace.MethodTable = [ # method name # symbol # number of arguments # special method name(s) + ('is_', 'is', 2, []), ('id', 'id', 1, []), ('type', 'type', 1, []), ('issubtype', 'issubtype', 2, []), # not for old-style classes Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Thu Nov 11 11:24:28 2004 @@ -423,7 +423,7 @@ _impl_maker = _make_unaryop_impl if _impl_maker: setattr(DescrOperation,_name,_impl_maker(_symbol,_specialnames)) - elif _name not in ['id','type','issubtype', + elif _name not in ['is_', 'id','type','issubtype', # not really to be defined in DescrOperation 'ord','round']: raise Exception,"missing def for operation%s" % _name Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Thu Nov 11 11:24:28 2004 @@ -243,16 +243,12 @@ def checkgraph(graph): "Check the consistency of a flow graph." if __debug__: + this_block = [None] exitblocks = [graph.returnblock] + graph.exceptblocks.values() - for block in exitblocks: - assert len(block.inputargs) == 1 - assert not block.operations - assert not block.exits - - vars_previous_blocks = {} - + def visit(block): if isinstance(block, Block): + this_block[0] = block assert bool(block.isstartblock) == (block is graph.startblock) if not block.exits: assert block in exitblocks @@ -291,4 +287,19 @@ assert v in vars vars_previous_blocks.update(vars) - traverse(visit, graph) + try: + for block in exitblocks: + this_block[0] = block + assert len(block.inputargs) == 1 + assert not block.operations + assert not block.exits + + vars_previous_blocks = {} + + traverse(visit, graph) + + except AssertionError, e: + # hack for debug tools only + if this_block[0] and not hasattr(e, '__annotator_block'): + setattr(e, '__annotator_block', this_block[0]) + raise Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Nov 11 11:24:28 2004 @@ -182,7 +182,7 @@ # ______________________________________________________________________ implicit_exceptions = { - 'getitem': [IndexError], + 'getitem': [IndexError, KeyError], } def extract_cell_content(c): @@ -207,8 +207,8 @@ # op = apply if name == 'issubtype': op = issubclass - elif name == 'id': - op = id + elif name == 'is_': + op = lambda x, y: x is y elif name == 'getattr': op = getattr else: From arigo at codespeak.net Thu Nov 11 11:25:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 11 Nov 2004 11:25:45 +0100 (MET) Subject: [pypy-svn] r7210 - pypy/trunk/src/goal Message-ID: <20041111102545.743ED5B16F@thoth.codespeak.net> Author: arigo Date: Thu Nov 11 11:25:45 2004 New Revision: 7210 Modified: pypy/trunk/src/goal/translate_pypy.py Log: - fixed a bug with the debugging support :-) - try (unsuccessfully so far, of course) to generate C code instead of Pyrex. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Thu Nov 11 11:25:45 2004 @@ -20,11 +20,11 @@ # __________ Main __________ def analyse(entry_point=entry_point): + global t t = Translator(entry_point, verbose=True, simplifying=True) space = StdObjSpace() a = t.annotate([annmodel.immutablevalue(space)]) a.simplify() - return t if __name__ == '__main__': @@ -80,9 +80,10 @@ pdb.post_mortem(tb) try: - t = analyse() + analyse() print '-'*60 - t.compile() + print 'Generating C code...' + t.ccompile() except: debug() else: From arigo at codespeak.net Fri Nov 12 11:51:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 12 Nov 2004 11:51:34 +0100 (MET) Subject: [pypy-svn] r7225 - pypy/trunk/src/pypy/translator Message-ID: <20041112105134.BCAA55A1D3@thoth.codespeak.net> Author: arigo Date: Fri Nov 12 11:51:33 2004 New Revision: 7225 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Oups. Not running the tests before a check-in... Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Nov 12 11:51:33 2004 @@ -232,7 +232,7 @@ # * self.annotated[block] == False: # the input variables of the block are in self.bindings but we # still have to consider all the operations in the block. - # * self.annotated[block] == : + # * self.annotated[block] == True or : # analysis done (at least until we find we must generalize the # input variables). @@ -242,7 +242,7 @@ elif cells is not None: self.mergeinputargs(block, cells) if not self.annotated[block]: - self.annotated[block] = fn + self.annotated[block] = fn or True try: self.flowin(fn, block) except BlockedInference, e: From arigo at codespeak.net Fri Nov 12 12:24:40 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 12 Nov 2004 12:24:40 +0100 (MET) Subject: [pypy-svn] r7226 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041112112440.656D75A2DE@thoth.codespeak.net> Author: arigo Date: Fri Nov 12 12:24:39 2004 New Revision: 7226 Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: Python 2.4 fix. Yet Another Change in distutils breaks code -- this time in Pyrex -- but it's easy to work around it because we don't really need this Pyrex code, which was an extension to allow direct .pyx->.so generation. We are going through C anyway. Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Fri Nov 12 12:24:39 2004 @@ -20,15 +20,14 @@ i+=1 pyxfile.write(string) if debug: print "made pyxfile", pyxfile - make_c_from_pyxfile(pyxfile) - module = make_module_from_c(pyxfile) + cfile = make_c_from_pyxfile(pyxfile) + module = make_module_from_c(cfile) #print "made module", module return module -def make_module_from_c(pyxfile): +def make_module_from_c(cfile): from distutils.core import setup from distutils.extension import Extension - from Pyrex.Distutils import build_ext #try: # from distutils.log import set_threshold @@ -37,11 +36,11 @@ # print "ERROR IMPORTING" # pass - dirpath = pyxfile.dirpath() + dirpath = cfile.dirpath() lastdir = path.local() os.chdir(str(dirpath)) try: - modname = pyxfile.get('purebasename') + modname = cfile.get('purebasename') if debug: print "modname", modname c = stdoutcapture.Capture(mixed_out_err = True) try: @@ -49,9 +48,8 @@ setup( name = "testmodules", ext_modules=[ - Extension(modname, [str(pyxfile)]) + Extension(modname, [str(cfile)]) ], - cmdclass = {'build_ext': build_ext}, script_name = 'setup.py', script_args = ['-q', 'build_ext', '--inplace'] #script_args = ['build_ext', '--inplace'] @@ -88,6 +86,7 @@ except PyrexError, e: print >>sys.stderr, e cfile = pyxfile.new(ext='.c') + return cfile def build_cfunc(func, simplify=1, dot=1, inputargtypes=None): """ return a pyrex-generated cfunction from the given func. From hpk at codespeak.net Mon Nov 15 10:48:16 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Nov 2004 10:48:16 +0100 (MET) Subject: [pypy-svn] r7230 - pypy/trunk/src/pypy/translator Message-ID: <20041115094816.E876D5B029@thoth.codespeak.net> Author: hpk Date: Mon Nov 15 10:48:15 2004 New Revision: 7230 Modified: pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/translator.py Log: don't return the graph for inplace-operations but return None. (the functions in simplify.py modify the graph inplace) Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Mon Nov 15 10:48:15 2004 @@ -81,14 +81,12 @@ traverse(visit, graph) def simplify_graph(graph): - """Apply all the existing optimisations to the graph.""" + """inplace-apply all the existing optimisations to the graph.""" checkgraph(graph) eliminate_empty_blocks(graph) remove_implicit_exceptions(graph) join_blocks(graph) checkgraph(graph) - return graph - def remove_direct_loops(graph): """This is useful for code generators: it ensures that no link has Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Mon Nov 15 10:48:15 2004 @@ -73,7 +73,7 @@ space = FlowObjSpace() graph = space.build_flow(func) if self.simplifying: - graph = simplify_graph(graph) + simplify_graph(graph) self.flowgraphs[func] = graph self.functions.append(func) try: @@ -115,7 +115,7 @@ self.simplify(func) else: graph = self.getflowgraph(func) - self.flowgraphs[func] = simplify_graph(graph) + simplify_graph(graph) def annotate(self, input_args_types, func=None): """annotate(self, input_arg_types[, func]) -> Annotator From bob at codespeak.net Mon Nov 15 11:03:05 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 11:03:05 +0100 (MET) Subject: [pypy-svn] r7231 - pypy/trunk/src/goal Message-ID: <20041115100305.BAC1E5B051@thoth.codespeak.net> Author: bob Date: Mon Nov 15 11:03:05 2004 New Revision: 7231 Modified: pypy/trunk/src/goal/translate_pypy.py Log: move pdb to background thread, makes example work on Mac OS X and Win32 Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 15 11:03:05 2004 @@ -51,15 +51,11 @@ return print "don't know about", x - def run_server(background=False): + def run_server(): from pypy.translator.tool.pygame.flowviewer import TranslatorLayout from pypy.translator.tool.pygame.graphdisplay import GraphDisplay display = GraphDisplay(TranslatorLayout(t)) - if background: - import thread - thread.start_new_thread(display.run, ()) - else: - display.run() + display.run() def debug(): import traceback @@ -74,10 +70,11 @@ about(block) print '-'*60 - run_server(background=True) print >> sys.stderr + import thread import pdb - pdb.post_mortem(tb) + thread.start_new_thread(pdb.post_mortem, (tb,)) + run_server() try: analyse() From hpk at codespeak.net Mon Nov 15 11:32:18 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Nov 2004 11:32:18 +0100 (MET) Subject: [pypy-svn] r7232 - in pypy/trunk/src/pypy/interpreter: . test Message-ID: <20041115103218.09D835B112@thoth.codespeak.net> Author: hpk Date: Mon Nov 15 11:32:18 2004 New Revision: 7232 Modified: pypy/trunk/src/pypy/interpreter/pycode.py pypy/trunk/src/pypy/interpreter/test/test_code.py Log: add a 'keys()' method to enhanceclass in order to list all possible arguments for enhanceclass (for the translator to substitute the too-dynamic enhanceclass with a static dict lookup) Modified: pypy/trunk/src/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pycode.py (original) +++ pypy/trunk/src/pypy/interpreter/pycode.py Mon Nov 15 11:32:18 2004 @@ -130,7 +130,6 @@ code.co_cellvars = space.unwrap(w_cellvars) return space.wrap(code) - def enhanceclass(baseclass, newclass, cache={}): # this is a bit too dynamic for RPython, but it looks nice # and I assume that we can easily change it into a static @@ -145,3 +144,16 @@ pass cache[baseclass, newclass] = Mixed return Mixed + +def keys(): + from pypy.interpreter.pyopcode import PyInterpFrame as Frame + from pypy.interpreter.nestedscope import PyNestedScopeFrame + from pypy.interpreter.generator import GeneratorFrame + + return [ + (Frame, PyNestedScopeFrame), + (Frame, GeneratorFrame), + (enhanceclass(Frame, PyNestedScopeFrame), GeneratorFrame), + ] + +enhanceclass.keys = keys Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_code.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_code.py Mon Nov 15 11:32:18 2004 @@ -92,5 +92,15 @@ exec co in d self.assertEquals(d['c'], 3) +class TestCodeEnhanceClass(testit.IntTestCase): + def test_enhanceclass_for_translator(self): + from pypy.interpreter.pycode import enhanceclass + assert hasattr(enhanceclass, 'keys') + arglist = enhanceclass.keys() + for args in arglist: + enhanceclass(*args) + + + if __name__ == '__main__': testit.main() From bob at codespeak.net Mon Nov 15 11:32:39 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 11:32:39 +0100 (MET) Subject: [pypy-svn] r7233 - in pypy/trunk/src/pypy: tool translator/tool/pygame Message-ID: <20041115103239.7B0375B116@thoth.codespeak.net> Author: bob Date: Mon Nov 15 11:32:39 2004 New Revision: 7233 Added: pypy/trunk/src/pypy/tool/uid.py Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: add a uid function that guarantees to return an unsigned int id of an object make the flowviewer use it Added: pypy/trunk/src/pypy/tool/uid.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/uid.py Mon Nov 15 11:32:39 2004 @@ -0,0 +1,5 @@ +def uid(obj): + rval = id(obj) + if rval < 1: + rval += 1L << 32 + return rval Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Mon Nov 15 11:32:39 2004 @@ -4,6 +4,7 @@ from pypy.translator.tool.make_dot import DotGen from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS from pypy.annotation import model, factory +from pypy.tool.uid import uid class SingleGraphLayout(GraphLayout): @@ -162,7 +163,7 @@ try: return cache[obj] except KeyError: - result = '%s__0x%x' % (getattr(obj, '__name__', ''), id(obj)) + result = '%s__0x%x' % (getattr(obj, '__name__', ''), uid(obj)) cache[obj] = result return result From bob at codespeak.net Mon Nov 15 11:33:05 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 11:33:05 +0100 (MET) Subject: [pypy-svn] r7234 - pypy/trunk/src/pypy/tool Message-ID: <20041115103305.45B2E5B113@thoth.codespeak.net> Author: bob Date: Mon Nov 15 11:33:04 2004 New Revision: 7234 Modified: pypy/trunk/src/pypy/tool/uid.py Log: should be < 0 Modified: pypy/trunk/src/pypy/tool/uid.py ============================================================================== --- pypy/trunk/src/pypy/tool/uid.py (original) +++ pypy/trunk/src/pypy/tool/uid.py Mon Nov 15 11:33:04 2004 @@ -1,5 +1,5 @@ def uid(obj): rval = id(obj) - if rval < 1: + if rval < 0: rval += 1L << 32 return rval From mwh at codespeak.net Mon Nov 15 12:27:38 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 12:27:38 +0100 (MET) Subject: [pypy-svn] r7235 - in pypy/trunk/src/pypy: interpreter objspace/flow Message-ID: <20041115112738.42F875B115@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 12:27:37 2004 New Revision: 7235 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: A rather hackish way for functions to lie to the flow object space about what its code is. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Mon Nov 15 12:27:37 2004 @@ -41,6 +41,7 @@ return self.generalcache[key] except KeyError: return self.generalcache.setdefault(key, builder(key, self)) + loadfromcache.translated_version = lambda s, k, b: s.generalcache[k] def make_builtins(self, for_builtins): # initializing builtins may require creating a frame which in Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Mon Nov 15 12:27:37 2004 @@ -108,6 +108,7 @@ def build_flow(self, func, constargs={}): """ """ + func = getattr(func, "translated_version", func) code = func.func_code code = PyCode()._from_code(code) if func.func_closure is None: From mwh at codespeak.net Mon Nov 15 15:09:48 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 15:09:48 +0100 (MET) Subject: [pypy-svn] r7236 - pypy/trunk/src/pypy/objspace Message-ID: <20041115140948.A97F25B138@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 15:09:48 2004 New Revision: 7236 Modified: pypy/trunk/src/pypy/objspace/descroperation.py Log: whitespace bigotry Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Mon Nov 15 15:09:48 2004 @@ -11,43 +11,43 @@ w_descr = space.lookup(w_obj, name) if w_descr is not None: if space.is_data_descr(w_descr): - return space.get(w_descr,w_obj) + return space.get(w_descr, w_obj) w_dict = space.getdict(w_obj) if w_dict is not None: try: - return space.getitem(w_dict,w_name) + return space.getitem(w_dict, w_name) except OperationError, e: - if not e.match(space,space.w_KeyError): + if not e.match(space, space.w_KeyError): raise if w_descr is not None: - return space.get(w_descr,w_obj) - raise OperationError(space.w_AttributeError,w_name) + return space.get(w_descr, w_obj) + raise OperationError(space.w_AttributeError, w_name) def descr__setattr__(space, w_obj, w_name, w_value): name = space.unwrap(w_name) w_descr = space.lookup(w_obj, name) if w_descr is not None: if space.is_data_descr(w_descr): - return space.set(w_descr,w_obj,w_value) + return space.set(w_descr, w_obj, w_value) w_dict = space.getdict(w_obj) if w_dict is not None: - return space.setitem(w_dict,w_name,w_value) - raise OperationError(space.w_AttributeError,w_name) + return space.setitem(w_dict, w_name, w_value) + raise OperationError(space.w_AttributeError, w_name) def descr__delattr__(space, w_obj, w_name): name = space.unwrap(w_name) w_descr = space.lookup(w_obj, name) if w_descr is not None: if space.is_data_descr(w_descr): - return space.delete(w_descr,w_obj) + return space.delete(w_descr, w_obj) w_dict = space.getdict(w_obj) if w_dict is not None: try: - return space.delitem(w_dict,w_name) + return space.delitem(w_dict, w_name) except OperationError, ex: if not ex.match(space, space.w_KeyError): raise - raise OperationError(space.w_AttributeError,w_name) + raise OperationError(space.w_AttributeError, w_name) def descr__init__(space, w_obj, __args__): pass # XXX some strange checking maybe @@ -102,55 +102,55 @@ space.wrap('object %r is not callable' % (w_obj,))) return space.get_and_call_args(w_descr, w_obj, args) - def get(space,w_descr,w_obj,w_type=None): - w_get = space.lookup(w_descr,'__get__') + def get(space, w_descr, w_obj, w_type=None): + w_get = space.lookup(w_descr, '__get__') if w_get is None: return w_descr if w_type is None: w_type = space.type(w_obj) - return space.get_and_call_function(w_get,w_descr,w_obj,w_type) + return space.get_and_call_function(w_get, w_descr, w_obj, w_type) - def set(space,w_descr,w_obj,w_val): - w_set = space.lookup(w_descr,'__set__') + def set(space, w_descr, w_obj, w_val): + w_set = space.lookup(w_descr, '__set__') if w_set is None: - raise OperationError(space.w_TypeError, + raise OperationError(space.w_TypeError, space.wrap("object is not a descriptor with set")) - return space.get_and_call_function(w_set,w_descr,w_obj,w_val) + return space.get_and_call_function(w_set, w_descr, w_obj, w_val) - def delete(space,w_descr,w_obj): - w_delete = space.lookup(w_descr,'__delete__') + def delete(space, w_descr, w_obj): + w_delete = space.lookup(w_descr, '__delete__') if w_delete is None: raise OperationError(space.w_TypeError, space.wrap("object is not a descriptor with delete")) - return space.get_and_call_function(w_delete,w_descr,w_obj) + return space.get_and_call_function(w_delete, w_descr, w_obj) - def getattr(space,w_obj,w_name): - w_descr = space.lookup(w_obj,'__getattribute__') + def getattr(space, w_obj, w_name): + w_descr = space.lookup(w_obj, '__getattribute__') try: - return space.get_and_call_function(w_descr,w_obj,w_name) - except OperationError,e: - if not e.match(space,space.w_AttributeError): + return space.get_and_call_function(w_descr, w_obj, w_name) + except OperationError, e: + if not e.match(space, space.w_AttributeError): raise - w_descr = space.lookup(w_obj,'__getattr__') + w_descr = space.lookup(w_obj, '__getattr__') if w_descr is None: raise - return space.get_and_call_function(w_descr,w_obj,w_name) + return space.get_and_call_function(w_descr, w_obj, w_name) - def setattr(space,w_obj,w_name,w_val): - w_descr = space.lookup(w_obj,'__setattr__') + def setattr(space, w_obj, w_name, w_val): + w_descr = space.lookup(w_obj, '__setattr__') if w_descr is None: raise OperationError(space.w_AttributeError, space.wrap("object is readonly")) - return space.get_and_call_function(w_descr,w_obj,w_name,w_val) + return space.get_and_call_function(w_descr, w_obj, w_name, w_val) - def delattr(space,w_obj,w_name): - w_descr = space.lookup(w_obj,'__delattr__') + def delattr(space, w_obj, w_name): + w_descr = space.lookup(w_obj, '__delattr__') if w_descr is None: raise OperationError(space.w_AttributeError, space.wrap("object does not support attribute removal")) - return space.get_and_call_function(w_descr,w_obj,w_name) + return space.get_and_call_function(w_descr, w_obj, w_name) - def is_true(space,w_obj): + def is_true(space, w_obj): if w_obj == space.w_False: return False if w_obj == space.w_True: @@ -159,91 +159,91 @@ return False w_descr = space.lookup(w_obj, '__nonzero__') if w_descr is not None: - w_res = space.get_and_call_function(w_descr,w_obj) + w_res = space.get_and_call_function(w_descr, w_obj) return space.is_true(w_res) w_descr = space.lookup(w_obj, '__len__') if w_descr is not None: - w_res = space.get_and_call_function(w_descr,w_obj) + w_res = space.get_and_call_function(w_descr, w_obj) return space.is_true(w_res) return True - def str(space,w_obj): - w_descr = space.lookup(w_obj,'__str__') - return space.get_and_call_function(w_descr,w_obj) + def str(space, w_obj): + w_descr = space.lookup(w_obj, '__str__') + return space.get_and_call_function(w_descr, w_obj) # XXX PyObject_Str() checks that the result is a string - def repr(space,w_obj): - w_descr = space.lookup(w_obj,'__repr__') - return space.get_and_call_function(w_descr,w_obj) + def repr(space, w_obj): + w_descr = space.lookup(w_obj, '__repr__') + return space.get_and_call_function(w_descr, w_obj) # XXX PyObject_Repr() probably checks that the result is a string - def iter(space,w_obj): - w_descr = space.lookup(w_obj,'__iter__') + def iter(space, w_obj): + w_descr = space.lookup(w_obj, '__iter__') if w_descr is None: - w_descr = space.lookup(w_obj,'__getitem__') + w_descr = space.lookup(w_obj, '__getitem__') if w_descr is None: raise OperationError(space.w_TypeError, space.wrap("object is not iter()-able")) return space.newseqiter(w_obj) - return space.get_and_call_function(w_descr,w_obj) + return space.get_and_call_function(w_descr, w_obj) - def next(space,w_obj): - w_descr = space.lookup(w_obj,'next') + def next(space, w_obj): + w_descr = space.lookup(w_obj, 'next') if w_descr is None: raise OperationError(space.w_TypeError, space.wrap("iterator has no next() method")) - return space.get_and_call_function(w_descr,w_obj) + return space.get_and_call_function(w_descr, w_obj) - def getitem(space,w_obj,w_key): - w_descr = space.lookup(w_obj,'__getitem__') + def getitem(space, w_obj, w_key): + w_descr = space.lookup(w_obj, '__getitem__') if w_descr is None: raise OperationError(space.w_TypeError, space.wrap("cannot get items from object")) - return space.get_and_call_function(w_descr,w_obj,w_key) + return space.get_and_call_function(w_descr, w_obj, w_key) - def setitem(space,w_obj,w_key,w_val): - w_descr = space.lookup(w_obj,'__setitem__') + def setitem(space, w_obj, w_key, w_val): + w_descr = space.lookup(w_obj, '__setitem__') if w_descr is None: raise OperationError(space.w_TypeError, space.wrap("cannot set items on object")) - return space.get_and_call_function(w_descr,w_obj,w_key,w_val) + return space.get_and_call_function(w_descr, w_obj, w_key, w_val) - def delitem(space,w_obj,w_key): - w_descr = space.lookup(w_obj,'__delitem__') + def delitem(space, w_obj, w_key): + w_descr = space.lookup(w_obj, '__delitem__') if w_descr is None: raise OperationError(space.w_TypeError, space.wrap("cannot delete items from object")) - return space.get_and_call_function(w_descr,w_obj,w_key) + return space.get_and_call_function(w_descr, w_obj, w_key) - def pow(space,w_obj1,w_obj2,w_obj3): + def pow(space, w_obj1, w_obj2, w_obj3): w_typ1 = space.type(w_obj1) w_typ2 = space.type(w_obj2) - w_left_impl = space.lookup(w_obj1,'__pow__') - if space.is_true(space.is_(w_typ1,w_typ2)): + w_left_impl = space.lookup(w_obj1, '__pow__') + if space.is_true(space.is_(w_typ1, w_typ2)): w_right_impl = None else: - w_right_impl = space.lookup(w_obj2,'__rpow__') - if space.is_true(space.issubtype(w_typ1,w_typ2)): - w_obj1,w_obj2 = w_obj2,w_obj1 - w_left_impl,w_right_impl = w_right_impl,w_left_impl + w_right_impl = space.lookup(w_obj2, '__rpow__') + if space.is_true(space.issubtype(w_typ1, w_typ2)): + w_obj1, w_obj2 = w_obj2, w_obj1 + w_left_impl, w_right_impl = w_right_impl, w_left_impl if w_left_impl is not None: - w_res = space.get_and_call_function(w_left_impl,w_obj1,w_obj2, + w_res = space.get_and_call_function(w_left_impl, w_obj1, w_obj2, w_obj3) - if _check_notimplemented(space,w_res): + if _check_notimplemented(space, w_res): return w_res if w_right_impl is not None: - w_res = space.get_and_call_function(w_right_impl,w_obj2,w_obj1, + w_res = space.get_and_call_function(w_right_impl, w_obj2, w_obj1, w_obj3) - if _check_notimplemented(space,w_res): + if _check_notimplemented(space, w_res): return w_res raise OperationError(space.w_TypeError, space.wrap("operands do not support **")) - def contains(space,w_container,w_item): - w_descr = space.lookup(w_container,'__contains__') + def contains(space, w_container, w_item): + w_descr = space.lookup(w_container, '__contains__') if w_descr is not None: - return space.get_and_call_function(w_descr,w_container,w_item) + return space.get_and_call_function(w_descr, w_container, w_item) w_iter = space.iter(w_container) while 1: try: @@ -262,45 +262,45 @@ # helpers -def _check_notimplemented(space,w_obj): - return not space.is_true(space.is_(w_obj,space.w_NotImplemented)) +def _check_notimplemented(space, w_obj): + return not space.is_true(space.is_(w_obj, space.w_NotImplemented)) -def _invoke_binop(space,w_impl,w_obj1,w_obj2): +def _invoke_binop(space, w_impl, w_obj1, w_obj2): if w_impl is not None: - w_res = space.get_and_call_function(w_impl,w_obj1,w_obj2) - if _check_notimplemented(space,w_res): + w_res = space.get_and_call_function(w_impl, w_obj1, w_obj2) + if _check_notimplemented(space, w_res): return w_res return None # helper for invoking __cmp__ -def _conditional_neg(space,w_obj,flag): +def _conditional_neg(space, w_obj, flag): if flag: return space.neg(w_obj) else: return w_obj -def _cmp(space,w_obj1,w_obj2): +def _cmp(space, w_obj1, w_obj2): w_typ1 = space.type(w_obj1) w_typ2 = space.type(w_obj2) - w_left_impl = space.lookup(w_obj1,'__cmp__') + w_left_impl = space.lookup(w_obj1, '__cmp__') do_neg1 = False do_neg2 = True - if space.is_true(space.is_(w_typ1,w_typ2)): + if space.is_true(space.is_(w_typ1, w_typ2)): w_right_impl = None else: - w_right_impl = space.lookup(w_obj2,'__cmp__') - if space.is_true(space.issubtype(w_typ1,w_typ2)): - w_obj1,w_obj2 = w_obj2,w_obj1 - w_left_impl,w_right_impl = w_right_impl,w_left_impl - do_neg1,do_neg2 = do_neg2,do_neg1 + w_right_impl = space.lookup(w_obj2, '__cmp__') + if space.is_true(space.issubtype(w_typ1, w_typ2)): + w_obj1, w_obj2 = w_obj2, w_obj1 + w_left_impl, w_right_impl = w_right_impl, w_left_impl + do_neg1, do_neg2 = do_neg2, do_neg1 - w_res = _invoke_binop(space,w_left_impl,w_obj1,w_obj2) + w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2) if w_res is not None: - return _conditional_neg(space,w_res,do_neg1) - w_res = _invoke_binop(space,w_right_impl,w_obj2,w_obj1) + return _conditional_neg(space, w_res, do_neg1) + w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1) if w_res is not None: - return _conditional_neg(space,w_res,do_neg2) + return _conditional_neg(space, w_res, do_neg2) # fall back to internal rules if space.is_true(space.is_(w_obj1, w_obj2)): return space.wrap(0) @@ -345,88 +345,88 @@ space.wrap("unsupported operand type(s) for %s" % symbol)) return binop_impl -def _make_comparison_impl(symbol,specialnames): +def _make_comparison_impl(symbol, specialnames): left, right = specialnames op = getattr(operator, left) - def comparison_impl(space,w_obj1,w_obj2): + def comparison_impl(space, w_obj1, w_obj2): w_typ1 = space.type(w_obj1) w_typ2 = space.type(w_obj2) - w_left_impl = space.lookup(w_obj1,left) + w_left_impl = space.lookup(w_obj1, left) w_first = w_obj1 w_second = w_obj2 - if space.is_true(space.is_(w_typ1,w_typ2)): + if space.is_true(space.is_(w_typ1, w_typ2)): w_right_impl = None else: - w_right_impl = space.lookup(w_obj2,right) - if space.is_true(space.issubtype(w_typ1,w_typ2)): - w_obj1,w_obj2 = w_obj2,w_obj1 - w_left_impl,w_right_impl = w_right_impl,w_left_impl + w_right_impl = space.lookup(w_obj2, right) + if space.is_true(space.issubtype(w_typ1, w_typ2)): + w_obj1, w_obj2 = w_obj2, w_obj1 + w_left_impl, w_right_impl = w_right_impl, w_left_impl - w_res = _invoke_binop(space,w_left_impl,w_obj1,w_obj2) + w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2) if w_res is not None: return w_res - w_res = _invoke_binop(space,w_right_impl,w_obj2,w_obj1) + w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1) if w_res is not None: return w_res - # fallback: lt(a,b) <= lt(cmp(a,b),0) ... - w_res = _cmp(space,w_first,w_second) + # fallback: lt(a, b) <= lt(cmp(a, b), 0) ... + w_res = _cmp(space, w_first, w_second) res = space.unwrap(w_res) return space.wrap(op(res, 0)) return comparison_impl -def _make_inplace_impl(symbol,specialnames): +def _make_inplace_impl(symbol, specialnames): specialname, = specialnames assert specialname.startswith('__i') and specialname.endswith('__') noninplacespacemethod = specialname[3:-2] if noninplacespacemethod in ['or', 'and']: noninplacespacemethod += '_' # not too clean - def inplace_impl(space,w_lhs,w_rhs): - w_impl = space.lookup(w_lhs,specialname) + def inplace_impl(space, w_lhs, w_rhs): + w_impl = space.lookup(w_lhs, specialname) if w_impl is not None: - w_res = space.get_and_call_function(w_impl,w_lhs,w_rhs) - if _check_notimplemented(space,w_res): + w_res = space.get_and_call_function(w_impl, w_lhs, w_rhs) + if _check_notimplemented(space, w_res): return w_res # XXX fix the error message we get here - return getattr(space, noninplacespacemethod)(w_lhs,w_rhs) + return getattr(space, noninplacespacemethod)(w_lhs, w_rhs) return inplace_impl -def _make_unaryop_impl(symbol,specialnames): +def _make_unaryop_impl(symbol, specialnames): specialname, = specialnames - def unaryop_impl(space,w_obj): - w_impl = space.lookup(w_obj,specialname) + def unaryop_impl(space, w_obj): + w_impl = space.lookup(w_obj, specialname) if w_impl is None: raise OperationError(space.w_TypeError, space.wrap("operand does not support unary %s" % symbol)) - return space.get_and_call_function(w_impl,w_obj) + return space.get_and_call_function(w_impl, w_obj) return unaryop_impl # add regular methods for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable: - if not hasattr(DescrOperation,_name): + if not hasattr(DescrOperation, _name): _impl_maker = None - if _arity ==2 and _name in ['lt','le','gt','ge','ne','eq']: - #print "comparison",_specialnames + if _arity ==2 and _name in ['lt', 'le', 'gt', 'ge', 'ne', 'eq']: + #print "comparison", _specialnames _impl_maker = _make_comparison_impl elif _arity == 2 and _name.startswith('inplace_'): - #print "inplace",_specialnames + #print "inplace", _specialnames _impl_maker = _make_inplace_impl elif _arity == 2 and len(_specialnames) == 2: - #print "binop",_specialnames + #print "binop", _specialnames _impl_maker = _make_binop_impl elif _arity == 1 and len(_specialnames) == 1: - #print "unaryop",_specialnames + #print "unaryop", _specialnames _impl_maker = _make_unaryop_impl if _impl_maker: setattr(DescrOperation,_name,_impl_maker(_symbol,_specialnames)) elif _name not in ['is_', 'id','type','issubtype', # not really to be defined in DescrOperation - 'ord','round']: - raise Exception,"missing def for operation%s" % _name + 'ord', 'round']: + raise Exception, "missing def for operation%s" % _name From arigo at codespeak.net Mon Nov 15 15:13:47 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 15 Nov 2004 15:13:47 +0100 (MET) Subject: [pypy-svn] r7237 - pypy/trunk/src/pypy/tool Message-ID: <20041115141347.022055B13D@thoth.codespeak.net> Author: arigo Date: Mon Nov 15 15:13:47 2004 New Revision: 7237 Modified: pypy/trunk/src/pypy/tool/uid.py Log: generalized, just in case Modified: pypy/trunk/src/pypy/tool/uid.py ============================================================================== --- pypy/trunk/src/pypy/tool/uid.py (original) +++ pypy/trunk/src/pypy/tool/uid.py Mon Nov 15 15:13:47 2004 @@ -1,5 +1,7 @@ +import sys + def uid(obj): rval = id(obj) if rval < 0: - rval += 1L << 32 + rval += (long(sys.maxint)+1)*2 return rval From bob at codespeak.net Mon Nov 15 15:31:47 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 15:31:47 +0100 (MET) Subject: [pypy-svn] r7238 - pypy/trunk/src/pypy/tool Message-ID: <20041115143147.23F015B14B@thoth.codespeak.net> Author: bob Date: Mon Nov 15 15:31:46 2004 New Revision: 7238 Modified: pypy/trunk/src/pypy/tool/uid.py Log: clean up implementation Modified: pypy/trunk/src/pypy/tool/uid.py ============================================================================== --- pypy/trunk/src/pypy/tool/uid.py (original) +++ pypy/trunk/src/pypy/tool/uid.py Mon Nov 15 15:31:46 2004 @@ -1,7 +1,12 @@ import sys +HUGEINT = (sys.maxint + 1L) * 2L def uid(obj): + """ + Return the id of an object as an unsigned number so that its hex + representation makes sense + """ rval = id(obj) if rval < 0: - rval += (long(sys.maxint)+1)*2 + rval += HUGEINT return rval From bob at codespeak.net Mon Nov 15 15:40:35 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 15:40:35 +0100 (MET) Subject: [pypy-svn] r7239 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041115144035.DC50F5B156@thoth.codespeak.net> Author: bob Date: Mon Nov 15 15:40:35 2004 New Revision: 7239 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: replace '\l' with '\\l' to make its intent clearer Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Mon Nov 15 15:40:35 2004 @@ -245,7 +245,7 @@ bgcolor = getcolor(node.fillcolor, (255,255,255)) text = node.label - lines = text.replace('\l','\l\n').replace('\r','\r\n').split('\n') + lines = text.replace('\\l','\\l\n').replace('\r','\r\n').split('\n') # ignore a final newline if not lines[-1]: del lines[-1] @@ -255,12 +255,12 @@ bkgndcommands = [] for line in lines: - raw_line = line.replace('\l','').replace('\r','') or ' ' + raw_line = line.replace('\\l','').replace('\r','') or ' ' img = TextSnippet(self, raw_line, (0, 0, 0), bgcolor) w, h = img.get_size() if w>wmax: wmax = w if raw_line.strip(): - if line.endswith('\l'): + if line.endswith('\\l'): def cmd(img=img, y=hmax): img.draw(xleft, ytop+y) elif line.endswith('\r'): From mwh at codespeak.net Mon Nov 15 15:45:15 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 15:45:15 +0100 (MET) Subject: [pypy-svn] r7240 - pypy/trunk/src/pypy/translator Message-ID: <20041115144515.C5DB75B157@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 15:45:15 2004 New Revision: 7240 Modified: pypy/trunk/src/pypy/translator/genc.py Log: better treatment (i.e. rejection :) of special names. some kind of __init__ support, not tested yet Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 15:45:15 2004 @@ -125,8 +125,11 @@ content.sort() lines = [] for key, value in content: - if key.startswith('__'): - continue + if key.startswith('__') and key != '__init__': + if key in ['__module__', '__doc__', '__dict__', + '__weakref__']: + continue + raise Exception, "unexpected name %r in class %s"%(key, cls) lines.append('INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value))) self.globaldecl.append('static PyObject* %s;' % name) From mwh at codespeak.net Mon Nov 15 15:55:27 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 15:55:27 +0100 (MET) Subject: [pypy-svn] r7241 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041115145527.A2DA15B159@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 15:55:26 2004 New Revision: 7241 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: test translated __init__ support and a little support for unbound methods. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 15:55:26 2004 @@ -46,7 +46,7 @@ return self.cnames[key] except KeyError: for cls in type(obj).__mro__: - meth = getattr(self, 'nameof_' + cls.__name__, None) + meth = getattr(self, 'nameof_' + cls.__name__.replace(' ', ''), None) if meth: break else: @@ -102,6 +102,11 @@ self.pendingfunctions.append(func) return name + def nameof_instancemethod(self, meth): + assert meth.im_self is None, "meth must be unbound (for now)" + # no error checking here + return self.nameof(meth.im_func) + def nameof_builtin_function_or_method(self, func): import __builtin__ assert func is getattr(__builtin__, func.__name__, None), ( Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Mon Nov 15 15:55:26 2004 @@ -383,6 +383,10 @@ def with_more_init(v=int, w=bool): z = WithMoreInit(v, w) + if z.b: + return z.a + else: + return -z.a global_z = Z() global_z.my_attribute = 42 Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Mon Nov 15 15:55:26 2004 @@ -89,6 +89,16 @@ self.assertEquals(yast([1000,100,10,1]), 1111) self.assertEquals(yast(range(100)), (99*100)/2) + def test_with_init(self): + with_init = self.build_cfunc(snippet.with_init) + self.assertEquals(with_init(0), 0) + self.assertEquals(with_init(-100), -100) + + def test_with_more_init(self): + with_more_init = self.build_cfunc(snippet.with_more_init) + self.assertEquals(with_more_init(10, False), -10) + self.assertEquals(with_more_init(20, True), 20) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From mwh at codespeak.net Mon Nov 15 16:22:16 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 16:22:16 +0100 (MET) Subject: [pypy-svn] r7243 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041115152216.1571D5B164@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 16:22:15 2004 New Revision: 7243 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: support for dumping instances (of old-style classes only (though they are, of course, dumped as new-style classes)) and bound methods. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 15 16:22:15 2004 @@ -110,6 +110,14 @@ #define SETUP_CLASS_ATTR(t, attr, value) \ (PyObject_SetAttrString(t, attr, value) >= 0) +/*** instances ***/ + +#define SETUP_INSTANCE_ATTR(t, attr, value) \ + (PyObject_SetAttrString(t, attr, value) >= 0) + +#define SETUP_INSTANCE(i, cls) \ + (i = PyType_GenericAlloc(cls, 0)) + /* we need a subclass of 'builtin_function_or_method' which can be used as methods: builtin function objects that can be bound on instances */ static PyObject * Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 16:22:15 2004 @@ -103,9 +103,35 @@ return name def nameof_instancemethod(self, meth): - assert meth.im_self is None, "meth must be unbound (for now)" - # no error checking here - return self.nameof(meth.im_func) + if meth.im_self is None: + # no error checking here + return self.nameof(meth.im_func) + else: + ob = self.nameof(meth.im_self) + func = self.nameof(meth.im_func) + typ = self.nameof(meth.im_class) + us = self.uniquename('gmeth_'+meth.im_func.__name__) + self.globaldecl.append('static PyObject* %s;'%(us,)) + self.initcode.append( + 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( + us, func, ob, typ)) + return us + + def nameof_instance(self, instance): + name = self.uniquename('ginst_' + instance.__class__.__name__) + cls = self.nameof(instance.__class__) + content = instance.__dict__.items() + content.sort() + lines = [] + for key, value in content: + lines.append('INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value))) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( + name, cls)) + self.initcode.extend(lines) + return name + def nameof_builtin_function_or_method(self, func): import __builtin__ Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Mon Nov 15 16:22:15 2004 @@ -99,6 +99,10 @@ self.assertEquals(with_more_init(10, False), -10) self.assertEquals(with_more_init(20, True), 20) + def test_global_instance(self): + global_instance = self.build_cfunc(snippet.global_instance) + self.assertEquals(global_instance(), 42) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From mwh at codespeak.net Mon Nov 15 16:34:51 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 16:34:51 +0100 (MET) Subject: [pypy-svn] r7244 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041115153451.3004F5B172@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 16:34:50 2004 New Revision: 7244 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: dumping new-style classes Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 16:34:50 2004 @@ -45,13 +45,19 @@ try: return self.cnames[key] except KeyError: - for cls in type(obj).__mro__: - meth = getattr(self, 'nameof_' + cls.__name__.replace(' ', ''), None) - if meth: - break + if type(obj).__module__ != '__builtin__': + # assume it's a user defined thingy + name = self.nameof_instance(obj) else: - raise TypeError, "nameof(%r)" % (obj,) - name = meth(obj) + for cls in type(obj).__mro__: + meth = getattr(self, + 'nameof_' + cls.__name__.replace(' ', ''), + None) + if meth: + break + else: + raise TypeError, "nameof(%r)" % (obj,) + name = meth(obj) self.cnames[key] = name return name Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Mon Nov 15 16:34:50 2004 @@ -395,6 +395,12 @@ return global_z.my_method() +global_c = C() +global_c.a = 1 + +def global_newstyle_instance(): + return global_c + def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Mon Nov 15 16:34:50 2004 @@ -103,6 +103,11 @@ global_instance = self.build_cfunc(snippet.global_instance) self.assertEquals(global_instance(), 42) + def test_global_newstyle_instance(self): + global_newstyle_instance = self.build_cfunc(snippet.global_newstyle_instance) + self.assertEquals(global_newstyle_instance().a, 1) + + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From bob at codespeak.net Mon Nov 15 16:40:34 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 16:40:34 +0100 (MET) Subject: [pypy-svn] r7245 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041115154034.362045B175@thoth.codespeak.net> Author: bob Date: Mon Nov 15 16:40:33 2004 New Revision: 7245 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: some tweaks that might make it faster (draw less often) Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Mon Nov 15 16:40:33 2004 @@ -178,18 +178,27 @@ def run(self): dragging = click_origin = click_time = None - while 1: - if self.must_redraw: + events = [] + def peek(typ): + for val in events: + if val.type == typ: + return True + return False + while True: + if self.must_redraw and not events: self.viewer.render() if self.statusbarinfo: self.drawstatusbar() pygame.display.flip() self.must_redraw = False - event = pygame.event.wait() + if not events: + events.append(pygame.event.wait()) + events.extend(pygame.event.get()) + event = events.pop(0) if event.type == MOUSEMOTION: # short-circuit if there are more motion events pending - if pygame.event.peek([MOUSEMOTION]): + if peek(MOUSEMOTION): continue if dragging: if (abs(event.pos[0] - click_origin[0]) + @@ -205,11 +214,11 @@ self.must_redraw = True else: self.notifymousepos(event.pos) - if event.type == MOUSEBUTTONDOWN: + elif event.type == MOUSEBUTTONDOWN: dragging = click_origin = event.pos click_time = time.time() pygame.event.set_grab(True) - if event.type == MOUSEBUTTONUP: + elif event.type == MOUSEBUTTONUP: dragging = None pygame.event.set_grab(False) if click_time is not None and abs(time.time() - click_time) < 1: @@ -217,18 +226,18 @@ self.notifyclick(click_origin) click_time = None self.notifymousepos(event.pos) - if event.type == KEYDOWN: + elif event.type == KEYDOWN: if event.key in [K_p, K_LEFT, K_BACKSPACE]: self.layout_back() - if event.key == K_ESCAPE: - break - if event.type == VIDEORESIZE: + elif event.key == K_ESCAPE: + events.insert(0, pygame.event.Event(QUIT)) + elif event.type == VIDEORESIZE: # short-circuit if there are more resize events pending - if pygame.event.peek([VIDEORESIZE]): + if peek(VIDEORESIZE): continue self.resize(event.size) self.must_redraw = True - if event.type == QUIT: + elif event.type == QUIT: break # cannot safely close and re-open the display, depending on # Pygame version and platform. From mwh at codespeak.net Mon Nov 15 16:50:53 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 15 Nov 2004 16:50:53 +0100 (MET) Subject: [pypy-svn] r7246 - pypy/trunk/src/pypy/translator Message-ID: <20041115155053.704615B17B@thoth.codespeak.net> Author: mwh Date: Mon Nov 15 16:50:52 2004 New Revision: 7246 Modified: pypy/trunk/src/pypy/translator/genc.py Log: support for dumping unhashable types, in particular lists and dicts. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 16:50:52 2004 @@ -43,6 +43,10 @@ def nameof(self, obj): key = type(obj), obj # to avoid confusing e.g. 0 and 0.0 try: + hash(key) + except TypeError: + key = id(obj) + try: return self.cnames[key] except KeyError: if type(obj).__module__ != '__builtin__': @@ -164,9 +168,10 @@ for key, value in content: if key.startswith('__') and key != '__init__': if key in ['__module__', '__doc__', '__dict__', - '__weakref__']: + '__weakref__', '__repr__']: continue - raise Exception, "unexpected name %r in class %s"%(key, cls) + # XXX some __NAMES__ are important... nicer solution sought + #raise Exception, "unexpected name %r in class %s"%(key, cls) lines.append('INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value))) self.globaldecl.append('static PyObject* %s;' % name) @@ -194,6 +199,31 @@ self.initcode.extend(lines) return name + def nameof_list(self, lis): + name = self.uniquename('g%dlist' % len(lis)) + lines = [] + for i in range(len(lis)): + item = self.nameof(lis[i]) + lines.append('\tPy_INCREF(%s);' % item) + lines.append('\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item)) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) + self.initcode.extend(lines) + return name + + def nameof_dict(self, dic): + name = self.uniquename('g%ddict' % len(dic)) + lines = [] + for k in dic: + assert type(k) is str, "can only dump dicts with string keys" + lines.append('\tINITCHK(PyDict_SetItemString(%s, "%s", %s) >= 0)'%( + name, k, self.nameof(dic[k]))) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) + self.initcode.extend(lines) + return name + + def gen_source(self): f = self.f info = { From hpk at codespeak.net Mon Nov 15 16:58:43 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Nov 2004 16:58:43 +0100 (MET) Subject: [pypy-svn] r7247 - in pypy/trunk/src: goal pypy/interpreter Message-ID: <20041115155843.2510A5B17D@thoth.codespeak.net> Author: hpk Date: Mon Nov 15 16:58:42 2004 New Revision: 7247 Added: pypy/trunk/src/goal/testcachebuild.py Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/gateway.py Log: the beginnings of filling caches and controling it via "allowbuildcache" as a flag on an objectspace Added: pypy/trunk/src/goal/testcachebuild.py ============================================================================== --- (empty file) +++ pypy/trunk/src/goal/testcachebuild.py Mon Nov 15 16:58:42 2004 @@ -0,0 +1,23 @@ +from pypy.tool import option, autopath, testit +from pypy.interpreter import gateway + +####################################################### +def app_triggergenerator(): + def gen(): + yield 42 + for x in gen(): + pass + +gateway.importall(globals()) # app_xxx() -> xxx() + +####################################################### + +def triggercachebuild(space): + triggergenerator(space) + +if __name__ == '__main__': + space = option.objspace('std') + #triggercachebuild(space) + testit.main(autopath.pypydir) + space.allowbuildcache = False + testit.main(autopath.pypydir) Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Mon Nov 15 16:58:42 2004 @@ -33,6 +33,7 @@ def __init__(self): "Basic initialization of objects." self.generalcache = {} + self.allowbuildcache = True # sets all the internal descriptors self.initialize() @@ -40,7 +41,10 @@ try: return self.generalcache[key] except KeyError: - return self.generalcache.setdefault(key, builder(key, self)) + if self.allowbuildcache: + #print "building for key %r" % key + return self.generalcache.setdefault(key, builder(key, self)) + raise loadfromcache.translated_version = lambda s, k, b: s.generalcache[k] def make_builtins(self, for_builtins): Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Mon Nov 15 16:58:42 2004 @@ -210,12 +210,11 @@ return self.build_function(space, w_globals) def build_function(self, space, w_globals): - if self in space.generalcache: - fn = space.generalcache[self] - else: - defs = self.getdefaults(space) # needs to be implemented by subclass - fn = Function(space, self.code, w_globals, defs, forcename = self.name) - space.generalcache[self] = fn + if not space.allowbuildcache: + return space.generalcache[self] + defs = self.getdefaults(space) # needs to be implemented by subclass + fn = Function(space, self.code, w_globals, defs, forcename = self.name) + space.generalcache[self] = fn return fn def get_method(self, obj): From arigo at codespeak.net Mon Nov 15 17:27:50 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 15 Nov 2004 17:27:50 +0100 (MET) Subject: [pypy-svn] r7250 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041115162750.BC8445B17F@thoth.codespeak.net> Author: arigo Date: Mon Nov 15 17:27:50 2004 New Revision: 7250 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Recursive constant objects. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 15 17:27:50 2004 @@ -30,22 +30,21 @@ self.translator = translator self.modname = (modname or uniquemodulename(translator.functions[0].__name__)) - self.cnames = {(type(None), None): 'Py_None', - ( bool, False): 'Py_False', - ( bool, True): 'Py_True', + self.cnames = {Constant(None).key: 'Py_None', + Constant(False).key: 'Py_False', + Constant(True).key: 'Py_True', } self.seennames = {} - self.initcode = [] + self.initcode = [] # list of lines for the module's initxxx() + self.latercode = [] # list of generators generating extra lines + # for later in initxxx() -- for recursive + # objects self.globaldecl = [] self.pendingfunctions = [] self.gen_source() def nameof(self, obj): - key = type(obj), obj # to avoid confusing e.g. 0 and 0.0 - try: - hash(key) - except TypeError: - key = id(obj) + key = Constant(obj).key try: return self.cnames[key] except KeyError: @@ -130,18 +129,17 @@ def nameof_instance(self, instance): name = self.uniquename('ginst_' + instance.__class__.__name__) cls = self.nameof(instance.__class__) - content = instance.__dict__.items() - content.sort() - lines = [] - for key, value in content: - lines.append('INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( - name, key, self.nameof(value))) + def initinstance(): + content = instance.__dict__.items() + content.sort() + for key, value in content: + yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) - self.initcode.extend(lines) + self.latercode.append(initinstance()) return name - def nameof_builtin_function_or_method(self, func): import __builtin__ @@ -162,22 +160,22 @@ base = self.nameof(bases[0]) else: base = '(PyObject*) &PyBaseObject_Type' - content = cls.__dict__.items() - content.sort() - lines = [] - for key, value in content: - if key.startswith('__') and key != '__init__': - if key in ['__module__', '__doc__', '__dict__', - '__weakref__', '__repr__']: - continue - # XXX some __NAMES__ are important... nicer solution sought - #raise Exception, "unexpected name %r in class %s"%(key, cls) - lines.append('INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( - name, key, self.nameof(value))) + def initclassobj(): + content = cls.__dict__.items() + content.sort() + for key, value in content: + if key.startswith('__') and key != '__init__': + if key in ['__module__', '__doc__', '__dict__', + '__weakref__', '__repr__']: + continue + # XXX some __NAMES__ are important... nicer solution sought + #raise Exception, "unexpected name %r in class %s"%(key, cls) + yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(SETUP_CLASS(%s, "%s", %s))' % ( name, cls.__name__, base)) - self.initcode.extend(lines) + self.latercode.append(initclassobj()) return name nameof_class = nameof_classobj # for Python 2.2 @@ -189,38 +187,38 @@ def nameof_tuple(self, tup): name = self.uniquename('g%dtuple' % len(tup)) - lines = [] - for i in range(len(tup)): - item = self.nameof(tup[i]) - lines.append('\tPy_INCREF(%s);' % item) - lines.append('\tPyTuple_SET_ITEM(%s, %d, %s);' % (name, i, item)) + def inittuple(): + for i in range(len(tup)): + item = self.nameof(tup[i]) + yield '\tPy_INCREF(%s);' % item + yield '\tPyTuple_SET_ITEM(%s, %d, %s);' % (name, i, item) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyTuple_New(%d))' % (name, len(tup))) - self.initcode.extend(lines) + self.latercode.append(inittuple()) return name def nameof_list(self, lis): name = self.uniquename('g%dlist' % len(lis)) - lines = [] - for i in range(len(lis)): - item = self.nameof(lis[i]) - lines.append('\tPy_INCREF(%s);' % item) - lines.append('\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item)) + def initlist(): + for i in range(len(lis)): + item = self.nameof(lis[i]) + yield '\tPy_INCREF(%s);' % item + yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) - self.initcode.extend(lines) + self.latercode.append(initlist()) return name def nameof_dict(self, dic): name = self.uniquename('g%ddict' % len(dic)) - lines = [] - for k in dic: - assert type(k) is str, "can only dump dicts with string keys" - lines.append('\tINITCHK(PyDict_SetItemString(%s, "%s", %s) >= 0)'%( - name, k, self.nameof(dic[k]))) + def initdict(): + for k in dic: + assert type(k) is str, "can only dump dicts with string keys" + yield '\tINITCHK(PyDict_SetItemString(%s, "%s", %s) >= 0)'%( + name, k, self.nameof(dic[k])) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) - self.initcode.extend(lines) + self.latercode.append(initdict()) return name @@ -235,8 +233,14 @@ print >> f, self.C_HEADER # function implementations - for func in self.pendingfunctions: + while self.pendingfunctions: + func = self.pendingfunctions.pop(0) self.gen_cfunction(func) + # collect more of the latercode after each function + while self.latercode: + gen = self.latercode.pop(0) + self.initcode.extend(gen) + self.gen_global_declarations() # footer print >> f, self.C_INIT_HEADER % info @@ -244,17 +248,21 @@ print >> f, '\t' + codeline print >> f, self.C_INIT_FOOTER % info - def gen_cfunction(self, func): - f = self.f - body = list(self.cfunction_body(func)) + def gen_global_declarations(self): g = self.globaldecl if g: + f = self.f print >> f, '/* global declaration%s */' % ('s'*(len(g)>1)) for line in g: print >> f, line print >> f del g[:] + def gen_cfunction(self, func): + f = self.f + body = list(self.cfunction_body(func)) + self.gen_global_declarations() + # print header name = self.nameof(func) assert name.startswith('gfunc_') Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Mon Nov 15 17:27:50 2004 @@ -401,6 +401,12 @@ def global_newstyle_instance(): return global_c +global_rl = [] +global_rl.append(global_rl) + +def global_recursive_list(): + return global_rl + def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Mon Nov 15 17:27:50 2004 @@ -106,7 +106,12 @@ def test_global_newstyle_instance(self): global_newstyle_instance = self.build_cfunc(snippet.global_newstyle_instance) self.assertEquals(global_newstyle_instance().a, 1) - + + def test_global_recursive_list(self): + global_recursive_list = self.build_cfunc(snippet.global_recursive_list) + lst = global_recursive_list() + self.assertEquals(len(lst), 1) + self.assert_(lst[0] is lst) class TypedTestCase(testit.IntTestCase): From arigo at codespeak.net Mon Nov 15 17:30:47 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 15 Nov 2004 17:30:47 +0100 (MET) Subject: [pypy-svn] r7251 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041115163047.83D465B181@thoth.codespeak.net> Author: arigo Date: Mon Nov 15 17:30:46 2004 New Revision: 7251 Modified: pypy/trunk/src/pypy/objspace/flow/model.py Log: Oups. This goes together with the previous check-in. Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Mon Nov 15 17:30:46 2004 @@ -100,15 +100,22 @@ class Constant: def __init__(self, value): self.value = value # a concrete value + # try to be smart about constant mutable or immutable values + key = type(self.value), self.value # to avoid confusing e.g. 0 and 0.0 + try: + hash(key) + except TypeError: + key = id(self.value) + self.key = key def __eq__(self, other): - return self.__class__ is other.__class__ and self.value == other.value + return self.__class__ is other.__class__ and self.key == other.key def __ne__(self, other): return not (self == other) def __hash__(self): - return hash(self.value) + return hash(self.key) def __repr__(self): # try to limit the size of the repr to make it more readable From bob at codespeak.net Mon Nov 15 19:23:43 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 15 Nov 2004 19:23:43 +0100 (MET) Subject: [pypy-svn] r7260 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041115182343.8386C5B184@thoth.codespeak.net> Author: bob Date: Mon Nov 15 19:23:40 2004 New Revision: 7260 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: break up the event processing Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Mon Nov 15 19:23:40 2004 @@ -5,7 +5,6 @@ from pygame.locals import * from drawgraph import GraphRenderer - class Display(object): def __init__(self, (w,h)=(800,740)): @@ -27,6 +26,7 @@ self.font = pygame.font.Font(self.STATUSBARFONT, 16) self.viewers_history = [] self.viewer = None + self.method_cache = {} self.setlayout(layout) def setlayout(self, layout): @@ -176,69 +176,91 @@ pygame.display.flip() return moving + def peek(self, typ): + for event in self.events: + if event.type == typ: + return True + return False + + def process_event(self, event): + method = self.method_cache.get(event.type, KeyError) + if method is KeyError: + method = getattr(self, 'process_%s' % (pygame.event.event_name(event.type),), None) + self.method_cache[method] = method + if method is not None: + method(event) + + def process_MouseMotion(self, event): + if self.peek(MOUSEMOTION): + return + if self.dragging: + if (abs(event.pos[0] - self.click_origin[0]) + + abs(event.pos[1] - self.click_origin[1])) > 12: + self.click_time = None + dx = event.pos[0] - self.dragging[0] + dy = event.pos[1] - self.dragging[1] + if event.buttons[0]: # left mouse button + self.viewer.shiftscale(1.003 ** (dx+dy)) + else: + self.viewer.shiftoffset(-2*dx, -2*dy) + self.dragging = event.pos + self.must_redraw = True + else: + self.notifymousepos(event.pos) + + def process_MouseButtonDown(self, event): + self.dragging = self.click_origin = event.pos + self.click_time = time.time() + pygame.event.set_grab(True) + + def process_MouseButtonUp(self, event): + self.dragging = None + pygame.event.set_grab(False) + if self.click_time is not None and abs(time.time() - self.click_time) < 1: + # click (no significant dragging) + self.notifyclick(self.click_origin) + self.click_time = None + self.notifymousepos(event.pos) + + def process_KeyDown(self, event): + if event.key in [K_p, K_LEFT, K_BACKSPACE]: + self.layout_back() + elif event.key == K_ESCAPE: + self.events.insert(0, pygame.event.Event(QUIT)) + + def process_VideoResize(self, event): + # short-circuit if there are more resize events pending + if self.peek(VIDEORESIZE): + return + self.resize(event.size) + self.must_redraw = True + + def process_Quit(self, event): + raise StopIteration + def run(self): - dragging = click_origin = click_time = None - events = [] - def peek(typ): - for val in events: - if val.type == typ: - return True - return False - while True: - if self.must_redraw and not events: - self.viewer.render() - if self.statusbarinfo: - self.drawstatusbar() - pygame.display.flip() - self.must_redraw = False - - if not events: - events.append(pygame.event.wait()) - events.extend(pygame.event.get()) - event = events.pop(0) - if event.type == MOUSEMOTION: - # short-circuit if there are more motion events pending - if peek(MOUSEMOTION): - continue - if dragging: - if (abs(event.pos[0] - click_origin[0]) + - abs(event.pos[1] - click_origin[1])) > 12: - click_time = None - dx = event.pos[0] - dragging[0] - dy = event.pos[1] - dragging[1] - if event.buttons[0]: # left mouse button - self.viewer.shiftscale(1.003 ** (dx+dy)) - else: - self.viewer.shiftoffset(-2*dx, -2*dy) - dragging = event.pos - self.must_redraw = True - else: - self.notifymousepos(event.pos) - elif event.type == MOUSEBUTTONDOWN: - dragging = click_origin = event.pos - click_time = time.time() - pygame.event.set_grab(True) - elif event.type == MOUSEBUTTONUP: - dragging = None - pygame.event.set_grab(False) - if click_time is not None and abs(time.time() - click_time) < 1: - # click (no significant dragging) - self.notifyclick(click_origin) - click_time = None - self.notifymousepos(event.pos) - elif event.type == KEYDOWN: - if event.key in [K_p, K_LEFT, K_BACKSPACE]: - self.layout_back() - elif event.key == K_ESCAPE: - events.insert(0, pygame.event.Event(QUIT)) - elif event.type == VIDEORESIZE: - # short-circuit if there are more resize events pending - if peek(VIDEORESIZE): - continue - self.resize(event.size) - self.must_redraw = True - elif event.type == QUIT: - break + self.dragging = self.click_origin = self.click_time = None + events = self.events = [] + try: + + while True: + + if self.must_redraw and not events: + self.viewer.render() + if self.statusbarinfo: + self.drawstatusbar() + pygame.display.flip() + self.must_redraw = False + + if not events: + events.append(pygame.event.wait()) + events.extend(pygame.event.get()) + + self.process_event(events.pop(0)) + + except StopIteration: + pass + # cannot safely close and re-open the display, depending on # Pygame version and platform. pygame.display.set_mode((self.width,1)) From hpk at codespeak.net Mon Nov 15 19:40:16 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 15 Nov 2004 19:40:16 +0100 (MET) Subject: [pypy-svn] r7261 - in pypy/trunk/src: goal pypy/interpreter pypy/interpreter/test pypy/objspace/flow pypy/objspace/std pypy/objspace/test pypy/tool pypy/tool/test Message-ID: <20041115184016.758785B188@thoth.codespeak.net> Author: hpk Date: Mon Nov 15 19:40:09 2004 New Revision: 7261 Added: pypy/trunk/src/pypy/tool/frozendict.py Removed: pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/test/test_newtest.py Modified: pypy/trunk/src/goal/testcachebuild.py pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/test/test_gateway.py pypy/trunk/src/pypy/interpreter/unittest_w.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Log: - reworked the "space.generalcache" into space._typecache # cache for types space._faketypecache # cache for faked types space._gatewaycache # cache for gateway's interp2app/app2interp and changed space.loadfromcache to require a third parameter 'cache' which the different users have to provide - the testing parts of pypy (unittest_w and test_gateway.py etc.pp) don't participate in the above caches but use their own cache - the new goal/testcachebuild.py shows that we can run all tests, then turn the above caches into frozendict(cache)'s and still run all tests successfully (so no new building of cache content takes place anymore) - removed the unused newtest.py and related files (some leftover from three sprints ago or so) Modified: pypy/trunk/src/goal/testcachebuild.py ============================================================================== --- pypy/trunk/src/goal/testcachebuild.py (original) +++ pypy/trunk/src/goal/testcachebuild.py Mon Nov 15 19:40:09 2004 @@ -1,5 +1,6 @@ -from pypy.tool import option, autopath, testit +from pypy.tool import option, autopath, testit from pypy.interpreter import gateway +from pypy.tool.frozendict import frozendict ####################################################### def app_triggergenerator(): @@ -19,5 +20,9 @@ space = option.objspace('std') #triggercachebuild(space) testit.main(autopath.pypydir) - space.allowbuildcache = False + + space._typecache = frozendict(space._typecache) + space._faketypecache = frozendict(space._faketypecache) + space._gatewaycache = frozendict(space._gatewaycache) + testit.main(autopath.pypydir) Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Mon Nov 15 19:40:09 2004 @@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.miscutils import getthreadlocals from pypy.interpreter.argument import Arguments +from pypy.tool.frozendict import frozendict __all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'BaseWrappable', 'W_Root'] @@ -32,20 +33,17 @@ def __init__(self): "Basic initialization of objects." - self.generalcache = {} - self.allowbuildcache = True + self._gatewaycache = {} # sets all the internal descriptors self.initialize() - def loadfromcache(self, key, builder): + def loadfromcache(self, key, builder, cache): try: - return self.generalcache[key] + return cache[key] except KeyError: - if self.allowbuildcache: - #print "building for key %r" % key - return self.generalcache.setdefault(key, builder(key, self)) - raise - loadfromcache.translated_version = lambda s, k, b: s.generalcache[k] + assert not isinstance(cache, frozendict) + #print "building for key %r" % key + return cache.setdefault(key, builder(key, self)) def make_builtins(self, for_builtins): # initializing builtins may require creating a frame which in Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Mon Nov 15 19:40:09 2004 @@ -55,7 +55,7 @@ ('__interplevel__eval', self.interpleveleval.im_func), ('__interplevel__execfile', self.interplevelexecfile.im_func), ('__import__', self.interplevelimport.im_func)]: - hook = gateway.interp2app(impl).get_method(self) + hook = gateway.interp2app_temp(impl).get_method(self) w_name = space.wrap(name) try: self.__saved_hooks[name] = space.getitem(w_builtins, w_name) Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Mon Nov 15 19:40:09 2004 @@ -182,7 +182,9 @@ return self.get_function(space) def get_function(self, space): - return space.loadfromcache(self, Gateway.build_all_functions) + return space.loadfromcache(self, + Gateway.build_all_functions, + self.getcache(space)) def build_all_functions(self, space): # the construction is supposed to be done only once in advance, @@ -197,25 +199,31 @@ else: # is there another Gateway in staticglobals for which we # already have a w_globals for this space ? + cache = self.getcache(space) for value in self.staticglobals.itervalues(): if isinstance(value, Gateway): - if self in space.generalcache: + if value in cache: # yes, we share its w_globals - fn = space.generalcache[value] + fn = cache[value] w_globals = fn.w_func_globals break else: # no, we build all Gateways in the staticglobals now. w_globals = build_dict(self.staticglobals, space) - return self.build_function(space, w_globals) + return self._build_function(space, w_globals) - def build_function(self, space, w_globals): - if not space.allowbuildcache: - return space.generalcache[self] - defs = self.getdefaults(space) # needs to be implemented by subclass - fn = Function(space, self.code, w_globals, defs, forcename = self.name) - space.generalcache[self] = fn - return fn + def getcache(self, space): + return space._gatewaycache + + def _build_function(self, space, w_globals): + cache = self.getcache(space) + try: + return cache[self] + except KeyError: + defs = self.getdefaults(space) # needs to be implemented by subclass + fn = Function(space, self.code, w_globals, defs, forcename = self.name) + cache[self] = fn + return fn def get_method(self, obj): # to get the Gateway as a method out of an instance, we build a @@ -289,8 +297,12 @@ def getdefaults(self, space): return self.staticdefs -def exportall(d): +def exportall(d, temporary=False): """Publish every function from a dict.""" + if temporary: + i2a = interp2app_temp + else: + i2a = interp2app for name, obj in d.items(): if isinstance(obj, types.FunctionType): # names starting in 'app_' are supposedly already app-level @@ -303,7 +315,7 @@ if name.startswith('_') and not name.endswith('_'): continue if 'app_'+name not in d: - d['app_'+name] = interp2app(obj, name) + d['app_'+name] = i2a(obj, name) def export_values(space, dic, w_namespace): for name, w_value in dic.items(): @@ -316,22 +328,40 @@ w_name = space.wrap(name[2:]) space.setitem(w_namespace, w_name, w_value) -def importall(d): +def importall(d, temporary=False): """Import all app_-level functions as Gateways into a dict.""" + if temporary: + a2i = app2interp_temp + else: + a2i = app2interp for name, obj in d.items(): if name.startswith('app_') and name[4:] not in d: if isinstance(obj, types.FunctionType): - d[name[4:]] = app2interp(obj, name[4:]) + d[name[4:]] = a2i(obj, name[4:]) def build_dict(d, space): """Search all Gateways and put them into a wrapped dictionary.""" w_globals = space.newdict([]) for value in d.itervalues(): if isinstance(value, Gateway): - fn = value.build_function(space, w_globals) + fn = value._build_function(space, w_globals) w_name = space.wrap(value.name) w_object = space.wrap(fn) space.setitem(w_globals, w_name, w_object) if hasattr(space, 'w_sys'): # give them 'sys' if it exists already space.setitem(w_globals, space.wrap('sys'), space.w_sys) return w_globals + + +# +# the next gateways are to be used only for +# temporary/initialization purposes +class app2interp_temp(app2interp): + def getcache(self, space): + return self.__dict__.setdefault(space, {}) + # ^^^^^ + # armin suggested this + +class interp2app_temp(interp2app): + def getcache(self, space): + return self.__dict__.setdefault(space, {}) Modified: pypy/trunk/src/pypy/interpreter/test/test_gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_gateway.py Mon Nov 15 19:40:09 2004 @@ -3,7 +3,6 @@ from pypy.tool import testit from pypy.interpreter import gateway - class TestBuiltinCode(testit.IntTestCase): def setUp(self): self.space = testit.objspace() @@ -66,7 +65,7 @@ w = self.space.wrap def app_g3(a, b): return a+b - g3 = gateway.app2interp(app_g3) + g3 = gateway.app2interp_temp(app_g3) self.assertEqual_w(g3(self.space, w('foo'), w('bar')), w('foobar')) def test_interp2app(self): @@ -74,7 +73,7 @@ w = space.wrap def g3(space, w_a, w_b): return space.add(w_a, w_b) - app_g3 = gateway.interp2app(g3) + app_g3 = gateway.interp2app_temp(g3) w_app_g3 = space.wrap(app_g3) self.assertEqual_w( space.call(w_app_g3, @@ -94,7 +93,7 @@ def app_g1(x): return g3('foo', x) """ in g - gateway.importall(g) + gateway.importall(g, temporary=True) g1 = g['g1'] self.assertEqual_w(g1(self.space, w('bar')), w('foobar')) @@ -107,8 +106,8 @@ def app_g1(x): return g3('foo', x) """ in g - gateway.exportall(g) - g1 = gateway.app2interp(g['app_g1']) + gateway.exportall(g, temporary=True) + g1 = gateway.app2interp_temp(g['app_g1']) self.assertEqual_w(g1(self.space, w('bar')), w('foobar')) Modified: pypy/trunk/src/pypy/interpreter/unittest_w.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/unittest_w.py (original) +++ pypy/trunk/src/pypy/interpreter/unittest_w.py Mon Nov 15 19:40:09 2004 @@ -12,7 +12,6 @@ IGNORE_TESTS = [s.strip() for s in f.readlines()] f.close() - def make_testcase_class(space, tc_w): # XXX this is all a bit insane (but it works) @@ -22,7 +21,7 @@ for name in dir(AppTestCase): if ( name.startswith('assert') or name.startswith('fail') and name != 'failureException'): - fn = gateway.app2interp(getattr(tc_w, name).im_func, name) + fn = gateway.app2interp_temp(getattr(tc_w, name).im_func, name) space.setitem(w_dict, w(name), w(fn)) # space-dependent part: make an object-space-level dictionary @@ -52,7 +51,7 @@ setattr(space, w_tc_attr, w_tc) f = self.testMethod.im_func - gway = gateway.app2interp(f, f.func_name) + gway = gateway.app2interp_temp(f, f.func_name) gway(space, w_tc) Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Mon Nov 15 19:40:09 2004 @@ -28,9 +28,9 @@ #self.make_builtins() #self.make_sys() - def loadfromcache(self, key, builder): + def loadfromcache(self, key, builder, cache): try: - return self.generalcache[key] + return cache[key] except KeyError: # this method is overloaded to allow the space to switch to # "concrete mode" when building the object that goes into @@ -39,7 +39,7 @@ self.executioncontext.crnt_ops = flowcontext.ConcreteNoOp() self.concrete_mode += 1 try: - return self.generalcache.setdefault(key, builder(key, self)) + return cache.setdefault(key, builder(key, self)) finally: self.executioncontext.crnt_ops = previous_ops self.concrete_mode -= 1 Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Mon Nov 15 19:40:09 2004 @@ -7,7 +7,6 @@ from pypy.objspace.std import stdtypedef import types - class W_Object(W_Root, object): "Parent base class for wrapped objects." typedef = None @@ -136,6 +135,9 @@ return done def initialize(self): + self._typecache = {} + self._faketypecache = {} + # The object implementations that we want to 'link' into PyPy must be # imported here. This registers them into the multimethod tables, # *before* the type objects are built from these multimethod tables. @@ -206,7 +208,9 @@ def gettypeobject(self, typedef): # types_w maps each StdTypeDef instance to its # unique-for-this-space W_TypeObject instance - return self.loadfromcache(typedef, stdtypedef.buildtypeobject) + return self.loadfromcache(typedef, + stdtypedef.buildtypeobject, + self._typecache) def wrap(self, x): "Wraps the Python value 'x' into one of the wrapper classes." @@ -251,9 +255,9 @@ if hasattr(self, 'w_' + x.__name__): return getattr(self, 'w_' + x.__name__) if isinstance(x, type): - ft = self.loadfromcache(x, fake_type) + ft = self.loadfromcache(x, fake_type, self._faketypecache) return self.gettypeobject(ft.typedef) - ft = self.loadfromcache(type(x), fake_type) + ft = self.loadfromcache(type(x), fake_type, self._faketypecache) return ft(self, x) def newint(self, intval): Modified: pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py (original) +++ pypy/trunk/src/pypy/objspace/test/test_traceobjspace.py Mon Nov 15 19:40:09 2004 @@ -1,8 +1,8 @@ import autopath from pypy.tool import testit from pypy.objspace import trace -from pypy.interpreter.gateway import app2interp from pypy.tool import pydis +from pypy.interpreter import gateway class Test_TraceObjSpace(testit.IntTestCase): @@ -15,7 +15,7 @@ def perform_trace(self, app_func): tspace = self.space - func_gw = app2interp(app_func) + func_gw = gateway.app2interp_temp(app_func) func = func_gw.get_function(tspace) tspace.settrace() tspace.call_function(tspace.wrap(func)) Added: pypy/trunk/src/pypy/tool/frozendict.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/frozendict.py Mon Nov 15 19:40:09 2004 @@ -0,0 +1,7 @@ + +# hacks += 1 +class frozendict(dict): + def __setitem__(self, *args): + raise TypeError, "this dict is already frozen, you are too late!" + __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ + Deleted: /pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- /pypy/trunk/src/pypy/tool/newtest.py Mon Nov 15 19:40:09 2004 +++ (empty file) @@ -1,672 +0,0 @@ -""" -Unit testing framework for PyPy. - -The following picture is an UML class diagram of the framework. - - +----------+ 1 1 +------------+ - | TestItem |------------------------| TestResult | - +----------+ | (abstract) | - | * +------------+ - | A - | - - | 1 | - +-----------+ +-----------+--------+----------+ - | TestSuite | | | | - +-----------+ +---------+ +---------+ +-------------------------+ - A | Success | | Skipped | | TestResultWithTraceback | - | +---------+ +---------+ | (abstract) | - | loaded by +-------------------------+ - | A A - | * - - - +------------+ | | - | TestCase | | | - | (abstract) | +-------+ +---------+ - +------------+ | Error | | Failure | - A +-------+ +---------+ - - - | - | - concrete test - case classes - -Like the unittest framework of Python, our framework implements -tests as test methods in TestCase classes. Custom test case classes -derive from the shown TestCase class, defined in this module. As in -Python's unittest, a test case class can contain setUp and tearDown -methods. Additionally, it contains a method 'skip' which can be -called to stop a test prematurely. This won't be counted as a failure -or error. - -Test cases are loaded by a TestSuite class via the method init_from_dir. -This method will read all test modules in and below a specified -directory, inspect them for classes derived from TestCase (i. e. _our_ -TestCase), and in turn inspect them for test methods (like in -unittest, all methods which start with "test"). - -For every found method, TestSuite will store its module, class and -unbound method objects in a TestItem object. There are also other -properties stored, e. g. the source code for each method and its -docstring. - -When the TestSuite's method 'run' is called, all collected TestItems -are run and, according to the outcome of the test, a TestResult object -is generated which holds a reference to "its" TestItem object. - -The TestResult classes Success and Skipped denote a passed test. A -skipped test means that not all test code has been run (and no error -or failure occurred before the skip method was called). If a test -fails, resulting in a Failure object, a test, e. g. tested with -assertEqual, has failed. An Error object is generated if something -else causes an unforeseen exception to be raised. -""" - -# for Python 2.2 compatibilty -from __future__ import generators - -import autopath - -import cStringIO as StringIO -import inspect -import os -import sys -import traceback -import types -from std import path - -#TODO -# - add support for ignored tests (do we need to differentiate between -# skipped and ignored tests at all?) -# - support TestItem.run with different object spaces -# - unify naming of methods/functions; what about the TestCase class? -# - support for pickling and retrieving TestItems and TestResults? - -# -# custom TestCase class (adapted from Python's unittest module) -# -class TestCase: - """A class whose instances are single test cases. - - By default, the test code itself should be placed in a method named - 'runTest'. - - If the fixture may be used for many test cases, create as - many test methods as are needed. When instantiating such a TestCase - subclass, specify in the constructor arguments the name of the test method - that the instance is to execute. - - Test authors should subclass TestCase for their own tests. Construction - and deconstruction of the test's environment ('fixture') can be - implemented by overriding the 'setUp' and 'tearDown' methods respectively. - """ - def setUp(self): - "Hook method for setting up the test fixture before exercising it." - pass - - def tearDown(self): - "Hook method for deconstructing the test fixture after testing it." - pass - - def skip(self, msg=None): - """Skip this test by raising exception Skipped.""" - raise Skipped(msg=msg) - - def fail(self, msg=None): - """Fail immediately, with the given message.""" - raise Failure(msg=msg) - - def failIf(self, expr, msg=None): - """Fail the test if the expression is true.""" - if expr: - raise Failure(msg=msg) - - def failUnless(self, expr, msg=None): - """Fail the test unless the expression is true.""" - if not expr: - raise Failure(msg=msg) - - def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): - """ - Fail unless an exception of class excClass is thrown - by callableObj when invoked with arguments args and keyword - arguments kwargs. If a different type of exception is - thrown, it will not be caught, and the test case will be - deemed to have suffered an error, exactly as for an - unexpected exception. - """ - try: - callableObj(*args, **kwargs) - except excClass: - return - else: - if hasattr(excClass,'__name__'): - excName = excClass.__name__ - else: - excName = str(excClass) - raise Failure(msg=excName) - - def failUnlessEqual(self, first, second, msg=None): - """ - Fail if the two objects are unequal as determined by the '==' - operator. - """ - if not first == second: - raise Failure(msg=(msg or '%s != %s' % (`first`, `second`))) - - def failIfEqual(self, first, second, msg=None): - """ - Fail if the two objects are equal as determined by the '==' - operator. - """ - if first == second: - raise Failure(msg=(msg or '%s == %s' % (`first`, `second`))) - - def failUnlessAlmostEqual(self, first, second, places=7, msg=None): - """ - Fail if the two objects are unequal as determined by their - difference rounded to the given number of decimal places - (default 7) and comparing to zero. - - Note that decimal places (from zero) is usually not the same - as significant digits (measured from the most signficant digit). - """ - if round(second-first, places) != 0: - raise Failure(msg=(msg or '%s != %s within %s places' % - (`first`, `second`, `places`))) - - def failIfAlmostEqual(self, first, second, places=7, msg=None): - """ - Fail if the two objects are equal as determined by their - difference rounded to the given number of decimal places - (default 7) and comparing to zero. - - Note that decimal places (from zero) is usually not the same - as significant digits (measured from the most signficant digit). - """ - if round(second-first, places) == 0: - raise Failure(msg=(msg or '%s == %s within %s places' % - (`first`, `second`, `places`))) - - # aliases - assertEqual = assertEquals = failUnlessEqual - assertNotEqual = assertNotEquals = failIfEqual - assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual - assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual - assertRaises = failUnlessRaises - assert_ = failUnless - - -# provide services from TestCase class also to test functions, e. g. -# def test_func4711(): -# service.assertEqual(3, 3.0, msg="objects with same value should be equal") -#XXX maybe use another name instead of 'service' -service = TestCase() - -# -# TestResult class family -# -class TestResult(Exception): - """Abstract class representing the outcome of a test.""" - def __init__(self, msg="", item=None): - Exception.__init__(self, msg) - self.msg = msg - self.item = item - self.name = self.__class__.__name__ - self.traceback = None - - #XXX possibly, we need an attribute/method has_traceback? - - def __eq__(self, other): - """ - Return True if both TestResult objects are semantically the same. - Else, return False. - """ - # trivial case - if (self is other) or (self.item is other.item): - return True - return False - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return id(self.item) - -class Success(TestResult): - pass - -class Skipped(TestResult): - pass - -class Ignored(TestResult): - pass - - -class TestResultWithTraceback(TestResult): - def __init__(self, msg='', item=None): - TestResult.__init__(self, msg, item) - self.set_exception() - - def __eq__(self, other): - return TestResult.__eq__(self, other) and \ - self.formatted_traceback == other.formatted_traceback - - def set_exception(self): - self.excinfo = sys.exc_info() - self.traceback = self.excinfo[2] - # store formatted traceback - output = StringIO.StringIO() - args = self.excinfo + (None, output) - traceback.print_exception(*args) - # strip trailing newline - self.formatted_traceback = output.getvalue().rstrip() - -class Error(TestResultWithTraceback): - pass - -class Failure(TestResultWithTraceback): - pass - -# -# other classes -# -class TestItem: - """ - Represent either a test function, or a single test method from a - TestCase class. - """ - def __init__(self, callable_, name=None): - """ - Construct a test item. - - The argument callable_ must be a callable object, i. e. a - plain function, a bound or unbound method of a class, or an - object with __call__ attribute. - - The optional argument name can be a string which will be used - as the object's name. Else, the name will be tried to be - determined from the object's __name__ attribute. - """ - assert callable(callable_), \ - "must get a callable item, but got '%s'" % callable_ - self.callable = callable_ - # determine additional attributes (e. g. for error reporting) - self.call_via_class = False - # - class - if hasattr(callable_, 'im_class'): - # unbound and bound methods; __class__ would be instancemethod, - # not the one containing the methods - self.cls = callable_.im_class - if callable_.im_self is None: - # unbound methods are not directly callable without - # arguments - self.call_via_class = True - elif hasattr(callable_, '__class__') and \ - not inspect.isfunction(callable_): - # class instances with __call__ attribute - self.cls = callable_.__class__ - else: - self.cls = None - # - module (sometimes, using the class works better than the callable) - self.module = inspect.getmodule(self.cls or callable_) - # - name - try: - self.name = name or callable_.__name__ - except AttributeError: - self.name = '' - # - full name (including module and class, if applicable) - try: - parts = [self.module.__name__] - except AttributeError: - parts = [] - if self.cls: - parts.append(self.cls.__name__) - parts.append(self.name) - self.full_name = '.'.join(parts) - # - file - try: - if self.module is None: - self.file = inspect.getsourcefile(self.cls or callable_) - else: - self.file = inspect.getsourcefile(self.module) - except IOError: - self.file = '' - except TypeError: - self.file = '' - # - docstrings - self.docs = (self._docstring(self.module), self._docstring(self.cls), - self._docstring(self.callable)) - # - source code properties - #XXX inspect.getsourcelines may fail if the file path stored - # in a module's pyc/pyo file doesn't match the py file's - # actual location. This can happen if a py file, together with - # its pyc/pyo file is moved to a new location. See Python - # bug "[570300] inspect.getmodule symlink-related failure": - # http://sourceforge.net/tracker/index.php?func=detail&aid=570300&group_id=5470&atid=105470 - try: - lines, self.lineno = inspect.getsourcelines(callable) - # removing trailing newline(s) but not the indentation - self.source = ''.join(lines).rstrip() - except IOError: - self.source, self.lineno = '', None - except TypeError: - self.source, self.lineno = '', None - - def _docstring(self, obj): - """ - Return the docstring of object obj or an empty string, if the - docstring doesn't exist, i. e. is None. - """ - if obj is None: - return None - return inspect.getdoc(obj) or "" - - def __eq__(self, other): - """ - Return True if this and the other item compare equal. (This doesn't - necessarily mean that they are the same object.) Else, return False. - """ - # trivial case - if self is other: - return True - # If module, cls and unbound method are the same, the files must - # also be equal. For the methods, we compare the names, not the - # methods themselves; see - # http://mail.python.org/pipermail/python-list/2002-September/121655.html - # for an explanation. - if (self.module is other.module) and (self.cls is other.cls) and \ - (self.callable.__name__ == other.callable.__name__): - return True - return False - - def __ne__(self, other): - return not (self == other) - - def __hash__(self): - return id(self.module) ^ id(self.cls) - - # credit: adapted from Python's unittest.TestCase.run - def run(self, test_runner=lambda callable: callable()): - """ - Run this TestItem and return a corresponding TestResult object. - - If the test item corresponds to a class method, the setUp and - tearDown methods of the associated class are called before and - after the invocation of the test method, repectively. - - If the optional argument test_runner is absent, the test function - or method is merely called with no arguments. Else, test_runner - must be a callable accepting one argument. Instead of only calling - the test callable, the test_runner object will be called with the - test function/method as its argument. - """ - if self.call_via_class: - # turn the test callable, an unbound method, into a bound method - cls_object = self.cls() - test = getattr(cls_object, self.callable.__name__) - else: - # use the test function directly - test = self.callable - - try: - # call setUp only for a class - self.call_via_class and cls_object.setUp() - except KeyboardInterrupt: - raise - except TestResult, result: - # reconstruct TestResult object, implicitly set exception - return result.__class__(msg=result.msg, item=self) - except Exception, exc: - return Error(msg=str(exc), item=self) - - try: - test_runner(test) - result = Success(msg='success', item=self) - except KeyboardInterrupt: - raise - except TestResult, result: - # reconstruct TestResult object, implicitly set exception - result = result.__class__(msg=result.msg, item=self) - except Exception, exc: - result = Error(msg=str(exc), item=self) - - try: - # call tearDown only for a class - self.call_via_class and cls_object.tearDown() - except KeyboardInterrupt: - raise - except Exception, exc: - # if we already had an exception in the test method, - # don't overwrite/mask it - if result.traceback is None: - result = Error(msg=str(exc), item=self) - return result - - def __str__(self): - return "TestItem from %s" % self.full_name - - def __repr__(self): - return "<%s at %#x>" % (str(self), id(self)) - - -class TestSuite: - """Represent a collection of test items.""" - def __init__(self): - self.reset() - - def reset(self): - """ - Clear this TestSuite instance from all stored items and - test results. - """ - self.items = [] - self.last_results = {} - - # - # get lists of TestItems from a class, a module, or a directory tree - # - def _module_from_modpath(self, modpath): - """ - Return a module object derived from the module path - (e. g. "pypy.module.builtin.test.test_minmax"). - """ - # This __import__ call is only used to ensure that the module - # is present in sys.modules. Unfortunately, the module returned - # from the __import__ function doesn't correspond to the last - # component of the module path but the first. In the example - # listed in the docstring we thus would get the pypy module - # (i. e. package), not the test_minmax module. - __import__(modpath) - return sys.modules[modpath] - - def _add_items(self, items): - """Add TestItems from list 'items' to TestSuite.""" - self.items.extend(items) - - def _items_from_class(self, cls): - """ - Return TestItems extracted from class cls. - - This includes all unbound methods whose names start with - "test_". - """ - items = [] - for attrname in cls.__dict__: - # don't use cls.__dict__[attrname]; for unbound methods, - # we would get function objects, i. e. - # cls.__dict__[attrname] != getattr(cls, attrname) - attr = getattr(cls, attrname) - if callable(attr) and attrname.startswith("test_"): - items.append(TestItem(attr, attrname)) - return items - - def _items_from_module(self, module): - """ - Return TestItems extracted from module. - - This includes all TestItems of classes derived from - TestCase and functions whose names start with "test_". - """ - items = [] - for attrname in module.__dict__: - # see comment in _items_from_class - attr = getattr(module, attrname) - if inspect.isclass(attr) and issubclass(attr, TestCase): - items.extend(self._items_from_class(attr)) - elif inspect.isfunction(attr) and attrname.startswith("test_"): - items.append(TestItem(attr, attrname)) - return items - - def _items_from_dir(self, dirname, filterfunc=None, recursive=True): - """ - Return a list of TestItems found by reading the directory denoted - by dirname. Find all test modules in it. Test modules are files that - comply with the shell pattern "test_*.py". - - filterfunc is a callable that can be used to filter the test - modules by module path. By default, all test modules are used. - - If recursive is true, which is the default, find all test modules - by scanning the start directory recursively. - """ - items = [] - dirname = path.local(dirname) - - def testfilefilter(path): - return path.check(file=1, fnmatch='test_*.py') - def recfilter(path): - return recursive and path.check(dotfile=0) - - for testfn in dirname.visit(testfilefilter, recfilter): - # strip the leading pypy directory and the .py suffix - modpath = str(testfn)[len(autopath.pypydir)+1:-3] - modpath = 'pypy.' + modpath.replace(os.sep, '.') - if (filterfunc is None) or filterfunc(modpath): - try: - module = self._module_from_modpath(modpath) - module_items = self._items_from_module(module) - except: - print >> sys.stderr, \ - "Warning: can't load module %s" % modpath - #raise - else: - items.extend(module_items) - return items - - def add(self, *args): - """ - Extract TestItems from the given args and add them to this - TestSuite. - - The given objects can be: - - callable (function, unbound or bound method, class instance - with __call__ attribute): convert to TestItem - - class: extract all test methods, i. e. whose names start - with "test_" - - module: extract all test classes, i. e. classes derived - from newtest.TestCase, and all functions whose names - start with "test_" - - string: interpret the string as a file system path and - search it for Python files located in (sub)directories - named "test" and matching the shell pattern "test_*.py" - """ - for arg in args: - if isinstance(arg, (types.ClassType, types.TypeType)): - self._add_items(self._items_from_class(arg)) - elif callable(arg): - self._add_items([TestItem(arg)]) - elif isinstance(arg, types.ModuleType): - self._add_items(self._items_from_module(arg)) - elif isinstance(arg, (str, unicode)): - self._add_items(self._items_from_dir(arg)) - else: - raise TypeError("unsupported TestItem source '%s'" % arg) - - # - # running tests and getting results - # - def result_generator(self, - classify=lambda result: result.item.module.__name__): - """ - Return a generator to get the test result for each test item. - - The optional argument classify must be callable which accepts - a TestResult instance as the argument and returns something - that can be used as a dictionary key. - - During the iteration over the generator, the TestSuite object - will contain a dictionary named lastresult which maps these - keys to a list of TestResult objects that correspond to the key. - """ - self.last_results = {} - for item in self.items: - result = item.run() - key = classify(result) - self.last_results.setdefault(key, []).append(result) - yield result - - def run(self): - """ - Run all the test items and return a list of the results. After - that, the results are available via the attribute last_results. - """ - # perform all the tests by using the existing generator; discard - # the results; they are then available via self.last_results - return [result for result in self.result_generator()] - - -def _print_results(suite): - """Print results for the items in a test suite.""" - # iterate over tests and collect data - for result in suite.result_generator(): - if result.traceback is None: - continue - print 79 * '-' - # print a line with the qualified name of the bad callable - item = result.item - print "%s: %s" % (item.full_name, result.name.upper()) - print - print result.formatted_traceback - # emit a summary - print 79 * '=' - modules = suite.last_results.keys() - modules.sort() - for module in modules: - results = suite.last_results[module] - resultstring = '' - for result in results: - status_char = {Success: '.', Ignored: 'i', Skipped: 's', - Error: 'E', Failure: 'F'}[result.__class__] - resultstring += status_char - print "%s [%d] %s" % (module, len(results), resultstring) - -def main(): - """ - Find all tests in the current module (i. e. the module from which this - function is called), execute them and print results. - """ - import __main__ - from pypy.tool import newtest - suite = TestSuite() - suite.add(__main__) - _print_results(suite) - -def test(do_selftest=False): - # possibly ignore dummy unit tests - if do_selftest: - # include only selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") != -1 - else: - # exclude selftest module - filterfunc = lambda m: m.find("pypy.tool.testdata.") == -1 - # collect tests - suite = TestSuite() - print "Loading test modules ..." - suite.init_from_dir(autopath.pypydir, filterfunc=filterfunc) - _print_results(suite) - - -if __name__ == '__main__': - # used to avoid subtle problems with class matching after different - # import statements - from pypy.tool import newtest - newtest.test(do_selftest=True) Deleted: /pypy/trunk/src/pypy/tool/test/test_newtest.py ============================================================================== --- /pypy/trunk/src/pypy/tool/test/test_newtest.py Mon Nov 15 19:40:09 2004 +++ (empty file) @@ -1,135 +0,0 @@ -import inspect -import new -import unittest - -import autopath -from pypy.tool import newtest - -#TODO test(s) for adding TestItems from directory - - -class TestTestItem(unittest.TestCase): - def _test_function(self, func, expected_name): - item = newtest.TestItem(func) - self.assertEqual(item.name, expected_name) - self.assertEqual(item.call_via_class, False) - self.assertEqual(item.cls, None) - self.failUnless(item.module is module) - self.assertEqual(item.file, file) - - def test_plain_function(self): - f = lambda: 'anything' - self._test_function(f, expected_name='') - def f(): pass - self._test_function(f, expected_name='f') - - def test_bound_method(self): - class X: - def f(self): pass - x = X() - item = newtest.TestItem(x.f) - self.assertEqual(item.name, 'f') - self.assertEqual(item.call_via_class, False) - self.failUnless(item.cls is X) - self.failUnless(item.module is module) - self.assertEqual(item.file, file) - - def test_unbound_method(self): - class X: - def f(self): pass - item = newtest.TestItem(X.f) - self.assertEqual(item.name, 'f') - self.assertEqual(item.call_via_class, True) - self.failUnless(item.cls is X) - self.failUnless(item.module is module) - self.assertEqual(item.file, file) - - def test_class_instance(self): - class X: - def __call__(self): pass - item = newtest.TestItem(X()) - self.assertEqual(item.name, '') - self.assertEqual(item.call_via_class, False) - self.failUnless(item.cls is X) - self.failUnless(item.module is module) - self.assertEqual(item.file, file) - - #XXX best way to trigger execptions in TestItem's constructor - # without getting rather complicated? - - def test_docstrings(self): - class X: - def f(self): - "Method docstring" - item = newtest.TestItem(X.f) - self.assertEqual(item.docs, ('', '', "Method docstring")) - - class X: - "Class docstring" - def f(self): pass - item = newtest.TestItem(X.f) - self.assertEqual(item.docs, ('', "Class docstring", '')) - - def test_name_argument(self): - def f(): pass - item = newtest.TestItem(f, 'g') - self.assertEqual(item.name, 'g') - - -class TestTestSuite(unittest.TestCase): - def check_names(self, test_suite, expected_item_names): - item_names = [item.name for item in test_suite.items] - item_names.sort() - expected_item_names.sort() - self.assertEqual(item_names, expected_item_names) - - def test_items_from_callables(self): - def f(): pass - g = lambda: None - class X: - def thisone(self): pass - ts = newtest.TestSuite() - ts.add(f, g, X.thisone) - self.check_names(ts, ['f', '', 'thisone']) - # add a bound method and an instance with __call__ attribute - class Y: - def thatone(self): pass - class Z: - def __call__(self): pass - ts.add(Y().thatone, Z()) - self.check_names(ts, ['f', '', 'thisone', 'thatone', - '']) - - def test_items_from_class(self): - class X: - """Docstring - don't find it.""" - def test_this(self): pass - def no_test(self): pass - def test_that(self): pass - ts = newtest.TestSuite() - ts.add(X) - self.check_names(ts, ['test_this', 'test_that']) - - def test_items_from_module(self): - mod = new.module('new_module') - class X(newtest.TestCase): - "Don't add docstring." - def dont_add_method(self): pass - def test_this_method(self): pass - def dont_add(): pass - def add_this(): pass - for name, object in [('X', X), ('dont_add', dont_add), - ('test_other_name', add_this)]: - setattr(mod, name, object) - ts = newtest.TestSuite() - ts.add(mod) - self.check_names(ts, ['test_this_method', 'test_other_name']) - - -# used in unit tests above; placed here, so that TestTestItem is accessible -module = inspect.getmodule(TestTestItem) -file = inspect.getsourcefile(TestTestItem) - - -if __name__ == '__main__': - unittest.main() From arigo at codespeak.net Tue Nov 16 09:24:51 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 09:24:51 +0100 (MET) Subject: [pypy-svn] r7262 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041116082451.B19155A70E@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 09:24:50 2004 New Revision: 7262 Modified: pypy/trunk/src/pypy/translator/tool/flowtrace.py Log: forgot to change a call to simplify_graph() Modified: pypy/trunk/src/pypy/translator/tool/flowtrace.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/flowtrace.py (original) +++ pypy/trunk/src/pypy/translator/tool/flowtrace.py Tue Nov 16 09:24:50 2004 @@ -226,7 +226,7 @@ func = self.space.unwrap(w_func) if hasattr(func, "func_code"): graph = self.flow_space.build_flow(func) - graph = simplify_graph(graph) + simplify_graph(graph) if self.debug: debug(func) return self.execute_function(graph, *args_w) From bob at codespeak.net Tue Nov 16 10:23:54 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 10:23:54 +0100 (MET) Subject: [pypy-svn] r7263 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116092354.0371C5AA26@thoth.codespeak.net> Author: bob Date: Tue Nov 16 10:23:54 2004 New Revision: 7263 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: beginnings of a new event system and UI for the viewer tool Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 10:23:54 2004 @@ -1,10 +1,29 @@ from __future__ import generators import autopath -import os, time +import os, time, sys import pygame from pygame.locals import * from drawgraph import GraphRenderer + +METAKEYS = dict([ + (ident[len('KMOD_'):].lower(), getattr(pygame.locals, ident)) + for ident in dir(pygame.locals) if ident.startswith('KMOD_') and ident != 'KMOD_NONE' +]) + +if sys.platform == 'darwin': + PMETA = 'lmeta' +else: + PMETA = 'lalt' + +METAKEYS['meta'] = METAKEYS[PMETA] +METAKEYS['shift'] = METAKEYS['lshift'] + +KEYS = dict([ + (ident[len('K_'):].lower(), getattr(pygame.locals, ident)) + for ident in dir(pygame.locals) if ident.startswith('K_') +]) + class Display(object): def __init__(self, (w,h)=(800,740)): @@ -14,35 +33,89 @@ def resize(self, (w,h)): self.width = w self.height = h - self.screen = pygame.display.set_mode((w, h), HWSURFACE|RESIZABLE) + self.screen = pygame.display.set_mode((w, h), HWSURFACE|RESIZABLE, 32) class GraphDisplay(Display): STATUSBARFONT = os.path.join(autopath.this_dir, 'VeraMoBd.ttf') ANIM_STEP = 0.07 + KEYS = { + 'meta =' : ('zoom', 1), + 'meta -' : ('zoom', -1), + 'meta 0' : 'zoom_actual_size', + 'meta 1' : 'zoom_to_fit', + 'meta q' : 'quit', + 'escape' : 'quit', + 'meta f4' : 'quit', + #'meta left' : 'go_back', + #'meta right' : 'go_forward', + 'meta left': 'layout_back', + 'p' : 'layout_back', + 'backspace' : 'layout_back', + 'left' : ('pan', (-1, 0)), + 'right' : ('pan', (1, 0)), + 'up' : ('pan', (0, -1)), + 'down' : ('pan', (0, 1)), + 'shift left' : ('fast_pan', (-1, 0)), + 'shift right' : ('fast_pan', (1, 0)), + 'shift up' : ('fast_pan', (0, -1)), + 'shift down' : ('fast_pan', (0, 1)), + } + + def __init__(self, layout): super(GraphDisplay, self).__init__() self.font = pygame.font.Font(self.STATUSBARFONT, 16) self.viewers_history = [] self.viewer = None self.method_cache = {} + self.key_cache = {} + self.initialize_keys() self.setlayout(layout) + def initialize_keys(self): + for strnames, methodname in self.KEYS.iteritems(): + names = strnames.split() + mod = 0 + key = 0 + if not isinstance(methodname, basestring): + methodname, args = methodname[0], methodname[1:] + else: + args = () + for name in names: + if name in METAKEYS: + mod |= METAKEYS[name] + elif name in KEYS: + key = KEYS[name] + else: + assert len(name) == 1 + key = ord(name) + method = getattr(self, methodname, None) + if method is None: + print 'Can not implement key mapping %r, %s.%s does not exist' % ( + strnames, self.__class__.__name__, methodname) + self.key_cache[(key, mod)] = (method, args) + def setlayout(self, layout): if self.viewer: self.viewers_history.append(self.viewer) self.layout = layout self.viewer = GraphRenderer(self.screen, layout) - # center and scale to view the whole graph + self.zoom_to_fit() + + def zoom_to_fit(self): + """ + center and scale to view the whole graph + """ self.viewer.setoffset((self.viewer.width - self.width) // 2, (self.viewer.height - self.height) // 2) f = min(float(self.width-40) / self.viewer.width, - float(self.height-40) / self.viewer.height) - if f < 1.0: - self.viewer.shiftscale(f) + float(self.height-40) / self.viewer.height, + 1.0) + self.viewer.shiftscale(f) self.updated_viewer() - + def updated_viewer(self): self.sethighlight() self.statusbarinfo = None @@ -223,10 +296,9 @@ self.notifymousepos(event.pos) def process_KeyDown(self, event): - if event.key in [K_p, K_LEFT, K_BACKSPACE]: - self.layout_back() - elif event.key == K_ESCAPE: - self.events.insert(0, pygame.event.Event(QUIT)) + method, args = self.key_cache.get((event.key, event.mod), (None, None)) + if method is not None: + method(*args) def process_VideoResize(self, event): # short-circuit if there are more resize events pending @@ -236,8 +308,11 @@ self.must_redraw = True def process_Quit(self, event): - raise StopIteration + self.quit() + def quit(self): + raise StopIteration + def run(self): self.dragging = self.click_origin = self.click_time = None events = self.events = [] From hpk at codespeak.net Tue Nov 16 10:47:46 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 10:47:46 +0100 (MET) Subject: [pypy-svn] r7264 - pypy/trunk/src/pypy/interpreter/test Message-ID: <20041116094746.CB5C25AF2E@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 10:47:46 2004 New Revision: 7264 Modified: pypy/trunk/src/pypy/interpreter/test/test_main.py Log: avoid using yet another class from CPython (StringIO) and just use a file (which we have to "fake" anyway) Modified: pypy/trunk/src/pypy/interpreter/test/test_main.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_main.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_main.py Tue Nov 16 10:47:46 2004 @@ -1,6 +1,7 @@ import unittest import autopath from cStringIO import StringIO +from pypy.tool.udir import udir from pypy.tool import testit from pypy.interpreter.baseobjspace import OperationError @@ -17,20 +18,20 @@ testresultoutput = '11\n' -capture = StringIO() def checkoutput(expected_output,f,*args): space = testit.objspace() w_sys = space.get_builtin_module("sys") w_oldout = space.getattr(w_sys, space.wrap("stdout")) - capture.reset() - space.setattr(w_sys, space.wrap("stdout"), space.wrap(capture)) + capturefn = udir.join('capturefile') + capturefile = capturefn.open('w') + space.setattr(w_sys, space.wrap("stdout"), space.wrap(capturefile)) try: f(*(args + (space,))) finally: space.setattr(w_sys, space.wrap("stdout"), w_oldout) - - return capture.getvalue() == expected_output + capturefile.close() + return capturefn.read() == expected_output testfn = 'tmp_hello_world.py' From hpk at codespeak.net Tue Nov 16 10:49:31 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 10:49:31 +0100 (MET) Subject: [pypy-svn] r7265 - in pypy/trunk/src: goal pypy/module/test Message-ID: <20041116094931.DB2C15AF31@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 10:49:31 2004 New Revision: 7265 Modified: pypy/trunk/src/goal/testcachebuild.py pypy/trunk/src/pypy/module/test/test_import.py Log: trigger building the caches with some (somewhat random) application code fixed the test_import to use temporary gateways (that don't participate in the space's cache) Modified: pypy/trunk/src/goal/testcachebuild.py ============================================================================== --- pypy/trunk/src/goal/testcachebuild.py (original) +++ pypy/trunk/src/goal/testcachebuild.py Tue Nov 16 10:49:31 2004 @@ -1,28 +1,57 @@ from pypy.tool import option, autopath, testit from pypy.interpreter import gateway from pypy.tool.frozendict import frozendict +import os ####################################################### -def app_triggergenerator(): +def app_triggerall(): + import sys, types # , exceptions + k = 42 def gen(): - yield 42 + yield k + #yield (k, 1.0, 4L, [''], {}, unicode, Ellipsis) + try: + raise ValueError + except ValueError: + x = sys.exc_info() + try: + raise x[0], x[1], x[2] + except ValueError: + pass + + gen.func_code.co_name + str({'co_name': ('f',)}), str(object.__init__.im_func.func_code) + "for %r" % ({'x': gen}) + ("%02d"%1) + ("%05d"%1) + ("%-05d"%1) + ("%04f"%2.25) + ("%05g"%2.25) + ("%-05g"%2.25) + ("%05s"%2.25) + ('<%s>' % [1,2]) + ('<%s-%s>' % ([1,2], [3,4])) + for x in gen(): pass + +def app_triggerexec(): + exec "i=3" gateway.importall(globals()) # app_xxx() -> xxx() ####################################################### def triggercachebuild(space): - triggergenerator(space) + triggerall(space) + triggerexec(space) if __name__ == '__main__': space = option.objspace('std') - #triggercachebuild(space) - testit.main(autopath.pypydir) - + triggercachebuild(space) + #testit.main(autopath.pypydir) space._typecache = frozendict(space._typecache) space._faketypecache = frozendict(space._faketypecache) space._gatewaycache = frozendict(space._gatewaycache) - testit.main(autopath.pypydir) + testit.main(os.path.join(autopath.pypydir)) # , 'objspace', 'std')) Modified: pypy/trunk/src/pypy/module/test/test_import.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_import.py (original) +++ pypy/trunk/src/pypy/module/test/test_import.py Tue Nov 16 10:49:31 2004 @@ -9,7 +9,7 @@ sys.path.append(dn) return sys.modules.copy() -_setup = gateway.app2interp(_setup,'setup') +_setup = gateway.app2interp_temp(_setup,'setup') def _teardown(saved_modules): import sys @@ -17,7 +17,7 @@ sys.modules.clear() sys.modules.update(saved_modules) -_teardown = gateway.app2interp(_teardown,'teardown') +_teardown = gateway.app2interp_temp(_teardown,'teardown') class TestImport(testit.AppTestCase): From bob at codespeak.net Tue Nov 16 10:51:28 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 10:51:28 +0100 (MET) Subject: [pypy-svn] r7266 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116095128.0B8D15AF33@thoth.codespeak.net> Author: bob Date: Tue Nov 16 10:51:27 2004 New Revision: 7266 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: add some zooming keys Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 10:51:27 2004 @@ -41,8 +41,8 @@ ANIM_STEP = 0.07 KEYS = { - 'meta =' : ('zoom', 1), - 'meta -' : ('zoom', -1), + 'meta -' : ('zoom', 0.5), + 'meta =' : ('zoom', 2.0), 'meta 0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', 'meta q' : 'quit', @@ -71,6 +71,7 @@ self.viewer = None self.method_cache = {} self.key_cache = {} + self.status_bar_height = 0 self.initialize_keys() self.setlayout(layout) @@ -104,20 +105,41 @@ self.viewer = GraphRenderer(self.screen, layout) self.zoom_to_fit() + def zoom_actual_size(self): + # XXX - HACK HACK HACK + #self.update_status_bar() + #self.drawstatusbar() + + self.viewer.shiftscale(self.viewer.SCALEMAX / self.viewer.scale) + #self.viewer.setoffset((self.viewer.width - self.width) // 2, + # (self.viewer.height - (self.height - self.status_bar_height)) // 2) + self.updated_viewer() + + def calculate_zoom_to_fit(self): + return min(float(self.width) / self.viewer.width, + float(self.height - self.status_bar_height) / self.viewer.height, + 1.0) + def zoom_to_fit(self): """ center and scale to view the whole graph """ - self.viewer.setoffset((self.viewer.width - self.width) // 2, - (self.viewer.height - self.height) // 2) - f = min(float(self.width-40) / self.viewer.width, - float(self.height-40) / self.viewer.height, - 1.0) + + # XXX - HACK HACK HACK + self.update_status_bar() + self.drawstatusbar() + + f = self.calculate_zoom_to_fit() self.viewer.shiftscale(f) + self.viewer.setoffset((self.viewer.width - self.width) // 2, + (self.viewer.height - (self.height - self.status_bar_height)) // 2) + self.updated_viewer() + + def zoom(self, scale): + self.viewer.shiftscale(max(scale, self.calculate_zoom_to_fit())) self.updated_viewer() - def updated_viewer(self): - self.sethighlight() + def update_status_bar(self): self.statusbarinfo = None self.must_redraw = True if self.viewers_history: @@ -126,6 +148,12 @@ info = ('Click to move around, or drag mouse buttons ' '(left to zoom, right to scroll)') self.setstatusbar(info) + + def updated_viewer(self): + self.sethighlight() + self.statusbarinfo = None + self.must_redraw = True + self.update_status_bar() def layout_back(self): if self.viewers_history: @@ -161,7 +189,8 @@ totalh += h y = self.height - totalh - self.screen.fill(bgcolor, (0, y-16, self.width, totalh+16)) + self.status_bar_height = totalh + 16 + self.screen.fill(bgcolor, (0, y-16, self.width, self.status_bar_height)) for img in lines: w, h = img.get_size() self.screen.blit(img, ((self.width-w)//2, y-8)) @@ -324,6 +353,8 @@ self.viewer.render() if self.statusbarinfo: self.drawstatusbar() + else: + self.status_bar_height = 0 pygame.display.flip() self.must_redraw = False From bob at codespeak.net Tue Nov 16 11:14:25 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 11:14:25 +0100 (MET) Subject: [pypy-svn] r7267 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116101425.2C9EA5AF36@thoth.codespeak.net> Author: bob Date: Tue Nov 16 11:14:24 2004 New Revision: 7267 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: implement panning Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:14:24 2004 @@ -138,6 +138,13 @@ def zoom(self, scale): self.viewer.shiftscale(max(scale, self.calculate_zoom_to_fit())) self.updated_viewer() + + def pan(self, (x, y)): + self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8)) + self.updated_viewer() + + def fast_pan(self, (x, y)): + self.pan((x * 4, y * 4)) def update_status_bar(self): self.statusbarinfo = None From bob at codespeak.net Tue Nov 16 11:14:42 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 11:14:42 +0100 (MET) Subject: [pypy-svn] r7268 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116101442.8DCB35AF3A@thoth.codespeak.net> Author: bob Date: Tue Nov 16 11:14:42 2004 New Revision: 7268 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: remove commented junk Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:14:42 2004 @@ -106,13 +106,7 @@ self.zoom_to_fit() def zoom_actual_size(self): - # XXX - HACK HACK HACK - #self.update_status_bar() - #self.drawstatusbar() - self.viewer.shiftscale(self.viewer.SCALEMAX / self.viewer.scale) - #self.viewer.setoffset((self.viewer.width - self.width) // 2, - # (self.viewer.height - (self.height - self.status_bar_height)) // 2) self.updated_viewer() def calculate_zoom_to_fit(self): From mgedmin at codespeak.net Tue Nov 16 11:15:12 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 11:15:12 +0100 (MET) Subject: [pypy-svn] r7269 - in pypy/trunk/src/pypy/interpreter: . test Message-ID: <20041116101512.E64295AF3C@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 11:15:12 2004 New Revision: 7269 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/interpreter/test/test_interpreter.py Log: Bugfix: when an import statement was executed in a function without a locals dict, a plain unwrapped None could be passed into space.call_function causing assertion errors later on. Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Tue Nov 16 11:15:12 2004 @@ -614,8 +614,11 @@ raise raise OperationError(space.w_ImportError, space.wrap("__import__ not found")) + w_locals = f.w_locals + if w_locals is None: # CPython does this + w_locals = space.w_None w_obj = space.call_function(w_import, space.wrap(modulename), - f.w_globals, f.w_locals, w_fromlist) + f.w_globals, w_locals, w_fromlist) f.valuestack.push(w_obj) def IMPORT_STAR(f): Modified: pypy/trunk/src/pypy/interpreter/test/test_interpreter.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_interpreter.py Tue Nov 16 11:15:12 2004 @@ -1,4 +1,5 @@ import autopath +import textwrap from pypy.tool import testit class TestInterpreter(testit.TestCase): @@ -142,6 +143,24 @@ self.assertEquals(self.codetest(code, 'f', [9]), 1+2+3 + 5+6+7+8+900) + def test_import(self): + # Regression test for a bug in PyInterpFrame.IMPORT_NAME: when an + # import statement was executed in a function without a locals dict, a + # plain unwrapped None could be passed into space.call_function causing + # assertion errors later on. + real_call_function = self.space.call_function + def safe_call_function(w_obj, *arg_w): + for arg in arg_w: + assert arg is not None + return real_call_function(w_obj, *arg_w) + self.space.call_function = safe_call_function + code = textwrap.dedent(''' + def f(): + import sys + ''') + self.codetest(code, 'f', []) + + class AppTestInterpreter(testit.AppTestCase): def test_trivial(self): x = 42 From bob at codespeak.net Tue Nov 16 11:27:46 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 11:27:46 +0100 (MET) Subject: [pypy-svn] r7270 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116102746.C8D9C5AF3E@thoth.codespeak.net> Author: bob Date: Tue Nov 16 11:27:46 2004 New Revision: 7270 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: translucent status bar Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:27:46 2004 @@ -191,11 +191,15 @@ y = self.height - totalh self.status_bar_height = totalh + 16 - self.screen.fill(bgcolor, (0, y-16, self.width, self.status_bar_height)) + block = pygame.Surface((self.width, self.status_bar_height), SWSURFACE | SRCALPHA) + block.fill(bgcolor) + sy = 16 for img in lines: w, h = img.get_size() - self.screen.blit(img, ((self.width-w)//2, y-8)) - y += h + block.blit(img, ((self.width-w)//2, sy-8)) + sy += h + block.set_alpha(int(255 * 0.75)) + self.screen.blit(block, (0, y-16)) def notifymousepos(self, pos): word = self.viewer.at_position(pos) From mgedmin at codespeak.net Tue Nov 16 11:29:52 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 11:29:52 +0100 (MET) Subject: [pypy-svn] r7271 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116102952.C12FF5AF40@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 11:29:52 2004 New Revision: 7271 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Changed the default size of the pygame window to 800x680 -- 800x740 is a bit too small for us poor folks with 1024x768 screens with two 24-pixel high GNOME panels. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:29:52 2004 @@ -26,7 +26,7 @@ class Display(object): - def __init__(self, (w,h)=(800,740)): + def __init__(self, (w,h)=(800,680)): pygame.init() self.resize((w,h)) From bob at codespeak.net Tue Nov 16 11:32:08 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 11:32:08 +0100 (MET) Subject: [pypy-svn] r7272 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116103208.EB6CA5AF42@thoth.codespeak.net> Author: bob Date: Tue Nov 16 11:32:08 2004 New Revision: 7272 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: add a forward history as well Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:32:08 2004 @@ -48,8 +48,7 @@ 'meta q' : 'quit', 'escape' : 'quit', 'meta f4' : 'quit', - #'meta left' : 'go_back', - #'meta right' : 'go_forward', + 'meta right' : 'layout_forward', 'meta left': 'layout_back', 'p' : 'layout_back', 'backspace' : 'layout_back', @@ -68,6 +67,7 @@ super(GraphDisplay, self).__init__() self.font = pygame.font.Font(self.STATUSBARFONT, 16) self.viewers_history = [] + self.forward_viewers_history = [] self.viewer = None self.method_cache = {} self.key_cache = {} @@ -101,6 +101,7 @@ def setlayout(self, layout): if self.viewer: self.viewers_history.append(self.viewer) + del self.forward_viewers_history[:] self.layout = layout self.viewer = GraphRenderer(self.screen, layout) self.zoom_to_fit() @@ -158,10 +159,18 @@ def layout_back(self): if self.viewers_history: + self.forward_viewers_history.append(self.viewer) self.viewer = self.viewers_history.pop() self.layout = self.viewer.graphlayout self.updated_viewer() + def layout_forward(self): + if self.forward_viewers_history: + self.viewers_history.append(self.viewer) + self.viewer = self.forward_viewers_history.pop() + self.layout = self.viewer.graphlayout + self.updated_viewer() + def setstatusbar(self, text, fgcolor=(255,255,80), bgcolor=(128,0,0)): info = (text, fgcolor, bgcolor) if info != self.statusbarinfo: From mgedmin at codespeak.net Tue Nov 16 11:34:27 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 11:34:27 +0100 (MET) Subject: [pypy-svn] r7273 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116103427.9B42E5AF44@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 11:34:27 2004 New Revision: 7273 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Fixed status line message -- now Left is used for panning, and Backspace (or Alt+Left) is used for going back. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 11:34:27 2004 @@ -145,7 +145,7 @@ self.statusbarinfo = None self.must_redraw = True if self.viewers_history: - info = 'Press Left Arrow to go back to previous screen' + info = 'Press Backspace to go back to previous screen' else: info = ('Click to move around, or drag mouse buttons ' '(left to zoom, right to scroll)') From bob at codespeak.net Tue Nov 16 11:58:06 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 11:58:06 +0100 (MET) Subject: [pypy-svn] r7274 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116105806.473255AF00@thoth.codespeak.net> Author: bob Date: Tue Nov 16 11:58:05 2004 New Revision: 7274 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: try very hard to render some useful text when zoomed out Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Tue Nov 16 11:58:05 2004 @@ -186,13 +186,18 @@ self.height = int((h + 2*self.MARGIN)*scale) self.bboxh = h size = int(15 * (scale-10) / 75) + self.font = self.getfont(size) + + def getfont(self, size): if size in self.FONTCACHE: - self.font = self.FONTCACHE[size] + return self.FONTCACHE[size] elif size < 4: - self.font = None + self.FONTCACHE[size] = None + return None else: - self.font = self.FONTCACHE[size] = pygame.font.Font(FONT, size) - + font = self.FONTCACHE[size] = pygame.font.Font(FONT, size) + return font + def setoffset(self, offsetx, offsety): "Set the (x,y) origin of the rectangle where the graph will be rendered." self.ofsx = offsetx - self.margin @@ -254,24 +259,43 @@ commands = [] bkgndcommands = [] - for line in lines: - raw_line = line.replace('\\l','').replace('\r','') or ' ' - img = TextSnippet(self, raw_line, (0, 0, 0), bgcolor) - w, h = img.get_size() - if w>wmax: wmax = w - if raw_line.strip(): - if line.endswith('\\l'): - def cmd(img=img, y=hmax): - img.draw(xleft, ytop+y) - elif line.endswith('\r'): - def cmd(img=img, y=hmax, w=w): - img.draw(xright-w, ytop+y) - else: - def cmd(img=img, y=hmax, w=w): - img.draw(xcenter-w//2, ytop+y) - commands.append(cmd) - hmax += h - #hmax += 8 + if self.font is None: + # does not run for now, we should have a second graph for low detail + if lines: + raw_line = lines[0].replace('\\l','').replace('\r','') + if raw_line: + for size in (12, 10, 8, 6, 4): + font = self.getfont(size) + img = TextSnippet(self, raw_line, (0, 0, 0), bgcolor, font=font) + w, h = img.get_size() + if (w >= boxwidth or h >= boxheight): + continue + else: + if w>wmax: wmax = w + def cmd(img=img, y=hmax, w=w): + img.draw(xcenter-w//2, ytop+y) + commands.append(cmd) + hmax += h + break + else: + for line in lines: + raw_line = line.replace('\\l','').replace('\r','') or ' ' + img = TextSnippet(self, raw_line, (0, 0, 0), bgcolor) + w, h = img.get_size() + if w>wmax: wmax = w + if raw_line.strip(): + if line.endswith('\\l'): + def cmd(img=img, y=hmax): + img.draw(xleft, ytop+y) + elif line.endswith('\r'): + def cmd(img=img, y=hmax, w=w): + img.draw(xright-w, ytop+y) + else: + def cmd(img=img, y=hmax, w=w): + img.draw(xcenter-w//2, ytop+y) + commands.append(cmd) + hmax += h + #hmax += 8 # we know the bounding box only now; setting these variables will # have an effect on the values seen inside the cmd() functions above @@ -394,11 +418,13 @@ class TextSnippet: - def __init__(self, renderer, text, fgcolor, bgcolor=None): + def __init__(self, renderer, text, fgcolor, bgcolor=None, font=None): self.renderer = renderer self.imgs = [] self.parts = [] - if renderer.font is None: + if font is None: + font = renderer.font + if font is None: return parts = self.parts for word in re_nonword.split(text): @@ -427,7 +453,7 @@ word = part[0] antialias = not re_nonword.match(word) # SDL bug with anti-aliasing try: - img = renderer.font.render(word, antialias, *part[1:]) + img = font.render(word, antialias, *part[1:]) except pygame.error: del parts[i] # Text has zero width else: From hpk at codespeak.net Tue Nov 16 12:03:06 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 12:03:06 +0100 (MET) Subject: [pypy-svn] r7275 - pypy/trunk/src/goal Message-ID: <20041116110306.10BC45AF4C@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 12:03:05 2004 New Revision: 7275 Added: pypy/trunk/src/goal/buildcache.py - copied, changed from r7269, pypy/trunk/src/goal/testcachebuild.py Removed: pypy/trunk/src/goal/testcachebuild.py Modified: pypy/trunk/src/goal/translate_pypy.py Log: almost integrate building of caches into translate_pypy.py (you just need to un-comment the buildcache(space) line) Copied: pypy/trunk/src/goal/buildcache.py (from r7269, pypy/trunk/src/goal/testcachebuild.py) ============================================================================== --- pypy/trunk/src/goal/testcachebuild.py (original) +++ pypy/trunk/src/goal/buildcache.py Tue Nov 16 12:03:05 2004 @@ -42,16 +42,18 @@ ####################################################### -def triggercachebuild(space): +def buildcache(space): + print "triggering cache build for %r" % space triggerall(space) triggerexec(space) + space._typecache = frozendict(space._typecache) + space._faketypecache = frozendict(space._faketypecache) + space._gatewaycache = frozendict(space._gatewaycache) + print "cache build finished, caches are 'frozen' now" if __name__ == '__main__': space = option.objspace('std') - triggercachebuild(space) + buildcache(space) #testit.main(autopath.pypydir) - space._typecache = frozendict(space._typecache) - space._faketypecache = frozendict(space._faketypecache) - space._gatewaycache = frozendict(space._gatewaycache) testit.main(os.path.join(autopath.pypydir)) # , 'objspace', 'std')) Deleted: /pypy/trunk/src/goal/testcachebuild.py ============================================================================== --- /pypy/trunk/src/goal/testcachebuild.py Tue Nov 16 12:03:05 2004 +++ (empty file) @@ -1,57 +0,0 @@ -from pypy.tool import option, autopath, testit -from pypy.interpreter import gateway -from pypy.tool.frozendict import frozendict -import os - -####################################################### -def app_triggerall(): - import sys, types # , exceptions - k = 42 - def gen(): - yield k - #yield (k, 1.0, 4L, [''], {}, unicode, Ellipsis) - try: - raise ValueError - except ValueError: - x = sys.exc_info() - try: - raise x[0], x[1], x[2] - except ValueError: - pass - - gen.func_code.co_name - str({'co_name': ('f',)}), str(object.__init__.im_func.func_code) - "for %r" % ({'x': gen}) - ("%02d"%1) - ("%05d"%1) - ("%-05d"%1) - ("%04f"%2.25) - ("%05g"%2.25) - ("%-05g"%2.25) - ("%05s"%2.25) - ('<%s>' % [1,2]) - ('<%s-%s>' % ([1,2], [3,4])) - - for x in gen(): - pass - -def app_triggerexec(): - exec "i=3" - -gateway.importall(globals()) # app_xxx() -> xxx() - -####################################################### - -def triggercachebuild(space): - triggerall(space) - triggerexec(space) - -if __name__ == '__main__': - space = option.objspace('std') - triggercachebuild(space) - #testit.main(autopath.pypydir) - space._typecache = frozendict(space._typecache) - space._faketypecache = frozendict(space._faketypecache) - space._gatewaycache = frozendict(space._gatewaycache) - - testit.main(os.path.join(autopath.pypydir)) # , 'objspace', 'std')) Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 16 12:03:05 2004 @@ -2,12 +2,12 @@ # # import autopath, sys - from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.objspace.std.intobject import W_IntObject from pypy.translator.translator import Translator from pypy.annotation import model as annmodel +import buildcache # __________ Entry point __________ @@ -23,6 +23,7 @@ global t t = Translator(entry_point, verbose=True, simplifying=True) space = StdObjSpace() + #buildcache.buildcache(space) a = t.annotate([annmodel.immutablevalue(space)]) a.simplify() From bob at codespeak.net Tue Nov 16 12:03:18 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 12:03:18 +0100 (MET) Subject: [pypy-svn] r7276 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116110318.3DB405AF4F@thoth.codespeak.net> Author: bob Date: Tue Nov 16 12:03:17 2004 New Revision: 7276 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: remove incorrect comment Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Tue Nov 16 12:03:17 2004 @@ -260,7 +260,6 @@ bkgndcommands = [] if self.font is None: - # does not run for now, we should have a second graph for low detail if lines: raw_line = lines[0].replace('\\l','').replace('\r','') if raw_line: From bob at codespeak.net Tue Nov 16 12:07:54 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 12:07:54 +0100 (MET) Subject: [pypy-svn] r7277 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116110754.6D3AF5AF9D@thoth.codespeak.net> Author: bob Date: Tue Nov 16 12:07:53 2004 New Revision: 7277 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: add keyboard repeat rate (500ms delay, 30ms repeat interval) Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 12:07:53 2004 @@ -39,6 +39,7 @@ class GraphDisplay(Display): STATUSBARFONT = os.path.join(autopath.this_dir, 'VeraMoBd.ttf') ANIM_STEP = 0.07 + KEY_REPEAT = (500, 30) KEYS = { 'meta -' : ('zoom', 0.5), @@ -76,6 +77,7 @@ self.setlayout(layout) def initialize_keys(self): + pygame.key.set_repeat(*self.KEY_REPEAT) for strnames, methodname in self.KEYS.iteritems(): names = strnames.split() mod = 0 From bob at codespeak.net Tue Nov 16 12:25:48 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 12:25:48 +0100 (MET) Subject: [pypy-svn] r7278 - pypy/trunk/src/pypy/annotation Message-ID: <20041116112548.2D0C25AB59@thoth.codespeak.net> Author: bob Date: Tue Nov 16 12:25:47 2004 New Revision: 7278 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: nicer looking repr for ListFactory and DictFactory Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 16 12:25:47 2004 @@ -97,6 +97,9 @@ class ListFactory: s_item = SomeImpossibleValue() + def __repr__(self): + return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) + def create(self): return SomeList(factories = {self: True}, s_item = self.s_item) @@ -111,6 +114,9 @@ class DictFactory: items = {} + def __repr__(self): + return '%s(items=%r)' % (self.__class__.__name__, self.items) + def create(self): return SomeDict(factories = {self: True}, items = self.items) From arigo at codespeak.net Tue Nov 16 12:31:27 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 12:31:27 +0100 (MET) Subject: [pypy-svn] r7279 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20041116113127.61C205AFA5@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 12:31:26 2004 New Revision: 7279 Modified: pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/transform.py Log: Remove code found out to be dead by the annotator. A new test for it. A bug fix in transform_dead_op_vars(). Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 16 12:31:26 2004 @@ -28,7 +28,14 @@ return SomeInteger(nonneg=True) def is_true(obj): - return SomeBool() + if obj.is_constant(): + return immutablevalue(bool(obj.const)) + else: + s_len = obj.len() + if s_len.is_constant(): + return immutablevalue(s_len.const > 0) + else: + return SomeBool() def getattr(obj, s_attr): # get a SomeBuiltin if the SomeObject has Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 12:31:26 2004 @@ -285,7 +285,14 @@ self.consider_op(block.operations[i]) finally: self.bookkeeper.leave() - for link in block.exits: + # dead code removal: don't follow all exits if the exitswitch is known + exits = block.exits + if isinstance(block.exitswitch, Variable): + s_exitswitch = self.bindings[block.exitswitch] + if s_exitswitch.is_constant(): + exits = [link for link in exits + if link.exitcase == s_exitswitch.const] + for link in exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(fn, link.target, cells) if block in self.notify: Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 16 12:31:26 2004 @@ -267,6 +267,18 @@ a = call_five_six() return len(a), a[0], a[1] +def forty_two(): + return 42 + +def never_called(): + return "booo" + +def constant_result(): + if forty_two(): + return "yadda" + else: + return never_called() + # INHERITANCE / CLASS TESTS class C(object): pass Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 16 12:31:26 2004 @@ -251,6 +251,23 @@ self.assert_(isinstance(s, annmodel.SomeList)) self.assertEquals(s.s_item, annmodel.SomeInteger(nonneg=True)) + def test_constant_result(self): + a = RPythonAnnotator() + s = a.build_types(snippet.constant_result, []) + a.translator.simplify() + # must return "yadda" + self.assertEquals(s, annmodel.immutablevalue("yadda")) + keys = a.translator.flowgraphs.keys() + keys.sort() + expected = [snippet.constant_result, + snippet.forty_two, + # and not snippet.never_called + ] + expected.sort() + self.assertEquals(keys, expected) + a.simplify() + #a.translator.view() + def g(n): return [0,1,2,n] Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Tue Nov 16 12:31:26 2004 @@ -105,7 +105,8 @@ # the set of operations that can safely be removed (no side effects) CanRemove = {'newtuple': True, 'newlist': True, - 'newdict': True} + 'newdict': True, + 'is_true': True} read_vars = {} # set of variables really used variable_flow = {} # map {Var: list-of-Vars-it-depends-on} @@ -121,6 +122,9 @@ # on the input variables deps = variable_flow.setdefault(op.result, []) deps.extend(op.args) + + if isinstance(block.exitswitch, Variable): + read_vars[block.exitswitch] = True if block.exits: for link in block.exits: @@ -296,11 +300,26 @@ ## self.setbinding(a2, self.bindings[a1]) ## self.annotated[block] = True +def transform_dead_code(self): + """Remove dead code: these are the blocks that are not annotated at all + because the annotation considered that no conditional jump could reach + them.""" + for block in self.annotated: + for link in block.exits: + if link.target not in self.annotated: + lst = list(block.exits) + lst.remove(link) + block.exits = tuple(lst) + if len(block.exits) == 1: + block.exitswitch = None + block.exits[0].exitcase = None + def transform_graph(ann): """Apply set of transformations available.""" if ann.translator: ann.translator.checkgraphs() + transform_dead_code(ann) transform_allocate(ann) transform_slice(ann) ##transform_listextend(ann) From mgedmin at codespeak.net Tue Nov 16 12:31:54 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 12:31:54 +0100 (MET) Subject: [pypy-svn] r7280 - pypy/trunk/src/pypy/translator Message-ID: <20041116113154.A18C35AFCF@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 12:31:54 2004 New Revision: 7280 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Typo. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 12:31:54 2004 @@ -16,7 +16,7 @@ class RPythonAnnotator: """Block annotator for RPython. - See description in doc/transation/annotation.txt.""" + See description in doc/translation/annotation.txt.""" def __init__(self, translator=None): self.translator = translator From mgedmin at codespeak.net Tue Nov 16 12:33:44 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 12:33:44 +0100 (MET) Subject: [pypy-svn] r7281 - pypy/trunk/src/goal Message-ID: <20041116113344.8B42C5AFD1@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 12:33:44 2004 New Revision: 7281 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Use threading to start the PDB thread. The effect of this change is that closing the PyGame window will not abort the debugger session and therefore will not leave the terminal in inconsistent state. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 16 12:33:44 2004 @@ -72,10 +72,13 @@ print '-'*60 print >> sys.stderr - import thread + import threading import pdb - thread.start_new_thread(pdb.post_mortem, (tb,)) + t = threading.Thread(target=pdb.post_mortem, args=(tb,)) + t.start() run_server() + import pygame + pygame.quit() try: analyse() From hpk at codespeak.net Tue Nov 16 14:16:53 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 14:16:53 +0100 (MET) Subject: [pypy-svn] r7283 - pypy/trunk/src/goal Message-ID: <20041116131653.A2ADA5AC17@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 14:16:53 2004 New Revision: 7283 Modified: pypy/trunk/src/goal/buildcache.py Log: minimized the code for building the cached value somewhat Modified: pypy/trunk/src/goal/buildcache.py ============================================================================== --- pypy/trunk/src/goal/buildcache.py (original) +++ pypy/trunk/src/goal/buildcache.py Tue Nov 16 14:16:53 2004 @@ -21,17 +21,8 @@ gen.func_code.co_name str({'co_name': ('f',)}), str(object.__init__.im_func.func_code) - "for %r" % ({'x': gen}) - ("%02d"%1) - ("%05d"%1) - ("%-05d"%1) - ("%04f"%2.25) - ("%05g"%2.25) - ("%-05g"%2.25) - ("%05s"%2.25) - ('<%s>' % [1,2]) - ('<%s-%s>' % ([1,2], [3,4])) - + #"for %r" % ({'x': gen}) + "%02d %04f %05g %05s <%s> %r" % (1, 2.25, 2.25, 2.25, [1,2], {'x': gen}) for x in gen(): pass From hpk at codespeak.net Tue Nov 16 14:23:17 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 14:23:17 +0100 (MET) Subject: [pypy-svn] r7284 - pypy/trunk/src/goal Message-ID: <20041116132317.B5E6D5AF2F@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 14:23:17 2004 New Revision: 7284 Modified: pypy/trunk/src/goal/buildcache.py Log: some more optimization Modified: pypy/trunk/src/goal/buildcache.py ============================================================================== --- pypy/trunk/src/goal/buildcache.py (original) +++ pypy/trunk/src/goal/buildcache.py Tue Nov 16 14:23:17 2004 @@ -19,7 +19,7 @@ except ValueError: pass - gen.func_code.co_name + #gen.func_code.co_name str({'co_name': ('f',)}), str(object.__init__.im_func.func_code) #"for %r" % ({'x': gen}) "%02d %04f %05g %05s <%s> %r" % (1, 2.25, 2.25, 2.25, [1,2], {'x': gen}) From bob at codespeak.net Tue Nov 16 14:41:12 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 14:41:12 +0100 (MET) Subject: [pypy-svn] r7285 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116134112.45A345AFF4@thoth.codespeak.net> Author: bob Date: Tue Nov 16 14:41:11 2004 New Revision: 7285 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: ugly hack to clamp panning Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Tue Nov 16 14:41:11 2004 @@ -181,9 +181,9 @@ scale = max(min(scale, self.SCALEMAX), self.SCALEMIN) self.scale = float(scale) w, h = self.graphlayout.boundingbox - self.margin = int(self.MARGIN*scale) - self.width = int((w + 2*self.MARGIN)*scale) - self.height = int((h + 2*self.MARGIN)*scale) + self.margin = int(self.MARGIN * scale) + self.width = int(w * scale) + (2 * self.margin) + self.height = int(h * scale) + (2 * self.margin) self.bboxh = h size = int(15 * (scale-10) / 75) self.font = self.getfont(size) @@ -228,19 +228,37 @@ newx, newy = self.map(x, y) self.shiftoffset(newx - fixx, newy - fixy) + def reoffset(self, swidth, sheight): + offsetx = noffsetx = self.ofsx + offsety = noffsety = self.ofsy + width = self.width + height = self.height + + # if it fits, center it, otherwise clamp + if width <= swidth: + noffsetx = (width - swidth) // 2 + else: + noffsetx = min(max(0, offsetx), width - swidth) + + if height <= sheight: + noffsety = (height - sheight) // 2 + else: + noffsety = min(max(0, offsety), height - sheight) + + self.ofsx = noffsetx + self.ofsy = noffsety + def getboundingbox(self): "Get the rectangle where the graph will be rendered." - offsetx = - self.margin - self.ofsx - offsety = - self.margin - self.ofsy - return (offsetx, offsety, self.width, self.height) + return (-self.ofsx, -self.ofsy, self.width, self.height) def map(self, x, y): - return (int(x*self.scale) - self.ofsx, - int((self.bboxh-y)*self.scale) - self.ofsy) + return (int(x*self.scale) - (self.ofsx - self.margin), + int((self.bboxh-y)*self.scale) - (self.ofsy - self.margin)) def revmap(self, px, py): - return ((px + self.ofsx) / self.scale, - self.bboxh - (py + self.ofsy) / self.scale) + return ((px + (self.ofsx - self.margin)) / self.scale, + self.bboxh - (py + (self.ofsy - self.margin)) / self.scale) def draw_node_commands(self, node): xcenter, ycenter = self.map(node.x, node.y) Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 14:41:11 2004 @@ -109,13 +109,13 @@ self.zoom_to_fit() def zoom_actual_size(self): - self.viewer.shiftscale(self.viewer.SCALEMAX / self.viewer.scale) + self.viewer.shiftscale(float(self.viewer.SCALEMAX) / self.viewer.scale) self.updated_viewer() def calculate_zoom_to_fit(self): return min(float(self.width) / self.viewer.width, float(self.height - self.status_bar_height) / self.viewer.height, - 1.0) + float(self.viewer.SCALEMAX) / self.viewer.scale) def zoom_to_fit(self): """ @@ -128,14 +128,17 @@ f = self.calculate_zoom_to_fit() self.viewer.shiftscale(f) - self.viewer.setoffset((self.viewer.width - self.width) // 2, - (self.viewer.height - (self.height - self.status_bar_height)) // 2) + #self.viewer.setoffset((self.viewer.width - self.width) // 2, + # (self.viewer.height - (self.height - self.status_bar_height)) // 2) self.updated_viewer() def zoom(self, scale): self.viewer.shiftscale(max(scale, self.calculate_zoom_to_fit())) self.updated_viewer() + def reoffset(self): + self.viewer.reoffset(self.width, self.height - self.status_bar_height) + def pan(self, (x, y)): self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8)) self.updated_viewer() @@ -154,6 +157,7 @@ self.setstatusbar(info) def updated_viewer(self): + self.reoffset() self.sethighlight() self.statusbarinfo = None self.must_redraw = True @@ -225,6 +229,7 @@ newlayout = self.layout.followlink(word) if newlayout is not None: self.setlayout(newlayout) + self.zoom_to_fit() return node = self.viewer.node_at_position(pos) if node: From arigo at codespeak.net Tue Nov 16 15:00:05 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 15:00:05 +0100 (MET) Subject: [pypy-svn] r7286 - in pypy/trunk/src: goal pypy/annotation pypy/translator Message-ID: <20041116140005.BD9C85AFF9@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 15:00:05 2004 New Revision: 7286 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/genc.py Log: - Added SomePrebuiltConstant annotation for pre-built global constant instances. - isinstance() annotation support. - enabled freezing the caches in translate_pypy. - generate the name of well-known built-in types in genc. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 16 15:00:05 2004 @@ -23,7 +23,7 @@ global t t = Translator(entry_point, verbose=True, simplifying=True) space = StdObjSpace() - #buildcache.buildcache(space) + buildcache.buildcache(space) a = t.annotate([annmodel.immutablevalue(space)]) a.simplify() Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 16 15:00:05 2004 @@ -8,8 +8,10 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod from pypy.annotation.model import SomeBuiltin, SomeIterator +from pypy.annotation.model import SomePrebuiltConstant, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize +from pypy.objspace.flow.model import Constant # XXX unify this with ObjSpace.MethodTable @@ -217,3 +219,26 @@ class __extend__(pairtype(SomeObject, SomeImpossibleValue)): def union((obj1, imp2)): return obj1 + + +class __extend__(pairtype(SomePrebuiltConstant, SomePrebuiltConstant)): + def union((pbc1, pbc2)): + return SomePrebuiltConstant(setunion(pbc1.prebuiltinstances, + pbc2.prebuiltinstances)) + +class __extend__(pairtype(SomePrebuiltConstant, SomeObject)): + def getitem((pbc1, obj2)): + # special case for SomePrebuiltConstants that are dictionaries + # (actually frozendicts) + possibleresults = [] + for c_inst in pbc1.prebuiltinstances: + assert isinstance(c_inst, Constant) + inst = c_inst.value + if isinstance(inst, dict): + possibleresults += inst.values() + elif isinstance(inst, list): + possibleresults += inst # maybe + else: + raise TypeError, "cannot getitem() from %r" % (inst,) + possibleresults = [immutablevalue(x) for x in possibleresults] + return unionof(*possibleresults) Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Tue Nov 16 15:00:05 2004 @@ -2,7 +2,8 @@ Built-in functions. """ -from pypy.annotation.model import SomeInteger, SomeObject, SomeChar +from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool +from pypy.annotation.model import immutablevalue from pypy.annotation.factory import ListFactory, getbookkeeper import pypy.objspace.std.restricted_int @@ -30,6 +31,14 @@ def builtin_chr(s_int): return SomeChar() +def builtin_isinstance(s_obj, s_type): + # XXX simple case only + if s_type.is_constant(): + typ = s_type.const + if issubclass(s_obj.knowntype, typ): + return immutablevalue(True) + return SomeBool() + # collect all functions import __builtin__ Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue Nov 16 15:00:05 2004 @@ -29,7 +29,9 @@ from types import ClassType, BuiltinFunctionType, FunctionType, MethodType +from types import InstanceType from pypy.annotation.pairtype import pair, extendabletype +from pypy.objspace.flow.model import Constant class SomeObject: @@ -134,6 +136,14 @@ def __init__(self, meths): self.meths = meths # map {python_function: classdef} +class SomePrebuiltConstant(SomeObject): + """Stands for a global user instance, built prior to the analysis, + or a set of such instances.""" + def __init__(self, prebuiltinstances): + self.prebuiltinstances = prebuiltinstances # set of Constants + self.knowntype = reduce(commonbase, [x.value.__class__ + for x in prebuiltinstances]) + class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that will never show up at run-time, e.g. elements of an empty list.""" @@ -171,6 +181,8 @@ result = SomeClass(x) elif isinstance(x, (FunctionType, MethodType)): result = SomeFunction({x: True}) + elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': + result = SomePrebuiltConstant({Constant(x): True}) # pre-built instances else: result = SomeObject() result.const = x @@ -218,6 +230,11 @@ d[x] = True return d +def commonbase(cls1, cls2): # XXX single inheritance only XXX hum + while not issubclass(cls1, cls2): + cls2, = [x for x in cls2.__bases__ if x is not object] or [object] + return cls2 + def missing_operation(cls, name): def default_op(*args): #print '* warning, no type available for %s(%s)' % ( Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Tue Nov 16 15:00:05 2004 @@ -157,9 +157,10 @@ bases = [base for base in cls.__bases__ if base is not object] assert len(bases) <= 1, "%r needs multiple inheritance" % (cls,) if bases: - base = self.nameof(bases[0]) + base = bases[0] else: - base = '(PyObject*) &PyBaseObject_Type' + base = object + base = self.nameof(base) def initclassobj(): content = cls.__dict__.items() content.sort() @@ -180,9 +181,22 @@ nameof_class = nameof_classobj # for Python 2.2 + typename_mapping = { + object: 'PyBaseObject_Type', + int: 'PyInt_Type', + long: 'PyLong_Type', + bool: 'PyBool_Type', + list: 'PyList_Type', + tuple: 'PyTuple_Type', + dict: 'PyDict_Type', + str: 'PyString_Type', + } + def nameof_type(self, cls): + if cls in self.typename_mapping: + return '(PyObject*) &%s' % self.typename_mapping[cls] assert hasattr(cls, '__weakref__'), ( - "%r is not a user-defined class" % (cls,)) + "built-in class %r not found in typename_mapping" % (cls,)) return self.nameof_classobj(cls) def nameof_tuple(self, tup): From bob at codespeak.net Tue Nov 16 15:04:04 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 15:04:04 +0100 (MET) Subject: [pypy-svn] r7287 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116140404.52E0D5B000@thoth.codespeak.net> Author: bob Date: Tue Nov 16 15:04:03 2004 New Revision: 7287 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: add meta-+ for zoom and clamp mouse movement Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 15:04:03 2004 @@ -40,10 +40,14 @@ STATUSBARFONT = os.path.join(autopath.this_dir, 'VeraMoBd.ttf') ANIM_STEP = 0.07 KEY_REPEAT = (500, 30) + STATUSBAR_ALPHA = 0.75 + STATUSBAR_FGCOLOR = (255, 255, 80) + STATUSBAR_BGCOLOR = (128, 0, 0) KEYS = { 'meta -' : ('zoom', 0.5), 'meta =' : ('zoom', 2.0), + 'meta +' : ('zoom', 2.0), 'meta 0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', 'meta q' : 'quit', @@ -114,7 +118,7 @@ def calculate_zoom_to_fit(self): return min(float(self.width) / self.viewer.width, - float(self.height - self.status_bar_height) / self.viewer.height, + float(self.height) / self.viewer.height, float(self.viewer.SCALEMAX) / self.viewer.scale) def zoom_to_fit(self): @@ -122,14 +126,8 @@ center and scale to view the whole graph """ - # XXX - HACK HACK HACK - self.update_status_bar() - self.drawstatusbar() - f = self.calculate_zoom_to_fit() self.viewer.shiftscale(f) - #self.viewer.setoffset((self.viewer.width - self.width) // 2, - # (self.viewer.height - (self.height - self.status_bar_height)) // 2) self.updated_viewer() def zoom(self, scale): @@ -137,7 +135,7 @@ self.updated_viewer() def reoffset(self): - self.viewer.reoffset(self.width, self.height - self.status_bar_height) + self.viewer.reoffset(self.width, self.height) def pan(self, (x, y)): self.viewer.shiftoffset(x * (self.width // 8), y * (self.height // 8)) @@ -177,8 +175,8 @@ self.layout = self.viewer.graphlayout self.updated_viewer() - def setstatusbar(self, text, fgcolor=(255,255,80), bgcolor=(128,0,0)): - info = (text, fgcolor, bgcolor) + def setstatusbar(self, text, fgcolor=None, bgcolor=None): + info = (text, fgcolor or self.STATUSBAR_FGCOLOR, bgcolor or self.STATUSBAR_BGCOLOR) if info != self.statusbarinfo: self.statusbarinfo = info self.must_redraw = True @@ -213,7 +211,7 @@ w, h = img.get_size() block.blit(img, ((self.width-w)//2, sy-8)) sy += h - block.set_alpha(int(255 * 0.75)) + block.set_alpha(int(255 * self.STATUSBAR_ALPHA)) self.screen.blit(block, (0, y-16)) def notifymousepos(self, pos): @@ -295,6 +293,7 @@ self.viewer.setscale(startscale*(1-t) + endscale*t + bumpscale*t*(1-t)) self.viewer.setcenter(cx1*(1-t) + cx2*t, cy1*(1-t) + cy2*t) + self.updated_viewer() self.viewer.render() pygame.display.flip() return moving @@ -323,9 +322,10 @@ dx = event.pos[0] - self.dragging[0] dy = event.pos[1] - self.dragging[1] if event.buttons[0]: # left mouse button - self.viewer.shiftscale(1.003 ** (dx+dy)) + self.zoom(1.003 ** (dx+dy)) else: self.viewer.shiftoffset(-2*dx, -2*dy) + self.updated_viewer() self.dragging = event.pos self.must_redraw = True else: @@ -342,6 +342,7 @@ if self.click_time is not None and abs(time.time() - self.click_time) < 1: # click (no significant dragging) self.notifyclick(self.click_origin) + self.update_status_bar() self.click_time = None self.notifymousepos(event.pos) From bob at codespeak.net Tue Nov 16 16:01:18 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 16:01:18 +0100 (MET) Subject: [pypy-svn] r7289 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116150118.CEF8E5AF30@thoth.codespeak.net> Author: bob Date: Tue Nov 16 16:01:18 2004 New Revision: 7289 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: crazy "meta meta meta" key permutations for situations such as lalt and ralt that should always be considered equivalent. also for keys like = and + which depend on the keyboard mapping (english vs. german) Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 16:01:18 2004 @@ -12,18 +12,37 @@ ]) if sys.platform == 'darwin': - PMETA = 'lmeta' + PMETA = 'lmeta', 'rmeta' else: - PMETA = 'lalt' + PMETA = 'lalt', 'ralt' -METAKEYS['meta'] = METAKEYS[PMETA] -METAKEYS['shift'] = METAKEYS['lshift'] +METAKEYS['meta'] = PMETA +METAKEYS['shift'] = 'lshift', 'rshift' KEYS = dict([ (ident[len('K_'):].lower(), getattr(pygame.locals, ident)) for ident in dir(pygame.locals) if ident.startswith('K_') ]) +KEYS['plus'] = ('=', '+') +KEYS['quit'] = ('q', 'f4') + +def GET_KEY(key): + k = KEYS.get(key) + if k is None: + assert len(key) == 1 + return ord(key) + return k + +def permute_mods(base, args): + if not args: + yield base + return + first, rest = args[0], args[1:] + for val in first: + for rval in permute_mods(base | val, rest): + yield rval + class Display(object): def __init__(self, (w,h)=(800,680)): @@ -46,13 +65,11 @@ KEYS = { 'meta -' : ('zoom', 0.5), - 'meta =' : ('zoom', 2.0), - 'meta +' : ('zoom', 2.0), + 'meta plus' : ('zoom', 2.0), 'meta 0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', - 'meta q' : 'quit', + 'meta quit' : 'quit', 'escape' : 'quit', - 'meta f4' : 'quit', 'meta right' : 'layout_forward', 'meta left': 'layout_back', 'p' : 'layout_back', @@ -84,25 +101,37 @@ pygame.key.set_repeat(*self.KEY_REPEAT) for strnames, methodname in self.KEYS.iteritems(): names = strnames.split() - mod = 0 - key = 0 if not isinstance(methodname, basestring): methodname, args = methodname[0], methodname[1:] else: args = () - for name in names: - if name in METAKEYS: - mod |= METAKEYS[name] - elif name in KEYS: - key = KEYS[name] - else: - assert len(name) == 1 - key = ord(name) method = getattr(self, methodname, None) if method is None: print 'Can not implement key mapping %r, %s.%s does not exist' % ( strnames, self.__class__.__name__, methodname) - self.key_cache[(key, mod)] = (method, args) + continue + + mods = [] + basemod = 0 + keys = [] + for name in names: + if name in METAKEYS: + val = METAKEYS[name] + if not isinstance(val, int): + mods.append(tuple([METAKEYS[k] for k in val])) + else: + basemod |= val + else: + val = GET_KEY(name) + assert len(keys) == 0 + if not isinstance(val, int): + keys.extend([GET_KEY(k) for k in val]) + else: + keys.append(val) + assert keys + for key in keys: + for mod in permute_mods(basemod, mods): + self.key_cache[(key, mod)] = (method, args) def setlayout(self, layout): if self.viewer: From bob at codespeak.net Tue Nov 16 16:59:29 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 16:59:29 +0100 (MET) Subject: [pypy-svn] r7290 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041116155929.A2F535AA0E@thoth.codespeak.net> Author: bob Date: Tue Nov 16 16:59:29 2004 New Revision: 7290 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: ugly mouseover highlighting Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Tue Nov 16 16:59:29 2004 @@ -19,11 +19,21 @@ } re_nonword=re.compile(r'(\W+)') +def highlight_color(color): + intensity = sum(color) + components = [] + if color == (0,0,0): + return (255, 0, 255) + elif color == (255,255,255): + return (255, 255, 0) + return color[1:] + color[:1] + def getcolor(name, default): if name in COLOR: return COLOR[name] elif name.startswith('#') and len(name) == 7: - return (int(name[1:3],16), int(name[3:5],16), int(name[5:7],16)) + rval = COLOR[name] = (int(name[1:3],16), int(name[3:5],16), int(name[5:7],16)) + return rval else: return default @@ -70,6 +80,10 @@ self.shape = shape self.color = color self.fillcolor = fillcolor + self.highlight = False + + def sethighlight(self, which): + self.highlight = bool(which) class Edge: label = None @@ -87,6 +101,10 @@ self.yl = float(yl) rest = rest[3:] self.style, self.color = rest + self.highlight = False + + def sethighlight(self, which): + self.highlight = bool(which) def bezierpoints(self, resolution=8): result = [] @@ -266,6 +284,9 @@ boxheight = int(node.h * self.scale) fgcolor = getcolor(node.color, (0,0,0)) bgcolor = getcolor(node.fillcolor, (255,255,255)) + if node.highlight: + fgcolor = highlight_color(fgcolor) + bgcolor = highlight_color(bgcolor) text = node.label lines = text.replace('\\l','\\l\n').replace('\r','\r\n').split('\n') @@ -357,6 +378,8 @@ edgeheadcmd = [] for edge in self.graphlayout.edges: fgcolor = getcolor(edge.color, (0,0,0)) + if edge.highlight: + fgcolor = highlight_color(fgcolor) points = [self.map(*xy) for xy in edge.bezierpoints()] def drawedgebody(points=points, fgcolor=fgcolor): Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 16 16:59:29 2004 @@ -90,6 +90,7 @@ self.font = pygame.font.Font(self.STATUSBARFONT, 16) self.viewers_history = [] self.forward_viewers_history = [] + self.highlight_obj = None self.viewer = None self.method_cache = {} self.key_cache = {} @@ -249,6 +250,16 @@ info = self.layout.links[word] self.setstatusbar(info) self.sethighlight(word) + return + node = self.viewer.node_at_position(pos) + if node: + self.sethighlight(obj=node) + return + edge = self.viewer.edge_at_position(pos) + if edge: + self.sethighlight(obj=edge) + return + self.sethighlight() def notifyclick(self, pos): word = self.viewer.at_position(pos) @@ -270,12 +281,19 @@ else: self.look_at_node(edge.tail) - def sethighlight(self, word=None): + def sethighlight(self, word=None, obj=None): self.viewer.highlightwords = {} for name in self.layout.links: self.viewer.highlightwords[name] = ((128,0,0), None) if word: self.viewer.highlightwords[word] = ((255,255,80), (128,0,0)) + if self.highlight_obj is not None: + self.highlight_obj.sethighlight(False) + if obj is not None: + obj.sethighlight(True) + self.highlight_obj = obj + self.must_redraw = True + def animation(self, expectedtime=0.6): start = time.time() @@ -317,7 +335,7 @@ else: bumpscale = 0.0 self.statusbarinfo = None - self.sethighlight(None) + self.sethighlight() for t in self.animation(): self.viewer.setscale(startscale*(1-t) + endscale*t + bumpscale*t*(1-t)) From arigo at codespeak.net Tue Nov 16 17:17:22 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 17:17:22 +0100 (MET) Subject: [pypy-svn] r7291 - pypy/trunk/src/pypy/annotation Message-ID: <20041116161722.EAD295AF2D@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 17:17:22 2004 New Revision: 7291 Modified: pypy/trunk/src/pypy/annotation/unaryop.py Log: Removed out-of-date misleading comments. Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 16 17:17:22 2004 @@ -108,9 +108,6 @@ # look for the attribute in the MRO order for clsdef in ins.currentdef().getmro(): if attr in clsdef.attrs: - # XXX we can't see the difference between function objects - # XXX on classes or on instances, so this will incorrectly - # XXX turn functions read from instances into methods return clsdef.attrs[attr] # maybe the attribute exists in some subclass? if so, lift it clsdef = ins.classdef From mwh at codespeak.net Tue Nov 16 17:28:23 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:28:23 +0100 (MET) Subject: [pypy-svn] r7292 - pypy/trunk/src/goal Message-ID: <20041116162823.1D08A5AF32@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:28:22 2004 New Revision: 7292 Modified: pypy/trunk/src/goal/translate_pypy.py Log: make space a module-level global -- that way it gets found by the translator... Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 16 17:28:22 2004 @@ -11,7 +11,7 @@ # __________ Entry point __________ -def entry_point(space): +def entry_point(): w_a = W_IntObject(space, -6) w_b = W_IntObject(space, -7) return space.mul(w_a, w_b) @@ -20,11 +20,11 @@ # __________ Main __________ def analyse(entry_point=entry_point): - global t - t = Translator(entry_point, verbose=True, simplifying=True) + global t, space space = StdObjSpace() buildcache.buildcache(space) - a = t.annotate([annmodel.immutablevalue(space)]) + t = Translator(entry_point, verbose=True, simplifying=True) + a = t.annotate([]) a.simplify() From mwh at codespeak.net Tue Nov 16 17:31:21 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:31:21 +0100 (MET) Subject: [pypy-svn] r7293 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041116163121.52ABD5AF34@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:31:20 2004 New Revision: 7293 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/flow/specialcase.py Log: Rework the way flowobjspace deals with special cases. Add a special case for __import__. Watch out for the UNDEFINED hack in FlowObjSpace.wrap. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Tue Nov 16 17:31:20 2004 @@ -25,6 +25,7 @@ for exc in [KeyError, ValueError, IndexError, StopIteration]: clsname = exc.__name__ setattr(self, 'w_'+clsname, Constant(exc)) + self.specialcases = {} #self.make_builtins() #self.make_sys() @@ -80,7 +81,7 @@ return self.do_operation('newslice', w_start, w_stop, w_step) def wrap(self, obj): - if isinstance(obj, (Variable, Constant)): + if isinstance(obj, (Variable, Constant)) and obj is not UNDEFINED: raise TypeError("already wrapped: " + repr(obj)) return Constant(obj) @@ -168,8 +169,8 @@ def call_args(self, w_callable, args): try: - sc = self.unwrap(w_callable)._flowspecialcase_ - except (UnwrapException, AttributeError): + sc = self.specialcases[self.unwrap(w_callable)] + except (UnwrapException, KeyError): pass else: return sc(self, args) Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Tue Nov 16 17:31:20 2004 @@ -45,14 +45,24 @@ def loadfromcache(space, args): # XXX need some way to know how to fully initialize the cache + print space, args assert len(args.args_w) == 2 and args.kwds_w == {} w_key, w_builder = args.args_w w_cache = Constant('space_cache') # temporary return space.do_operation('getitem', w_cache, w_key) +def import_(space, args): + assert len(args.args_w) == 4 and args.kwds_w == {} + unwrapped_args = [] + for w_arg in args.args_w: + assert isinstance(w_arg, Constant) + unwrapped_args.append(space.unwrap(w_arg)) + return space.wrap(__import__(*unwrapped_args)) + def setup(space): fn = pyframe.normalize_exception.get_function(space) - fn._flowspecialcase_ = normalize_exception + space.specialcases[fn] = normalize_exception fn = baseobjspace.ObjSpace.loadfromcache.im_func - fn._flowspecialcase_ = loadfromcache + space.specialcases[fn] = loadfromcache + space.specialcases[__import__] = import_ From mwh at codespeak.net Tue Nov 16 17:32:50 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:32:50 +0100 (MET) Subject: [pypy-svn] r7294 - pypy/trunk/src/pypy/translator/test Message-ID: <20041116163250.D96905AF39@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:32:50 2004 New Revision: 7294 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: add a test that unreferenced __init__ methods are not translated. commented out, because it doesn't work. current thinking is that this sort of thing will only work in conjunction with annotation. Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 16 17:32:50 2004 @@ -419,6 +419,20 @@ def global_recursive_list(): return global_rl +class BadInit(object): + def update(self, k): + self.k = 1 + def __init__(self, v): + self.update(**{'k':v}) + def read(self): + return self.k + +global_bi = BadInit(1) + +def global_badinit(): + return global_bi.read() + + def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Tue Nov 16 17:32:50 2004 @@ -113,6 +113,10 @@ self.assertEquals(len(lst), 1) self.assert_(lst[0] is lst) +## def test_global_badinit(self): +## global_badinit = self.build_cfunc(snippet.global_badinit) +## self.assertEquals(global_badinit(), 1) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From mwh at codespeak.net Tue Nov 16 17:34:51 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:34:51 +0100 (MET) Subject: [pypy-svn] r7295 - pypy/trunk/src/pypy/translator Message-ID: <20041116163451.BF6195AF3B@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:34:51 2004 New Revision: 7295 Modified: pypy/trunk/src/pypy/translator/genc.h Log: implement 'is' Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Tue Nov 16 17:34:51 2004 @@ -15,6 +15,8 @@ #define OP_GT(x,y,r,err) op_richcmp(x,y,r,err, Py_GT) #define OP_GE(x,y,r,err) op_richcmp(x,y,r,err, Py_GE) +#define OP_IS_(x,y,r,err) r = x == y ? Py_True : Py_False; Py_INCREF(r); + #define OP_IS_TRUE(x,r,err) switch (PyObject_IsTrue(x)) { \ case 0: r=Py_False; break; \ case 1: r=Py_True; break; \ From bob at codespeak.net Tue Nov 16 17:38:32 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 16 Nov 2004 17:38:32 +0100 (MET) Subject: [pypy-svn] r7296 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041116163832.41D325AF3D@thoth.codespeak.net> Author: bob Date: Tue Nov 16 17:38:31 2004 New Revision: 7296 Modified: pypy/trunk/src/pypy/objspace/std/typetype.py Log: add mro() to type objects Modified: pypy/trunk/src/pypy/objspace/std/typetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/typetype.py Tue Nov 16 17:38:31 2004 @@ -23,6 +23,9 @@ # XXX this should be inside typeobject.py return space.newtuple(w_type.mro_w) +def descr_mro(space, w_type): + return space.newlist(w_type.mro_w) + def descr__bases(space, w_type): return space.newtuple(w_type.bases_w) @@ -44,4 +47,5 @@ __base__ = GetSetProperty(descr__base), __mro__ = GetSetProperty(descr_get__mro__), __dict__ = default_dict_descr, + mro = newmethod(descr_mro), ) From hpk at codespeak.net Tue Nov 16 17:40:38 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 16 Nov 2004 17:40:38 +0100 (MET) Subject: [pypy-svn] r7297 - in pypy/trunk/src/pypy/tool: . pytest testdata Message-ID: <20041116164038.2D8635AF41@thoth.codespeak.net> Author: hpk Date: Tue Nov 16 17:40:37 2004 New Revision: 7297 Added: pypy/trunk/src/pypy/tool/pytest/ pypy/trunk/src/pypy/tool/pytest/support.py - copied, changed from r7287, pypy/trunk/src/pypy/tool/pypyutest.py Removed: pypy/trunk/src/pypy/tool/pypyutest.py pypy/trunk/src/pypy/tool/testdata/ Log: - remove 'testdata' (only used by the old newtest.py which also got removed) - the beginnings of some support for conversion to using py.test (currently found in pypy/tool/pytest/support.py) Deleted: /pypy/trunk/src/pypy/tool/pypyutest.py ============================================================================== --- /pypy/trunk/src/pypy/tool/pypyutest.py Tue Nov 16 17:40:37 2004 +++ (empty file) @@ -1,41 +0,0 @@ -from py.__impl__.magic import exprinfo -import py -py.magic.autopath() -from pypy.objspace.std import StdObjSpace - -class AppRunnerFrame: - - def __init__(self, space, w_globals, w_locals): - self.space = space - self.w_globals = w_globals - self.w_locals = w_locals - - def eval(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - return space.eval(code, self.w_globals, self.w_locals) - - def exec_(self, code, **vars): - space = self.space - for key, w_value in vars.items(): - space.setitem(self.w_locals, space.wrap(key), w_value) - space.exec_(code, self.w_globals, self.w_locals) - - def repr(self, w_value): - return self.space.unwrap(self.space.repr(w_value)) - - def is_true(self, w_value): - return self.space.is_true(w_value) - - -def test(): - space = StdObjSpace() - w_glob = space.newdict([]) - w_loc = space.newdict([]) - runner = AppRunnerFrame(space, w_glob, w_loc) - exprinfo.run("f = lambda x: x+1", runner) - exprinfo.check("isinstance(f(2), float)", runner) - -if __name__ == '__main__': - test() Copied: pypy/trunk/src/pypy/tool/pytest/support.py (from r7287, pypy/trunk/src/pypy/tool/pypyutest.py) ============================================================================== --- pypy/trunk/src/pypy/tool/pypyutest.py (original) +++ pypy/trunk/src/pypy/tool/pytest/support.py Tue Nov 16 17:40:37 2004 @@ -2,6 +2,7 @@ import py py.magic.autopath() from pypy.objspace.std import StdObjSpace +from pypy.interpreter.gateway import app2interp, interp2app class AppRunnerFrame: @@ -28,6 +29,26 @@ def is_true(self, w_value): return self.space.is_true(w_value) +def build_pytest_assertion(space): + def app_getmyassertion(): + class MyAssertionError(AssertionError): + def __init__(self, *args): + AssertionError.__init__(self, *args) + self.inspect_assertion() + return MyAssertionError + getmyassertion = app2interp(app_getmyassertion) + w_myassertion = getmyassertion(space) + + def inspect_assertion(space, w_self): + pass + #print w_self + #print "got to interp-level inspect_assertion" + + w_inspect_assertion = space.wrap(interp2app(inspect_assertion)) + space.setattr(w_myassertion, + space.wrap('inspect_assertion'), + w_inspect_assertion) + return w_myassertion def test(): space = StdObjSpace() From mwh at codespeak.net Tue Nov 16 17:48:55 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:48:55 +0100 (MET) Subject: [pypy-svn] r7298 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041116164855.6C2815AF3F@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:48:54 2004 New Revision: 7298 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Support multiple inheritance in genc.py. Also, raise Exception, not TypeError, in nameof as the latter get annoyingly eaten by list.extend (GRRR!) Tests. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Tue Nov 16 17:48:54 2004 @@ -105,9 +105,9 @@ /*** classes ***/ -#define SETUP_CLASS(t, name, base) \ +/*#define SETUP_CLASS(t, name, base) \ t = PyObject_CallFunction((PyObject*) &PyType_Type, \ - "s(O){}", name, base) + "s(O){}", name, base)*/ #define SETUP_CLASS_ATTR(t, attr, value) \ (PyObject_SetAttrString(t, attr, value) >= 0) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Tue Nov 16 17:48:54 2004 @@ -59,7 +59,7 @@ if meth: break else: - raise TypeError, "nameof(%r)" % (obj,) + raise Exception, "nameof(%r)" % (obj,) name = meth(obj) self.cnames[key] = name return name @@ -153,19 +153,16 @@ return name def nameof_classobj(self, cls): + if issubclass(cls, Exception) and cls.__module__ == 'exceptions': + return 'PyExc_%s'%cls.__name__ name = self.uniquename('gcls_' + cls.__name__) bases = [base for base in cls.__bases__ if base is not object] - assert len(bases) <= 1, "%r needs multiple inheritance" % (cls,) - if bases: - base = bases[0] - else: - base = object - base = self.nameof(base) + basenames = [self.nameof(base) for base in bases] def initclassobj(): content = cls.__dict__.items() content.sort() for key, value in content: - if key.startswith('__') and key != '__init__': + if key.startswith('__'): if key in ['__module__', '__doc__', '__dict__', '__weakref__', '__repr__']: continue @@ -174,8 +171,15 @@ yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('INITCHK(SETUP_CLASS(%s, "%s", %s))' % ( - name, cls.__name__, base)) + + baseargs = ", ".join(basenames) + if baseargs: + baseargs = ', '+baseargs + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) &PyType_Type,' + %(name,)) + self.initcode.append('\t\t"s(%s){}", "%s"%s))' + %("O"*len(bases), cls.__name__, baseargs)) + self.latercode.append(initclassobj()) return name Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 16 17:48:54 2004 @@ -429,6 +429,19 @@ global_bi = BadInit(1) +class MI_A(object): + a = 1 +class MI_B(MI_A): + b = 2 +class MI_C(MI_A): + c = 3 +class MI_D(MI_B, MI_C): + d = 4 + +def multiple_inheritance(): + i = MI_D() + return i.a + i.b + i.c + i.d + def global_badinit(): return global_bi.read() Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Tue Nov 16 17:48:54 2004 @@ -117,6 +117,10 @@ ## global_badinit = self.build_cfunc(snippet.global_badinit) ## self.assertEquals(global_badinit(), 1) + def test_multiple_inheritance(self): + multiple_inheritance = self.build_cfunc(snippet.multiple_inheritance) + self.assertEquals(multiple_inheritance(), 1+2+3+4) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From mwh at codespeak.net Tue Nov 16 17:56:55 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 16 Nov 2004 17:56:55 +0100 (MET) Subject: [pypy-svn] r7301 - in pypy/trunk/src: goal pypy/annotation pypy/translator Message-ID: <20041116165655.1596C5AF45@thoth.codespeak.net> Author: mwh Date: Tue Nov 16 17:56:54 2004 New Revision: 7301 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/translator.py Log: Hacks towards goal/translate_pypy.py. Track which attributes are read from PreBuiltConstants (beware: new jargon appears to be 'pbc' == 'PreBuiltConstant'). Support 'freezing' a translator, after which point no more flow graphs will be built. Support dumping a few more types (implementations of varying degrees of hackishness). Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 16 17:56:54 2004 @@ -82,6 +82,7 @@ try: analyse() + t.frozen = True print '-'*60 print 'Generating C code...' t.ccompile() Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 16 17:56:54 2004 @@ -38,6 +38,7 @@ self.creationpoints = {} # map position-in-a-block to its Factory self.userclasses = {} # map classes to ClassDefs self.userclasseslist = []# userclasses.keys() in creation order + self.attrs_read_from_constants = {} def enter(self, position_key): """Start of an operation. Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 16 17:56:54 2004 @@ -9,6 +9,7 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass from pypy.annotation.model import SomeFunction, SomeMethod, SomeIterator +from pypy.annotation.model import SomePrebuiltConstant from pypy.annotation.model import immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -179,3 +180,19 @@ # call func(s_self, *arglist) results.append(factory.pycall(func, s_self, *args)) return unionof(*results) + +class __extend__(SomePrebuiltConstant): + def getattr(pbc, s_attr): + assert s_attr.is_constant() + bookkeeper = getbookkeeper() + actuals = [] + attr = s_attr.const + for c in pbc.prebuiltinstances: + bookkeeper.attrs_read_from_constants.setdefault(c, {})[attr] = True + if hasattr(c.value, attr): + actuals.append(immutablevalue(getattr(c.value, s_attr.const))) + return unionof(*actuals) + + def setattr(pbc, s_attr, s_value): + raise Exception, "oops!" + Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 17:56:54 2004 @@ -88,6 +88,9 @@ self.bindings[v] = s_value yield v + def getpbcattrs(self, pbc): + c = Constant(pbc) + return self.bookkeeper.attrs_read_from_constants.get(c, {}) #___ medium-level interface ____________________________ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Tue Nov 16 17:56:54 2004 @@ -8,6 +8,7 @@ from pypy.objspace.flow.model import FunctionGraph, Block, Link, last_exception from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph from pypy.translator.simplify import remove_direct_loops +from types import FunctionType # ____________________________________________________________ @@ -73,6 +74,24 @@ self.seennames[name] = True return name + def nameof_object(self, value): + if type(value) is not object: + raise Exception, "nameof(%r)" % (value,) + name = self.uniquename('g_object') + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) + return name + + def nameof_module(self, value): +## assert not hasattr(value, "__file__") or \ +## not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py')), \ +## "%r is not a builtin module (probably :)"%value + name = self.uniquename('mod%s'%value.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) + return name + + def nameof_int(self, value): if value >= 0: name = 'gint_%d' % value @@ -103,6 +122,8 @@ return name def nameof_function(self, func): + if self.translator.frozen: + assert func in self.translator.flowgraphs, func name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' @@ -111,6 +132,20 @@ self.pendingfunctions.append(func) return name + def nameof_staticmethod(self, sm): + # XXX XXX XXXX + func = sm.__get__(42.5) + if self.translator.frozen: + assert func in self.translator.flowgraphs, func + + name = self.uniquename('gsm_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.pendingfunctions.append(func) + return name + + def nameof_instancemethod(self, meth): if meth.im_self is None: # no error checking here @@ -125,7 +160,13 @@ 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( us, func, ob, typ)) return us - + + def should_translate_attr(self, pbc, attr): + ann = self.translator.annotator + if ann is None: + return "good luck" # True + return attr in ann.getpbcattrs(pbc) + def nameof_instance(self, instance): name = self.uniquename('ginst_' + instance.__class__.__name__) cls = self.nameof(instance.__class__) @@ -133,8 +174,9 @@ content = instance.__dict__.items() content.sort() for key, value in content: - yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( - name, key, self.nameof(value)) + if self.should_translate_attr(instance, key): + yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) @@ -168,6 +210,9 @@ continue # XXX some __NAMES__ are important... nicer solution sought #raise Exception, "unexpected name %r in class %s"%(key, cls) + if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: + continue + yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) self.globaldecl.append('static PyObject* %s;' % name) @@ -277,6 +322,10 @@ del g[:] def gen_cfunction(self, func): +## print 'gen_cfunction (%s:%d) %s' % ( +## func.func_globals.get('__name__', '?'), +## func.func_code.co_firstlineno, +## func.__name__) f = self.f body = list(self.cfunction_body(func)) self.gen_global_declarations() Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Tue Nov 16 17:56:54 2004 @@ -57,6 +57,7 @@ self.flowgraphs = {} # {function: graph} self.functions = [] # the keys of self.flowgraphs, in creation order self.callgraph = {} # {opaque_tag: (caller, callee)} + self.frozen = False # when frozen, no more flowgraphs can be generated self.getflowgraph() def getflowgraph(self, func=None, called_by=None, call_tag=None): @@ -70,6 +71,7 @@ func.func_globals.get('__name__', '?'), func.func_code.co_firstlineno, func.__name__) + assert not self.frozen space = FlowObjSpace() graph = space.build_flow(func) if self.simplifying: From mgedmin at codespeak.net Tue Nov 16 18:38:23 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 18:38:23 +0100 (MET) Subject: [pypy-svn] r7302 - pypy/trunk/src/pypy/translator Message-ID: <20041116173823.8B68C5AF46@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 18:38:22 2004 New Revision: 7302 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Store the tracebacks to show the reason why some block were left blocked in an attribute of the annotator. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 18:38:22 2004 @@ -23,6 +23,7 @@ self.pendingblocks = [] # list of (fn, block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen + self.why_not_annotated = {} # {block: traceback_where_BlockedInference_was_raised} self.notify = {} # {block: {factory-to-invalidate-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues self.bookkeeper = Bookkeeper(self) @@ -254,6 +255,7 @@ #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily + self.why_not_annotated[block] = sys.exc_info()[2] except Exception, e: # hack for debug tools only if not hasattr(e, '__annotator_block'): From mgedmin at codespeak.net Tue Nov 16 18:39:55 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 16 Nov 2004 18:39:55 +0100 (MET) Subject: [pypy-svn] r7303 - pypy/trunk/src/pypy/translator Message-ID: <20041116173955.2073E5AF51@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 16 18:39:54 2004 New Revision: 7303 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Oops. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 18:39:54 2004 @@ -255,6 +255,7 @@ #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily + import sys self.why_not_annotated[block] = sys.exc_info()[2] except Exception, e: # hack for debug tools only From arigo at codespeak.net Tue Nov 16 19:05:13 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 19:05:13 +0100 (MET) Subject: [pypy-svn] r7304 - pypy/trunk/src/pypy/annotation Message-ID: <20041116180513.3BE2E5AF9E@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 19:05:06 2004 New Revision: 7304 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Support for is_(). Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 16 19:05:06 2004 @@ -18,7 +18,7 @@ BINARY_OPERATIONS = set(['add', 'sub', 'mul', 'div', 'mod', 'getitem', 'setitem', 'inplace_add', 'inplace_sub', - 'lt', 'le', 'eq', 'ne', 'gt', 'ge', + 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_', 'union']) for opname in BINARY_OPERATIONS: @@ -39,6 +39,14 @@ def inplace_sub((obj1, obj2)): return pair(obj1, obj2).sub() # default + def lt((obj1, obj2)): return SomeBool() + def le((obj1, obj2)): return SomeBool() + def eq((obj1, obj2)): return SomeBool() + def ne((obj1, obj2)): return SomeBool() + def gt((obj1, obj2)): return SomeBool() + def ge((obj1, obj2)): return SomeBool() + def is_((obj1, obj2)): return SomeBool() + class __extend__(pairtype(SomeInteger, SomeInteger)): # unsignedness is considered a rare and contagious disease @@ -56,13 +64,6 @@ def sub((int1, int2)): return SomeInteger(unsigned = int1.unsigned or int2.unsigned) - def lt((int1, int2)): return SomeBool() - def le((int1, int2)): return SomeBool() - def eq((int1, int2)): return SomeBool() - def ne((int1, int2)): return SomeBool() - def gt((int1, int2)): return SomeBool() - def ge((int1, int2)): return SomeBool() - class __extend__(pairtype(SomeBool, SomeBool)): From arigo at codespeak.net Tue Nov 16 19:05:42 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 16 Nov 2004 19:05:42 +0100 (MET) Subject: [pypy-svn] r7305 - pypy/trunk/src/pypy/translator Message-ID: <20041116180542.8F3995AFCD@thoth.codespeak.net> Author: arigo Date: Tue Nov 16 19:05:40 2004 New Revision: 7305 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Debugging help: print the reason why blocks remain blocked. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 16 19:05:40 2004 @@ -110,6 +110,16 @@ fn, block, cells = self.pendingblocks.pop() self.processblock(fn, block, cells) if False in self.annotated.values(): + for block in self.annotated: + if self.annotated[block] is False: + import traceback + print '-+' * 30 + print 'BLOCKED block at:', + print self.why_not_annotated[block][1].break_at + print 'because of:' + traceback.print_exception(*self.why_not_annotated[block]) + print '-+' * 30 + print raise AnnotatorError('%d blocks are still blocked' % self.annotated.values().count(False)) @@ -256,7 +266,7 @@ #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily import sys - self.why_not_annotated[block] = sys.exc_info()[2] + self.why_not_annotated[block] = sys.exc_info() except Exception, e: # hack for debug tools only if not hasattr(e, '__annotator_block'): From bob at codespeak.net Wed Nov 17 09:48:59 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 09:48:59 +0100 (MET) Subject: [pypy-svn] r7306 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041117084859.5CB0B5B001@thoth.codespeak.net> Author: bob Date: Wed Nov 17 09:48:57 2004 New Revision: 7306 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: add a (failing) test to make sure MRO works as it does in Python Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 09:48:57 2004 @@ -98,5 +98,24 @@ else: raise AssertionError, "this multiple inheritance should fail" + def test_mro(self): + class A(object): + a = 1 + + class B(A): + b = 1 + class __metaclass__(type): + def mro(self): + return [self, object] + + self.assertEquals(B.__bases__, (A,)) + self.assertEquals(B.__mro__, (B, object)) + self.assertEquals(B.mro(), [B, object]) + self.assertEquals(B.b, 1) + self.assertEquals(B().b, 1) + self.assertEquals(getattr(B, 'a', None), None) + self.assertEquals(getattr(B(), 'a', None), None) + + if __name__ == '__main__': testit.main() From arigo at codespeak.net Wed Nov 17 10:31:08 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 10:31:08 +0100 (MET) Subject: [pypy-svn] r7307 - pypy/trunk/src/pypy/annotation Message-ID: <20041117093108.DBDAC5B002@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 10:31:08 2004 New Revision: 7307 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/unaryop.py Log: - calling prebuilt constant instances with a custom __call__ method - getattr() and type() built-ins Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 10:31:08 2004 @@ -39,6 +39,18 @@ return immutablevalue(True) return SomeBool() +def builtin_getattr(s_obj, s_attr): + if not s_attr.is_constant() or not isinstance(s_attr.const, str): + raise Exception, 'getattr(%r, %r) is not RPythonic enough' % ( + s_obj, s_attr) + return s_obj.getattr(s_attr) + +def builtin_type(s_obj, *moreargs): + if moreargs: + raise Exception, 'type() called with more than one argument' + #... + return SomeObject(knowntype=type) + # collect all functions import __builtin__ Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 17 10:31:08 2004 @@ -181,7 +181,9 @@ results.append(factory.pycall(func, s_self, *args)) return unionof(*results) + class __extend__(SomePrebuiltConstant): + def getattr(pbc, s_attr): assert s_attr.is_constant() bookkeeper = getbookkeeper() @@ -195,4 +197,7 @@ def setattr(pbc, s_attr, s_value): raise Exception, "oops!" - + + def simple_call(pbc, *args): + s_meth = pbc.getattr(immutablevalue("__call__")) + return s_meth.simple_call(*args) From mgedmin at codespeak.net Wed Nov 17 10:32:06 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 10:32:06 +0100 (MET) Subject: [pypy-svn] r7308 - pypy/trunk/src/pypy/translator/test Message-ID: <20041117093206.CA9F05B003@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 10:32:06 2004 New Revision: 7308 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Added a unit test to check whether calling prebuilt constants is able to follow the call graph. Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Wed Nov 17 10:32:06 2004 @@ -279,6 +279,16 @@ else: return never_called() +class CallablePrebuiltConstant(object): + def __call__(self): + return 42 + +callable_prebuilt_constant = CallablePrebuiltConstant() + +def call_cpbc(): + return callable_prebuilt_constant() + + # INHERITANCE / CLASS TESTS class C(object): pass Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Wed Nov 17 10:32:06 2004 @@ -268,6 +268,12 @@ a.simplify() #a.translator.view() + def test_call_pbc(self): + a = RPythonAnnotator() + s = a.build_types(snippet.call_cpbc, []) + self.assertEquals(s, annmodel.immutablevalue(42)) + + def g(n): return [0,1,2,n] From arigo at codespeak.net Wed Nov 17 11:11:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 11:11:34 +0100 (MET) Subject: [pypy-svn] r7309 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117101134.DD3D65B004@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 11:11:34 2004 New Revision: 7309 Modified: pypy/trunk/src/pypy/objspace/flow/model.py Log: Debugging help. Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Wed Nov 17 11:11:34 2004 @@ -89,11 +89,13 @@ class Variable: counter = 0 + instances = {} def __init__(self, name=None): if name is None: name = 'v%d' % Variable.counter Variable.counter += 1 self.name = name + Variable.instances[name] = self def __repr__(self): return '%s' % self.name From arigo at codespeak.net Wed Nov 17 11:12:16 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 11:12:16 +0100 (MET) Subject: [pypy-svn] r7310 - pypy/trunk/src/pypy/annotation Message-ID: <20041117101216.836C85B005@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 11:12:16 2004 New Revision: 7310 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Fiddling around... Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 11:12:16 2004 @@ -49,7 +49,7 @@ if moreargs: raise Exception, 'type() called with more than one argument' #... - return SomeObject(knowntype=type) + return SomeObject() # collect all functions Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 17 11:12:16 2004 @@ -186,18 +186,14 @@ def getattr(pbc, s_attr): assert s_attr.is_constant() + attr = s_attr.const bookkeeper = getbookkeeper() actuals = [] - attr = s_attr.const for c in pbc.prebuiltinstances: bookkeeper.attrs_read_from_constants.setdefault(c, {})[attr] = True if hasattr(c.value, attr): - actuals.append(immutablevalue(getattr(c.value, s_attr.const))) + actuals.append(immutablevalue(getattr(c.value, attr))) return unionof(*actuals) def setattr(pbc, s_attr, s_value): raise Exception, "oops!" - - def simple_call(pbc, *args): - s_meth = pbc.getattr(immutablevalue("__call__")) - return s_meth.simple_call(*args) From arigo at codespeak.net Wed Nov 17 11:25:21 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 11:25:21 +0100 (MET) Subject: [pypy-svn] r7311 - pypy/trunk/src/pypy/annotation Message-ID: <20041117102521.D29525B006@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 11:25:21 2004 New Revision: 7311 Modified: pypy/trunk/src/pypy/annotation/model.py Log: For debugging, record where each SomeObject instance comes from. See their .origin property. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 17 11:25:21 2004 @@ -30,6 +30,7 @@ from types import ClassType, BuiltinFunctionType, FunctionType, MethodType from types import InstanceType +import pypy from pypy.annotation.pairtype import pair, extendabletype from pypy.objspace.flow.model import Constant @@ -52,6 +53,22 @@ def is_constant(self): return hasattr(self, 'const') + # for debugging, record where each instance comes from + _coming_from = {} + def __new__(cls, *args, **kw): + self = super(SomeObject, cls).__new__(cls, *args, **kw) + try: + position_key = pypy.annotation.factory.getbookkeeper().position_key + except AttributeError: + pass + else: + SomeObject._coming_from[id(self)] = position_key + return self + def origin(self): + return SomeObject._coming_from[id(self)] + origin = property(origin) + + class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." knowntype = int From tismer at codespeak.net Wed Nov 17 12:38:44 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 17 Nov 2004 12:38:44 +0100 (MET) Subject: [pypy-svn] r7312 - pypy/trunk/src/pypy/translator Message-ID: <20041117113844.353365B007@thoth.codespeak.net> Author: tismer Date: Wed Nov 17 12:38:43 2004 New Revision: 7312 Modified: pypy/trunk/src/pypy/translator/translator.py Log: importing test.autopath is bad, because test is in Python's default path list, so we won't find it >:-) Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Wed Nov 17 12:38:43 2004 @@ -29,7 +29,7 @@ Try dir(test) for list of current snippets. """ -import test.autopath +import autopath from pypy.objspace.flow.model import * from pypy.annotation.model import * From bob at codespeak.net Wed Nov 17 12:51:37 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 12:51:37 +0100 (MET) Subject: [pypy-svn] r7313 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041117115137.A83345B008@thoth.codespeak.net> Author: bob Date: Wed Nov 17 12:51:37 2004 New Revision: 7313 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py Log: spelling correction in comment Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Wed Nov 17 12:51:37 2004 @@ -11,7 +11,7 @@ # This file defines three major classes: # -# MultiMethod is the class you instanciate explicitely. +# MultiMethod is the class you instanciate explicitly. # It is essentially just a collection of registered functions. # If xxx is a MultiMethod, StdObjSpace.xxx is xxx again, # and space.xxx is a BoundMultiMethod. From bob at codespeak.net Wed Nov 17 12:52:15 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 12:52:15 +0100 (MET) Subject: [pypy-svn] r7314 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20041117115215.9DEE55B009@thoth.codespeak.net> Author: bob Date: Wed Nov 17 12:52:15 2004 New Revision: 7314 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py pypy/trunk/src/pypy/objspace/std/typeobject.py Log: hackish mro support that seems to work anyway should look at CPython implementation for more ideas Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 12:52:15 2004 @@ -98,23 +98,48 @@ else: raise AssertionError, "this multiple inheritance should fail" + def skip_test_metaclass(self): + class OuterMetaClass(type): + pass + + class HasOuterMetaclass(object): + __metaclass__ = OuterMetaClass + + self.assertEquals(type(HasOuterMetaclass), OuterMetaClass) + self.assertEquals(type(HasOuterMetaclass), HasOuterMetaclass.__metaclass__) + + class HasInnerMetaclass(object): + class __metaclass__(type): + pass + + self.assertEquals(type(HasInnerMetaclass), HasInnerMetaclass.__metaclass__) + + class __metaclass__(type): + pass + + class HasImplicitMetaclass: + pass + + self.assertEquals(type(HasImplicitMetaclass), __metaclass__) + def test_mro(self): - class A(object): + class A_mro(object): a = 1 - class B(A): + class B_mro(A_mro): b = 1 class __metaclass__(type): def mro(self): return [self, object] - self.assertEquals(B.__bases__, (A,)) - self.assertEquals(B.__mro__, (B, object)) - self.assertEquals(B.mro(), [B, object]) - self.assertEquals(B.b, 1) - self.assertEquals(B().b, 1) - self.assertEquals(getattr(B, 'a', None), None) - self.assertEquals(getattr(B(), 'a', None), None) + #self.assertEquals(type(B_mro), B_mro.__metaclass__) + self.assertEquals(B_mro.__bases__, (A_mro,)) + self.assertEquals(B_mro.__mro__, (B_mro, object)) + self.assertEquals(B_mro.mro(), [B_mro, object]) + self.assertEquals(B_mro.b, 1) + self.assertEquals(B_mro().b, 1) + self.assertEquals(getattr(B_mro, 'a', None), None) + self.assertEquals(getattr(B_mro(), 'a', None), None) if __name__ == '__main__': Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Wed Nov 17 12:52:15 2004 @@ -15,7 +15,9 @@ w_self.bases_w = bases_w w_self.dict_w = dict_w w_self.ensure_static__new__() - w_self.mro_w = compute_C3_mro(w_self) # XXX call type(w_self).mro() + + #compute_C3_mro(w_self) # XXX call type(w_self).mro() + w_self.mro_w = compute_C3_mro(w_self) if overridetypedef is not None: w_self.instancetypedef = overridetypedef else: @@ -31,6 +33,14 @@ w_self.instancetypedef = instancetypedef if forcedict and not w_self.lookup('__dict__'): w_self.dict_w['__dict__'] = space.wrap(default_dict_descr) + if overridetypedef is None: + w_type = space.type(w_self) + if not space.is_true(space.is_(w_type, space.w_type)): + mro_func = w_type.lookup('mro') + mro_func_args = Arguments(space, [w_self]) + w_mro = space.call_args(mro_func, mro_func_args) + w_self.mro_w = space.unpackiterable(w_mro) + def ensure_static__new__(w_self): # special-case __new__, as in CPython: From bob at codespeak.net Wed Nov 17 12:56:04 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 12:56:04 +0100 (MET) Subject: [pypy-svn] r7315 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041117115604.A08E25B00B@thoth.codespeak.net> Author: bob Date: Wed Nov 17 12:56:04 2004 New Revision: 7315 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: check in a failing test.. __metaclass__ seems to be missing from dicts sometimes Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 12:56:04 2004 @@ -98,7 +98,7 @@ else: raise AssertionError, "this multiple inheritance should fail" - def skip_test_metaclass(self): + def test_metaclass(self): class OuterMetaClass(type): pass @@ -132,7 +132,6 @@ def mro(self): return [self, object] - #self.assertEquals(type(B_mro), B_mro.__metaclass__) self.assertEquals(B_mro.__bases__, (A_mro,)) self.assertEquals(B_mro.__mro__, (B_mro, object)) self.assertEquals(B_mro.mro(), [B_mro, object]) From bob at codespeak.net Wed Nov 17 13:01:23 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 13:01:23 +0100 (MET) Subject: [pypy-svn] r7316 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041117120123.C38995B00C@thoth.codespeak.net> Author: bob Date: Wed Nov 17 13:01:23 2004 New Revision: 7316 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: split up into separate tests Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 13:01:23 2004 @@ -98,7 +98,7 @@ else: raise AssertionError, "this multiple inheritance should fail" - def test_metaclass(self): + def test_outer_metaclass(self): class OuterMetaClass(type): pass @@ -108,12 +108,14 @@ self.assertEquals(type(HasOuterMetaclass), OuterMetaClass) self.assertEquals(type(HasOuterMetaclass), HasOuterMetaclass.__metaclass__) + def test_inner_metaclass(self): class HasInnerMetaclass(object): class __metaclass__(type): pass self.assertEquals(type(HasInnerMetaclass), HasInnerMetaclass.__metaclass__) + def test_implicit_metaclass(self): class __metaclass__(type): pass From mgedmin at codespeak.net Wed Nov 17 13:08:36 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 13:08:36 +0100 (MET) Subject: [pypy-svn] r7317 - in pypy/trunk/src/pypy/translator: . tool/pygame Message-ID: <20041117120836.102055A1D3@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 13:08:35 2004 New Revision: 7317 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Debugging feature: when flow analysis causes some inputargs of the starting block of a function to be generalized, remember the origin of that call and display it in the binding history graph as a hyperlink. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 17 13:08:35 2004 @@ -23,9 +23,17 @@ self.pendingblocks = [] # list of (fn, block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen - self.why_not_annotated = {} # {block: traceback_where_BlockedInference_was_raised} + self.why_not_annotated = {} # {block: (exc_type, exc_value, traceback)} + # records the location of BlockedInference + # exceptions that blocked some blocks. self.notify = {} # {block: {factory-to-invalidate-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues + self.binding_caused_by = {} # map Variables to Factories + # records the FuncCallFactory that caused bindings of inputargs + # to be updated + self.binding_cause_history = {} # map Variables to lists of Factories + # history of binding_caused_by, kept in sync with + # bindingshistory self.bookkeeper = Bookkeeper(self) #___ convenience high-level interface __________________ @@ -87,6 +95,7 @@ for attr, s_value in clsdef.attrs.items(): v = Variable(name=attr) self.bindings[v] = s_value + self.binding_caused_by[v] = None yield v def getpbcattrs(self, pbc): @@ -95,20 +104,20 @@ #___ medium-level interface ____________________________ - def addpendingblock(self, fn, block, cells): + def addpendingblock(self, fn, block, cells, called_from=None): """Register an entry point into block with the given input cells.""" assert self.translator is None or fn in self.translator.flowgraphs for a in cells: assert isinstance(a, annmodel.SomeObject) - self.pendingblocks.append((fn, block, cells)) + self.pendingblocks.append((fn, block, cells, called_from)) def complete(self): """Process pending blocks until none is left.""" while self.pendingblocks: # XXX don't know if it is better to pop from the head or the tail. # but suspect from the tail is better in the new Factory model. - fn, block, cells = self.pendingblocks.pop() - self.processblock(fn, block, cells) + fn, block, cells, called_from = self.pendingblocks.pop() + self.processblock(fn, block, cells, called_from) if False in self.annotated.values(): for block in self.annotated: if self.annotated[block] is False: @@ -134,13 +143,16 @@ else: raise TypeError, 'Variable or Constant expected, got %r' % (arg,) - def setbinding(self, arg, s_value): + def setbinding(self, arg, s_value, called_from=None): if arg in self.bindings: # for debugging purposes, record the history of bindings that # have been given to this variable history = self.bindingshistory.setdefault(arg, []) history.append(self.bindings[arg]) + cause_history = self.binding_cause_history.setdefault(arg, []) + cause_history.append(self.binding_caused_by[arg]) self.bindings[arg] = s_value + self.binding_caused_by[arg] = called_from #___ interface for annotator.factory _______ @@ -192,7 +204,7 @@ for extra in func.func_defaults[-missingargs:]: inputcells.append(annmodel.immutablevalue(extra)) inputcells.extend(extracells) - self.addpendingblock(func, block, inputcells) + self.addpendingblock(func, block, inputcells, factory) # get the (current) return value v = graph.getreturnvar() return self.bindings.get(v, annmodel.SomeImpossibleValue()) @@ -237,7 +249,7 @@ #___ flowing annotations in blocks _____________________ - def processblock(self, fn, block, cells): + def processblock(self, fn, block, cells, called_from=None): # Important: this is not called recursively. # self.flowin() can only issue calls to self.addpendingblock(). # The analysis of a block can be in three states: @@ -252,9 +264,9 @@ #print '* processblock', block, cells if block not in self.annotated: - self.bindinputargs(block, cells) + self.bindinputargs(block, cells, called_from) elif cells is not None: - self.mergeinputargs(block, cells) + self.mergeinputargs(block, cells, called_from) if not self.annotated[block]: self.annotated[block] = fn or True try: @@ -274,24 +286,24 @@ raise def reflowpendingblock(self, fn, block): - self.pendingblocks.append((fn, block, None)) + self.pendingblocks.append((fn, block, None, None)) assert block in self.annotated self.annotated[block] = False # must re-flow - def bindinputargs(self, block, inputcells): + def bindinputargs(self, block, inputcells, called_from=None): # Create the initial bindings for the input args of a block. for a, cell in zip(block.inputargs, inputcells): - self.setbinding(a, cell) + self.setbinding(a, cell, called_from) self.annotated[block] = False # must flowin. - def mergeinputargs(self, block, inputcells): + def mergeinputargs(self, block, inputcells, called_from=None): # Merge the new 'cells' with each of the block's existing input # variables. oldcells = [self.binding(a) for a in block.inputargs] unions = [annmodel.unionof(c1,c2) for c1, c2 in zip(oldcells,inputcells)] # if the merged cells changed, we must redo the analysis if unions != oldcells: - self.bindinputargs(block, unions) + self.bindinputargs(block, unions, called_from) def flowin(self, fn, block): #print 'Flowing', block, [self.binding(a) for a in block.inputargs] Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Wed Nov 17 13:08:35 2004 @@ -16,13 +16,58 @@ GraphLayout.__init__(self, fn) +class VariableHistoryGraphLayout(GraphLayout): + """ A GraphLayout showing the history of variable bindings. """ + + def __init__(self, translator, info, caused_by, history, func_names): + self.links = {} + self.func_by_name = {} + self.translator = translator + self.func_names = func_names + dotgen = DotGen('binding') + label = "Most recent binding\\n\\n%s" % nottoowide(info) + if caused_by is not None: + label += '\\n' + self.createlink(caused_by) + dotgen.emit_node('0', shape="box", color="red", label=label) + for n, (data, caused_by) in zip(range(len(history)), history): + label = nottoowide(data) + if caused_by is not None: + label += '\\n' + self.createlink(caused_by) + dotgen.emit_node(str(n+1), shape="box", label=label) + dotgen.emit_edge(str(n+1), str(n)) + links = self.links # GraphLayout.__init__ will override it with {} + GraphLayout.__init__(self, dotgen.generate(target='plain')) + self.links.update(links) + + def createlink(self, factory): + fn, block, pos = factory.position_key + fn_name = self.func_names.get(fn, fn.func_name) + basename = fn_name + n = 1 + while fn_name in self.links: + n += 1 + fn_name = '%s_%d' % (basename, n) + self.func_by_name[fn_name] = fn + # It would be nice to get the block name somehow + blockname = block.__class__.__name__ + self.links[fn_name] = '%s, %s, position %r' % (basename, blockname, + pos) + return 'Caused by a call from %s' % fn_name + + def followlink(self, funcname): + func = self.func_by_name[funcname] + # It would be nice to focus on the block + return FlowGraphLayout(self.translator, [func], self.func_names) + + class FlowGraphLayout(GraphLayout): """ A GraphLayout showing a Flow Graph (or a few flow graphs). """ - def __init__(self, translator, functions=None): + def __init__(self, translator, functions=None, func_names=None): from pypy.translator.tool.make_dot import make_dot_graphs self.translator = translator self.annotator = translator.annotator + self.func_names = func_names or {} functions = functions or translator.functions graphs = [translator.getflowgraph(func) for func in functions] gs = [(graph.name, graph) for graph in graphs] @@ -30,25 +75,25 @@ GraphLayout.__init__(self, fn) # make the dictionary of links -- one per annotated variable self.binding_history = {} + self.caused_by = {} if self.annotator: for var in self.annotator.bindings: s_value = self.annotator.binding(var) info = '%s: %s' % (var.name, s_value) self.links[var.name] = info + self.caused_by[var.name] = self.annotator.binding_caused_by[var] for var, history in self.annotator.bindingshistory.items(): - self.binding_history[var.name] = history + cause_history = self.annotator.binding_cause_history[var] + self.binding_history[var.name] = zip(history, cause_history) def followlink(self, varname): # clicking on a variable name shows its binding history - dotgen = DotGen('binding') - data = "Most recent binding\\n\\n%s" % nottoowide(self.links[varname]) - dotgen.emit_node('0', shape="box", color="red", label=data) + info = self.links[varname] + caused_by = self.caused_by[varname] history = list(self.binding_history.get(varname, [])) history.reverse() - for n, data in zip(range(len(history)), history): - dotgen.emit_node(str(n+1), shape="box", label=nottoowide(data)) - dotgen.emit_edge(str(n+1), str(n)) - return GraphLayout(dotgen.generate(target='plain')) + return VariableHistoryGraphLayout(self.translator, info, caused_by, + history, self.func_names) def nottoowide(text, width=72): @@ -99,6 +144,7 @@ def __init__(self, translator): self.translator = translator self.object_by_name = {} + self.name_by_object = {} dotgen = DotGen('translator') dotgen.emit('mclimit=15.0') @@ -147,6 +193,7 @@ i += 1 name = '%s__%d' % (objname, i) self.object_by_name[name] = obj + self.name_by_object[obj] = name return name def followlink(self, name): @@ -154,7 +201,7 @@ if isinstance(obj, factory.ClassDef): return ClassDefLayout(self.translator, obj) else: - return FlowGraphLayout(self.translator, [obj]) + return FlowGraphLayout(self.translator, [obj], self.name_by_object) def nameof(obj, cache={}): From mgedmin at codespeak.net Wed Nov 17 13:15:14 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 13:15:14 +0100 (MET) Subject: [pypy-svn] r7318 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041117121514.9C96B5B00D@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 13:15:14 2004 New Revision: 7318 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Show the endpoints of an edge in the status bar when it is highlighted. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Wed Nov 17 13:15:14 2004 @@ -257,6 +257,8 @@ return edge = self.viewer.edge_at_position(pos) if edge: + info = '%s -> %s' % (edge.tail.label, edge.head.label) + self.setstatusbar(info) self.sethighlight(obj=edge) return self.sethighlight() From bob at codespeak.net Wed Nov 17 14:44:31 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 14:44:31 +0100 (MET) Subject: [pypy-svn] r7319 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041117134431.DDE285A2DE@thoth.codespeak.net> Author: bob Date: Wed Nov 17 14:44:31 2004 New Revision: 7319 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: fix broken test Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 14:44:31 2004 @@ -116,13 +116,27 @@ self.assertEquals(type(HasInnerMetaclass), HasInnerMetaclass.__metaclass__) def test_implicit_metaclass(self): + global __metaclass__ + try: + old_metaclass = __metaclass__ + has_old_metaclass = True + except NameError: + has_old_metaclass = False + class __metaclass__(type): pass class HasImplicitMetaclass: pass - self.assertEquals(type(HasImplicitMetaclass), __metaclass__) + try: + self.assertEquals(type(HasImplicitMetaclass), __metaclass__) + finally: + if has_old_metaclass: + __metaclass__ = old_metaclass + else: + del __metaclass__ + def test_mro(self): class A_mro(object): From bob at codespeak.net Wed Nov 17 14:49:57 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 14:49:57 +0100 (MET) Subject: [pypy-svn] r7320 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041117134957.D67A05B00F@thoth.codespeak.net> Author: bob Date: Wed Nov 17 14:49:57 2004 New Revision: 7320 Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py Log: add a useful comment about why the c3 mro is always computed Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Wed Nov 17 14:49:57 2004 @@ -16,7 +16,6 @@ w_self.dict_w = dict_w w_self.ensure_static__new__() - #compute_C3_mro(w_self) # XXX call type(w_self).mro() w_self.mro_w = compute_C3_mro(w_self) if overridetypedef is not None: w_self.instancetypedef = overridetypedef @@ -31,6 +30,9 @@ space.wrap("instance layout conflicts in " "multiple inheritance")) w_self.instancetypedef = instancetypedef + # XXX - this w_self.lookup('__dict__') is why we precalculate a C3 mro + # even for instances that may override the mro. This probably is not + # a good thing to do. if forcedict and not w_self.lookup('__dict__'): w_self.dict_w['__dict__'] = space.wrap(default_dict_descr) if overridetypedef is None: From mgedmin at codespeak.net Wed Nov 17 14:59:17 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 14:59:17 +0100 (MET) Subject: [pypy-svn] r7321 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041117135917.79A515B010@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 14:59:16 2004 New Revision: 7321 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Supress redraws on every mouse movement when the highlighted object does not change. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Wed Nov 17 14:59:16 2004 @@ -90,6 +90,7 @@ self.font = pygame.font.Font(self.STATUSBARFONT, 16) self.viewers_history = [] self.forward_viewers_history = [] + self.highlight_word = None self.highlight_obj = None self.viewer = None self.method_cache = {} @@ -269,7 +270,6 @@ newlayout = self.layout.followlink(word) if newlayout is not None: self.setlayout(newlayout) - self.zoom_to_fit() return node = self.viewer.node_at_position(pos) if node: @@ -284,18 +284,24 @@ self.look_at_node(edge.tail) def sethighlight(self, word=None, obj=None): + # The initialization of self.viewer.highlightwords should probably be + # moved to setlayout() self.viewer.highlightwords = {} for name in self.layout.links: self.viewer.highlightwords[name] = ((128,0,0), None) if word: self.viewer.highlightwords[word] = ((255,255,80), (128,0,0)) + + if word == self.highlight_obj and obj is self.highlight_obj: + return # Nothing has changed, so there's no need to redraw + if self.highlight_obj is not None: self.highlight_obj.sethighlight(False) if obj is not None: obj.sethighlight(True) + self.highlight_word = word self.highlight_obj = obj self.must_redraw = True - def animation(self, expectedtime=0.6): start = time.time() From mgedmin at codespeak.net Wed Nov 17 15:04:26 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 15:04:26 +0100 (MET) Subject: [pypy-svn] r7322 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041117140426.80E475B011@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 15:04:25 2004 New Revision: 7322 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Make edge labels sane in function flow graphs. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Wed Nov 17 15:04:25 2004 @@ -258,7 +258,8 @@ return edge = self.viewer.edge_at_position(pos) if edge: - info = '%s -> %s' % (edge.tail.label, edge.head.label) + info = '%s -> %s' % (shortlabel(edge.tail.label), + shortlabel(edge.head.label)) self.setstatusbar(info) self.sethighlight(obj=edge) return @@ -447,3 +448,8 @@ # cannot safely close and re-open the display, depending on # Pygame version and platform. pygame.display.set_mode((self.width,1)) + + +def shortlabel(label): + """Shorten a graph node label.""" + return label.replace('\\l', '').splitlines()[0] From mwh at codespeak.net Wed Nov 17 15:09:58 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 15:09:58 +0100 (MET) Subject: [pypy-svn] r7323 - in pypy/trunk/src/pypy: objspace tool Message-ID: <20041117140958.D4C345B013@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 15:09:58 2004 New Revision: 7323 Added: pypy/trunk/src/pypy/tool/hack.py Modified: pypy/trunk/src/pypy/objspace/descroperation.py Log: Add a hack to copy a function with a new name. Use this to good effect in descroperation. Only supported for 2.3 and later because new.function is REALLY DUMB in 2.2 and I can't be bothered to hack around it. Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Wed Nov 17 15:09:58 2004 @@ -321,6 +321,8 @@ # regular methods def helpers +from pypy.tool.hack import func_with_new_name + def _make_binop_impl(symbol, specialnames): left, right = specialnames def binop_impl(space, w_obj1, w_obj2): @@ -343,7 +345,7 @@ return w_res raise OperationError(space.w_TypeError, space.wrap("unsupported operand type(s) for %s" % symbol)) - return binop_impl + return func_with_new_name(binop_impl, "binop_%s_impl"%left.strip('_')) def _make_comparison_impl(symbol, specialnames): left, right = specialnames @@ -374,7 +376,8 @@ res = space.unwrap(w_res) return space.wrap(op(res, 0)) - return comparison_impl + return func_with_new_name(comparison_impl, 'comparison_%s_impl'%left.strip('_')) + def _make_inplace_impl(symbol, specialnames): specialname, = specialnames @@ -391,7 +394,7 @@ # XXX fix the error message we get here return getattr(space, noninplacespacemethod)(w_lhs, w_rhs) - return inplace_impl + return func_with_new_name(inplace_impl, 'inplace_%s_impl'%specialname.strip('_')) def _make_unaryop_impl(symbol, specialnames): specialname, = specialnames @@ -401,7 +404,7 @@ raise OperationError(space.w_TypeError, space.wrap("operand does not support unary %s" % symbol)) return space.get_and_call_function(w_impl, w_obj) - return unaryop_impl + return func_with_new_name(unaryop_impl, 'unaryop_%s_impl'%specialname.strip('_')) # add regular methods Added: pypy/trunk/src/pypy/tool/hack.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/hack.py Wed Nov 17 15:09:58 2004 @@ -0,0 +1,20 @@ +import autopath + +import new, sys + +if sys.version_info > (2, 2): + + def func_with_new_name(func, newname): + return new.function(func.func_code, func.func_globals, + newname, func.func_defaults, + func.func_closure) + +else: + + def func_with_new_name(func, newname): + return func + +if __name__ == '__main__': + def f(): pass + g = func_with_new_name(f, 'g') + print g.__name__ From mgedmin at codespeak.net Wed Nov 17 15:30:19 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 15:30:19 +0100 (MET) Subject: [pypy-svn] r7324 - in pypy/trunk/src/pypy: annotation translator/tool/pygame Message-ID: <20041117143019.8B4085B014@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 15:30:18 2004 New Revision: 7324 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Show the origin of an annotation (if it is available) in the variable bindings history graph. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 17 15:30:18 2004 @@ -65,7 +65,7 @@ SomeObject._coming_from[id(self)] = position_key return self def origin(self): - return SomeObject._coming_from[id(self)] + return SomeObject._coming_from.get(id(self), None) origin = property(origin) Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Wed Nov 17 15:30:18 2004 @@ -19,28 +19,32 @@ class VariableHistoryGraphLayout(GraphLayout): """ A GraphLayout showing the history of variable bindings. """ - def __init__(self, translator, info, caused_by, history, func_names): + def __init__(self, translator, name, info, caused_by, history, func_names): self.links = {} self.func_by_name = {} self.translator = translator self.func_names = func_names dotgen = DotGen('binding') - label = "Most recent binding\\n\\n%s" % nottoowide(info) + label = "Most recent binding of %s\\n\\n%s" % (name, nottoowide(info)) + if info.origin is not None: + label += "\\n" + self.createlink(info.origin, 'Originated at') if caused_by is not None: - label += '\\n' + self.createlink(caused_by) + label += '\\n' + self.createlink(caused_by.position_key) dotgen.emit_node('0', shape="box", color="red", label=label) for n, (data, caused_by) in zip(range(len(history)), history): label = nottoowide(data) + if data.origin is not None: + label += "\\n" + self.createlink(data.origin, 'Originated at') if caused_by is not None: - label += '\\n' + self.createlink(caused_by) + label += '\\n' + self.createlink(caused_by.position_key) dotgen.emit_node(str(n+1), shape="box", label=label) dotgen.emit_edge(str(n+1), str(n)) links = self.links # GraphLayout.__init__ will override it with {} GraphLayout.__init__(self, dotgen.generate(target='plain')) self.links.update(links) - def createlink(self, factory): - fn, block, pos = factory.position_key + def createlink(self, position_key, wording='Caused by a call from'): + fn, block, pos = position_key fn_name = self.func_names.get(fn, fn.func_name) basename = fn_name n = 1 @@ -52,7 +56,7 @@ blockname = block.__class__.__name__ self.links[fn_name] = '%s, %s, position %r' % (basename, blockname, pos) - return 'Caused by a call from %s' % fn_name + return '%s %s' % (wording, fn_name) def followlink(self, funcname): func = self.func_by_name[funcname] @@ -75,12 +79,14 @@ GraphLayout.__init__(self, fn) # make the dictionary of links -- one per annotated variable self.binding_history = {} + self.current_value = {} self.caused_by = {} if self.annotator: for var in self.annotator.bindings: s_value = self.annotator.binding(var) info = '%s: %s' % (var.name, s_value) self.links[var.name] = info + self.current_value[var.name] = s_value self.caused_by[var.name] = self.annotator.binding_caused_by[var] for var, history in self.annotator.bindingshistory.items(): cause_history = self.annotator.binding_cause_history[var] @@ -88,12 +94,12 @@ def followlink(self, varname): # clicking on a variable name shows its binding history - info = self.links[varname] + cur_value = self.current_value[varname] caused_by = self.caused_by[varname] history = list(self.binding_history.get(varname, [])) history.reverse() - return VariableHistoryGraphLayout(self.translator, info, caused_by, - history, self.func_names) + return VariableHistoryGraphLayout(self.translator, varname, cur_value, + caused_by, history, self.func_names) def nottoowide(text, width=72): From arigo at codespeak.net Wed Nov 17 15:44:50 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 15:44:50 +0100 (MET) Subject: [pypy-svn] r7325 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117144450.405155B015@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 15:44:49 2004 New Revision: 7325 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: Detect early a situation which throws the flow object space into an infinite loop. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Wed Nov 17 15:44:49 2004 @@ -140,6 +140,12 @@ len(result), expected_length) return result + def unpackiterable(self, w_iterable, expected_length=None): + if isinstance(w_iterable, Variable) and expected_length is None: + raise UnwrapException, ("cannot unpack a Variable iterable " + "without knowing its length") + return ObjSpace.unpackiterable(self, w_iterable, expected_length) + # ____________________________________________________________ def do_operation(self, name, *args_w): spaceop = SpaceOperation(name, args_w, Variable()) From bob at codespeak.net Wed Nov 17 15:48:30 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 15:48:30 +0100 (MET) Subject: [pypy-svn] r7326 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20041117144830.8DD9F5B018@thoth.codespeak.net> Author: bob Date: Wed Nov 17 15:48:30 2004 New Revision: 7326 Added: pypy/trunk/src/pypy/objspace/std/dictproxyobject.py pypy/trunk/src/pypy/objspace/std/dictproxytype.py pypy/trunk/src/pypy/objspace/std/test/test_dictproxy.py Modified: pypy/trunk/src/pypy/objspace/std/typetype.py Log: dictproxy Added: pypy/trunk/src/pypy/objspace/std/dictproxyobject.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/std/dictproxyobject.py Wed Nov 17 15:48:30 2004 @@ -0,0 +1,19 @@ +from pypy.objspace.std.objspace import * +from pypy.interpreter.typedef import GetSetProperty + +def descr_get_dictproxy(space, w_obj): + obj = space.unwrap_builtin(w_obj) + return W_DictProxyObject(space, obj.getdict()) + +dictproxy_descr = GetSetProperty(descr_get_dictproxy) + +class W_DictProxyObject(W_Object): + from pypy.objspace.std.dictproxytype import dictproxy_typedef as typedef + + def __init__(w_self, space, w_dict): + W_Object.__init__(w_self, space) + w_self.w_dict = w_dict + +registerimplementation(W_DictProxyObject) + +register_all(vars()) Added: pypy/trunk/src/pypy/objspace/std/dictproxytype.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/std/dictproxytype.py Wed Nov 17 15:48:30 2004 @@ -0,0 +1,38 @@ +from pypy.objspace.std.stdtypedef import * +from pypy.objspace.std.register_all import register_all +from pypy.interpreter.error import OperationError + +# ____________________________________________________________ + +def proxymethod(name): + def fget(space, w_obj): + obj = space.unwrap_builtin(w_obj) + return space.getattr(obj.w_dict, space.wrap(name)) + return GetSetProperty(fget) + +# ____________________________________________________________ + +dictproxy_typedef = StdTypeDef("dictproxy", + has_key = proxymethod('has_key'), + get = proxymethod('get'), + keys = proxymethod('keys'), + values = proxymethod('values'), + items = proxymethod('items'), + iterkeys = proxymethod('iterkeys'), + itervalues = proxymethod('itervalues'), + iteritems = proxymethod('iteritems'), + copy = proxymethod('copy'), + __len__ = proxymethod('__len__'), + __getitem__ = proxymethod('__getitem__'), + __contains__ = proxymethod('__contains__'), + __str__ = proxymethod('__str__'), + __iter__ = proxymethod('__iter__'), + __cmp__ = proxymethod('__cmp__'), + __lt__ = proxymethod('__lt__'), + __le__ = proxymethod('__le__'), + __eq__ = proxymethod('__eq__'), + __ne__ = proxymethod('__ne__'), + __gt__ = proxymethod('__gt__'), + __ge__ = proxymethod('__ge__'), +) +dictproxy_typedef.registermethods(globals()) Added: pypy/trunk/src/pypy/objspace/std/test/test_dictproxy.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/std/test/test_dictproxy.py Wed Nov 17 15:48:30 2004 @@ -0,0 +1,25 @@ +import autopath +from pypy.tool import testit + +class TestUserObject(testit.AppTestCase): + def setUp(self): + self.space = testit.objspace('std') + + def test_dictproxy(self): + class NotEmpty: + a = 1 + self.assertEquals(isinstance(NotEmpty.__dict__, dict), False) + self.assert_('a' in NotEmpty.__dict__) + self.assert_('a' in NotEmpty.__dict__.keys()) + self.assert_('b' not in NotEmpty.__dict__) + self.assert_(isinstance(NotEmpty.__dict__.copy(), dict)) + self.assert_(NotEmpty.__dict__ == NotEmpty.__dict__.copy()) + try: + NotEmpty.__dict__['b'] = 1 + except: + pass + else: + raise AssertionError, 'this should not have been writable' + +if __name__ == '__main__': + testit.main() Modified: pypy/trunk/src/pypy/objspace/std/typetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/typetype.py Wed Nov 17 15:48:30 2004 @@ -1,5 +1,5 @@ from pypy.objspace.std.stdtypedef import * -from pypy.interpreter.typedef import default_dict_descr +from pypy.objspace.std.dictproxyobject import dictproxy_descr def descr__new__(space, w_typetype, w_name, w_bases, w_dict): @@ -46,6 +46,6 @@ __bases__ = GetSetProperty(descr__bases), __base__ = GetSetProperty(descr__base), __mro__ = GetSetProperty(descr_get__mro__), - __dict__ = default_dict_descr, + __dict__ = dictproxy_descr, mro = newmethod(descr_mro), ) From mgedmin at codespeak.net Wed Nov 17 15:54:28 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 15:54:28 +0100 (MET) Subject: [pypy-svn] r7327 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041117145428.744C85B017@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 15:54:27 2004 New Revision: 7327 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Updated variable binding history graph so that links to the same location use the same word. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Wed Nov 17 15:54:27 2004 @@ -21,7 +21,7 @@ def __init__(self, translator, name, info, caused_by, history, func_names): self.links = {} - self.func_by_name = {} + self.linkinfo = {} self.translator = translator self.func_names = func_names dotgen = DotGen('binding') @@ -45,23 +45,23 @@ def createlink(self, position_key, wording='Caused by a call from'): fn, block, pos = position_key - fn_name = self.func_names.get(fn, fn.func_name) - basename = fn_name + basename = self.func_names.get(fn, fn.func_name) + linkname = basename n = 1 - while fn_name in self.links: + while self.linkinfo.get(linkname, position_key) != position_key: n += 1 - fn_name = '%s_%d' % (basename, n) - self.func_by_name[fn_name] = fn + linkname = '%s_%d' % (basename, n) + self.linkinfo[linkname] = position_key # It would be nice to get the block name somehow blockname = block.__class__.__name__ - self.links[fn_name] = '%s, %s, position %r' % (basename, blockname, + self.links[linkname] = '%s, %s, position %r' % (basename, blockname, pos) - return '%s %s' % (wording, fn_name) + return '%s %s' % (wording, linkname) def followlink(self, funcname): - func = self.func_by_name[funcname] + fn, block, pos = self.linkinfo[funcname] # It would be nice to focus on the block - return FlowGraphLayout(self.translator, [func], self.func_names) + return FlowGraphLayout(self.translator, [fn], self.func_names) class FlowGraphLayout(GraphLayout): From bob at codespeak.net Wed Nov 17 16:09:10 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 16:09:10 +0100 (MET) Subject: [pypy-svn] r7328 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041117150910.99EB55B019@thoth.codespeak.net> Author: bob Date: Wed Nov 17 16:09:10 2004 New Revision: 7328 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: add failing tests for type __doc__ Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 16:09:10 2004 @@ -156,6 +156,40 @@ self.assertEquals(getattr(B_mro, 'a', None), None) self.assertEquals(getattr(B_mro(), 'a', None), None) + def test_nodoc(self): + class NoDoc(object): + pass + + try: + self.assertEquals(NoDoc.__doc__, None) + except AttributeError: + raise AssertionError, "__doc__ missing!" + + def test_explicitdoc(self): + class ExplicitDoc(object): + __doc__ = 'foo' + + self.assertEquals(ExplicitDoc.__doc__, 'foo') + + def test_implicitdoc(self): + class ImplicitDoc(object): + "foo" + + self.assertEquals(ImplicitDoc.__doc__, 'foo') + + def test_immutabledoc(self): + class ImmutableDoc(object): + "foo" + + try: + ImmutableDoc.__doc__ = "bar" + except TypeError: + pass + else: + raise AssertionError, '__doc__ should not be writable' + + self.assertEquals_(ImmutableDoc.__doc__, 'foo') + if __name__ == '__main__': testit.main() From bob at codespeak.net Wed Nov 17 16:32:48 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 16:32:48 +0100 (MET) Subject: [pypy-svn] r7329 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20041117153248.A46D55B01B@thoth.codespeak.net> Author: bob Date: Wed Nov 17 16:32:48 2004 New Revision: 7329 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py pypy/trunk/src/pypy/objspace/std/typetype.py Log: doc descriptor, tests Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Wed Nov 17 16:32:48 2004 @@ -185,10 +185,12 @@ ImmutableDoc.__doc__ = "bar" except TypeError: pass + except AttributeError: + print 'XXX - Python raises TypeError for several descriptors, we always raise AttributeError.' else: raise AssertionError, '__doc__ should not be writable' - self.assertEquals_(ImmutableDoc.__doc__, 'foo') + self.assertEquals(ImmutableDoc.__doc__, 'foo') if __name__ == '__main__': Modified: pypy/trunk/src/pypy/objspace/std/typetype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typetype.py (original) +++ pypy/trunk/src/pypy/objspace/std/typetype.py Wed Nov 17 16:32:48 2004 @@ -38,6 +38,9 @@ else: return space.w_object +def descr__doc(space, w_type): + return w_type.dict_w.get('__doc__') + # ____________________________________________________________ type_typedef = StdTypeDef("type", @@ -47,5 +50,6 @@ __base__ = GetSetProperty(descr__base), __mro__ = GetSetProperty(descr_get__mro__), __dict__ = dictproxy_descr, + __doc__ = GetSetProperty(descr__doc), mro = newmethod(descr_mro), ) From arigo at codespeak.net Wed Nov 17 16:44:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 16:44:18 +0100 (MET) Subject: [pypy-svn] r7330 - pypy/trunk/src/pypy/annotation Message-ID: <20041117154418.80B8F5B01E@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 16:44:17 2004 New Revision: 7330 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Try to preserve the origin of SomeObjects across generalizations. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Wed Nov 17 16:44:17 2004 @@ -31,7 +31,14 @@ if obj1 == obj2: return obj1 else: - return SomeObject() + result = SomeObject() + # try to preserve the origin of SomeObjects + if obj1 == result: + return obj1 + elif obj2 == result: + return obj2 + else: + return result def inplace_add((obj1, obj2)): return pair(obj1, obj2).add() # default From tismer at codespeak.net Wed Nov 17 16:56:23 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 17 Nov 2004 16:56:23 +0100 (MET) Subject: [pypy-svn] r7331 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041117155623.8CD945B01F@thoth.codespeak.net> Author: tismer Date: Wed Nov 17 16:56:23 2004 New Revision: 7331 Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py Log: small corrections to escaping double quotes Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Wed Nov 17 16:56:23 2004 @@ -95,9 +95,9 @@ name = self.prefix # +'_'+funcgraph.name data = name if hasattr(funcgraph, 'source'): - source = funcgraph.source.replace('"', "'") + source = funcgraph.source.replace('"', '\\"') data += "\\n" + "\\l".join(source.split('\n')) - + self.emit_node(name, label=data, shape="box", fillcolor="green", style="filled") #('%(name)s [fillcolor="green", shape=box, label="%(data)s"];' % locals()) self.emit_edge(name, self.blockname(funcgraph.startblock), 'startblock') @@ -126,6 +126,7 @@ iargs = " ".join(map(repr, block.inputargs)) data = "%s(%s)\\ninputargs: %s\\n\\n" % (name, block.__class__.__name__, iargs) data = data + "\l".join(lines) + data = data.replace('"', '\\"') # make dot happy self.emit_node(name, label=data, shape=shape, color=color, style="filled", fillcolor=fillcolor) From hpk at codespeak.net Wed Nov 17 16:57:09 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 16:57:09 +0100 (MET) Subject: [pypy-svn] r7332 - pypy/trunk/src/pypy Message-ID: <20041117155709.889BC5B024@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 16:57:09 2004 New Revision: 7332 Modified: pypy/trunk/src/pypy/TODO Log: small fix to the note about test upgrades Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Wed Nov 17 16:57:09 2004 @@ -47,7 +47,7 @@ * (documentation) generate a nice dot-graph from the structure of PyPy -* port pypy's testing framework to std.utest (probably a sprint topic, +* port pypy's testing framework to py.test (probably a sprint topic, as some discussion how to do it is required) * clear out and do a clean implementation of multimethod delegation. From tismer at codespeak.net Wed Nov 17 16:57:25 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 17 Nov 2004 16:57:25 +0100 (MET) Subject: [pypy-svn] r7333 - pypy/trunk/src/pypy/appspace Message-ID: <20041117155725.C70D55B027@thoth.codespeak.net> Author: tismer Date: Wed Nov 17 16:57:25 2004 New Revision: 7333 Modified: pypy/trunk/src/pypy/appspace/_formatting.py Log: removed star args from format, because I wanted to try the flow space on it, which cannot do this currently. Modified: pypy/trunk/src/pypy/appspace/_formatting.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_formatting.py (original) +++ pypy/trunk/src/pypy/appspace/_formatting.py Wed Nov 17 16:57:25 2004 @@ -377,8 +377,13 @@ except KeyError: raise ValueError("unsupported format character " "'%s' (%x) at index %d" - %(t[0], ord(t[0]), fmtiter.i)) - r.append(f(*t).format()) + %(t[0], ord(t[0]), fmtiter.i)) + # Trying to translate this using the flow space. + # Currently, star args give a problem there, + # so let's be explicit about the args: + # r.append(f(*t).format()) + char, flags, width, prec, value = t + r.append(f(char, flags, width, prec, value).format()) else: # efficiency hack: r.append(c + fmtiter.skip_to_fmt()) From hpk at codespeak.net Wed Nov 17 16:57:38 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 16:57:38 +0100 (MET) Subject: [pypy-svn] r7334 - pypy/trunk/src/pypy/tool Message-ID: <20041117155738.6AE5B5B036@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 16:57:37 2004 New Revision: 7334 Modified: pypy/trunk/src/pypy/tool/frozendict.py Log: make frozendict's naively hashable (using id(x)) Modified: pypy/trunk/src/pypy/tool/frozendict.py ============================================================================== --- pypy/trunk/src/pypy/tool/frozendict.py (original) +++ pypy/trunk/src/pypy/tool/frozendict.py Wed Nov 17 16:57:37 2004 @@ -5,3 +5,6 @@ raise TypeError, "this dict is already frozen, you are too late!" __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ + def __hash__(self): + return id(self) + From hpk at codespeak.net Wed Nov 17 16:58:06 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 16:58:06 +0100 (MET) Subject: [pypy-svn] r7335 - pypy/trunk/src/pypy/tool/pytest Message-ID: <20041117155806.D80E05B037@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 16:58:06 2004 New Revision: 7335 Modified: pypy/trunk/src/pypy/tool/pytest/ (props changed) pypy/trunk/src/pypy/tool/pytest/support.py Log: ignore *.pyc beginnings of testing the magic assertion at app level Modified: pypy/trunk/src/pypy/tool/pytest/support.py ============================================================================== --- pypy/trunk/src/pypy/tool/pytest/support.py (original) +++ pypy/trunk/src/pypy/tool/pytest/support.py Wed Nov 17 16:58:06 2004 @@ -3,6 +3,7 @@ py.magic.autopath() from pypy.objspace.std import StdObjSpace from pypy.interpreter.gateway import app2interp, interp2app +from pypy.interpreter.argument import Arguments class AppRunnerFrame: @@ -50,13 +51,24 @@ w_inspect_assertion) return w_myassertion -def test(): - space = StdObjSpace() +def setup_module(mod): + mod.space = StdObjSpace() + +def test_AppRunnerFrame(): w_glob = space.newdict([]) w_loc = space.newdict([]) runner = AppRunnerFrame(space, w_glob, w_loc) exprinfo.run("f = lambda x: x+1", runner) exprinfo.check("isinstance(f(2), float)", runner) +def test_myexception(): + def app_test_func(): + assert 42 == 43 + t = app2interp(app_test_func) + f = t.get_function(space) + #space.setitem(space.w_builtins, space.wrap('AssertionError'), + # build_pytest_assertion(space)) + f.call_args(Arguments([])) + if __name__ == '__main__': test() From hpk at codespeak.net Wed Nov 17 16:59:49 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 16:59:49 +0100 (MET) Subject: [pypy-svn] r7336 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117155949.87A315B038@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 16:59:49 2004 New Revision: 7336 Modified: pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: remove typos and unused code Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Wed Nov 17 16:59:49 2004 @@ -63,7 +63,7 @@ return uniqueitems([w for w in result if isinstance(w, Variable)]) def getconstants(self): - "Return all constants mentionned in this Block." + "Return all constants mentioned in this Block." result = self.inputargs[:] for op in self.operations: result += op.args Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Wed Nov 17 16:59:49 2004 @@ -109,7 +109,6 @@ def build_flow(self, func, constargs={}): """ """ - func = getattr(func, "translated_version", func) code = func.func_code code = PyCode()._from_code(code) if func.func_closure is None: From hpk at codespeak.net Wed Nov 17 17:03:43 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 17:03:43 +0100 (MET) Subject: [pypy-svn] r7337 - in pypy/trunk/src/pypy: annotation interpreter translator Message-ID: <20041117160343.764805B02A@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 17:03:42 2004 New Revision: 7337 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genpyrex.py Log: - medium refactoring: unify SomeFunction, SomeClass and SomeMethod to become SomeCallable. This is meant to prevent the union of e.g. SomeFunction and SomeClass to result in a SomeObject - mark loadfromcache() with "specialize = True" to notify the annotator that we want differented "inlined" or specialized versions of this function for the various calling places - hack genpyrex to continue to pass the tests - but translate_pypy.py now fails in a different seemingly unrelated way :-/ Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Wed Nov 17 17:03:42 2004 @@ -6,11 +6,11 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod +from pypy.annotation.model import SomeInstance, SomeCallable from pypy.annotation.model import SomeBuiltin, SomeIterator from pypy.annotation.model import SomePrebuiltConstant, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation -from pypy.annotation.factory import generalize +from pypy.annotation.factory import generalize, isclassdef from pypy.objspace.flow.model import Constant @@ -24,6 +24,13 @@ for opname in BINARY_OPERATIONS: missing_operation(pairtype(SomeObject, SomeObject), opname) +#class __extend__(pairtype(SomeFunction, SomeObject)): +# def union((obj1, obj2)): +# raise TypeError, "generalizing not allowed: %r AND %r" % (obj1, obj2) +# +#class __extend__(pairtype(SomeObject, SomeFunction)): +# def union((obj1, obj2)): +# raise TypeError, "generalizing not allowed: %r AND %r" % (obj2, obj1) class __extend__(pairtype(SomeObject, SomeObject)): @@ -31,6 +38,11 @@ if obj1 == obj2: return obj1 else: + #if isinstance(obj1, SomeFunction) or \ + # isinstance(obj2, SomeFunction): + # raise TypeError, ("generalizing not allowed:" + # "%r AND %r" % (obj1, obj2)) + # result = SomeObject() # try to preserve the origin of SomeObjects if obj1 == result: @@ -198,27 +210,19 @@ s_self = unionof(bltn1.s_self, bltn2.s_self) return SomeBuiltin(bltn1.analyser, s_self) +class __extend__(pairtype(SomeCallable, SomeCallable)): -class __extend__(pairtype(SomeFunction, SomeFunction)): - - def union((fun1, fun2)): - return SomeFunction(setunion(fun1.funcs, fun2.funcs)) - - -class __extend__(pairtype(SomeMethod, SomeMethod)): - - def union((met1, met2)): - # the union of the two meths dictionaries is a dictionary - # {func: commonbase(met1[func], met2[func])} - # note that this case is probably very rare - # (the same Python object found in two different classes) - d = met1.meths.copy() - for func, classdef in met2.meths.items(): - if func in d: - classdef = classdef.commonbase(d[func]) - d[func] = classdef - return SomeMethod(d) - + def union((cal1, cal2)): + d = cal1.callables.copy() + for cal, classdef in cal2.callables.items(): + if cal in d: + if bool(isclassdef(classdef)) ^ bool(isclassdef(d[cal])): + raise Exception( + "union failed for %r with classdefs %r and %r" % + (cal, classdef, d[cal])) + classdef = classdef.commonbase(d[cal]) + d[cal] = classdef + return SomeCallable(d) class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): @@ -239,13 +243,11 @@ # special case for SomePrebuiltConstants that are dictionaries # (actually frozendicts) possibleresults = [] - for c_inst in pbc1.prebuiltinstances: - assert isinstance(c_inst, Constant) - inst = c_inst.value + for inst in pbc1.prebuiltinstances: if isinstance(inst, dict): possibleresults += inst.values() - elif isinstance(inst, list): - possibleresults += inst # maybe + #elif isinstance(inst, list): + # possibleresults += inst # maybe else: raise TypeError, "cannot getitem() from %r" % (inst,) possibleresults = [immutablevalue(x) for x in possibleresults] Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Wed Nov 17 17:03:42 2004 @@ -7,7 +7,7 @@ """ from __future__ import generators -from types import FunctionType +from types import FunctionType, ClassType, MethodType from pypy.annotation.model import SomeImpossibleValue, SomeList, SomeDict from pypy.annotation.model import SomeObject, SomeInstance from pypy.annotation.model import unionof, immutablevalue @@ -94,6 +94,8 @@ factory.bookkeeper.annotator.reflowfromposition(factory.position_key) raise BlockedInference # reflow now +def isclassdef(x): + return isinstance(x, ClassDef) class ListFactory: s_item = SomeImpossibleValue() @@ -133,26 +135,42 @@ return False -class FuncCallFactory: - +class CallableFactory: def pycall(self, func, *args): + if isinstance(func, (type, ClassType)) and \ + func.__module__ != '__builtin__': + cls = func + classdef = self.bookkeeper.getclassdef(cls) + classdef.instancefactories[self] = True + s_instance = SomeInstance(classdef) + # flow into __init__() if the class has got one + init = getattr(cls, '__init__', None) + if init is not None and init != object.__init__: + self.pycall(init, s_instance, *args) + else: + assert not args, "no __init__ found in %r" % (cls,) + return s_instance + if hasattr(func, '__call__') and \ + isinstance(func.__call__, MethodType): + func = func.__call__ + if hasattr(func, 'im_func'): + if func.im_self is not None: + s_self = immutablevalue(func.im_self) + args = [s_self] + list(args) + func = func.im_func return self.bookkeeper.annotator.recursivecall(func, self, *args) - -class InstanceFactory(FuncCallFactory): - - def create(self, cls, *args): - classdef = self.bookkeeper.getclassdef(cls) - classdef.instancefactories[self] = True - s_instance = SomeInstance(classdef) - # flow into __init__() if the class has got one - init = getattr(cls, '__init__', None) - if init is not None and init != object.__init__: - self.pycall(init, s_instance, *args) - else: - assert not args, "no __init__ found in %r" % (cls,) - return s_instance - + #if hasattr(func, 'specialize'): + # key = func, factory.position_key + # try: + # func = self._cachespecializedfunctions[key] + # except KeyError: + # func = new.function(func.func_code, + # func.func_globals, + # func.func_name, + # func.func_defaults, + # func.func_closure) + # self._cachespecializedfunctions[key] = func class ClassDef: "Wraps a user class." @@ -184,7 +202,7 @@ # the following might still invalidate some blocks if it # generalizes existing values in parent classes s_value = immutablevalue(value) - s_value = s_value.classattribute(self) + s_value = s_value.bindcallables(self) self.generalize(name, s_value, bookkeeper) def __repr__(self): @@ -240,3 +258,5 @@ if bookkeeper: for factory in self.getallfactories(): bookkeeper.annotator.reflowfromposition(factory.position_key) + +from pypy.annotation.builtin import BUILTIN_FUNCTIONS Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 17 17:03:42 2004 @@ -117,12 +117,12 @@ def __init__(self, s_item=SomeObject()): self.s_item = s_item -class SomeClass(SomeObject): - "Stands for a user-defined class object." - # only used when the class object is loaded in a variable - knowntype = ClassType - def __init__(self, cls): - self.cls = cls +#class SomeClass(SomeObject): +# "Stands for a user-defined class object." +# # only used when the class object is loaded in a variable +# knowntype = ClassType +# def __init__(self, cls): +# self.cls = cls class SomeInstance(SomeObject): "Stands for an instance of a (user-defined) class." @@ -131,35 +131,48 @@ self.knowntype = classdef.cls self.revision = classdef.revision -class SomeBuiltin(SomeObject): +class SomeCallable(SomeObject): + """Stands for a (callable) function, method, + prebuiltconstant or class""" + def __init__(self, callables): + # callables is a dictionary containing concrete python + # callable objects as keys and - in the case of a method - + # the value contains the classdef (see SomeMethod above) + self.callables = callables + if len(callables) == 1: + self.const, = callables + +class SomeBuiltin(SomeCallable): "Stands for a built-in function or method with special-cased analysis." knowntype = BuiltinFunctionType # == BuiltinMethodType def __init__(self, analyser, s_self=None): self.analyser = analyser self.s_self = s_self -class SomeFunction(SomeObject): - """Stands for a Python function (or some function out of a list). - Alternatively, it can be a constant bound or unbound method.""" - knowntype = FunctionType - def __init__(self, funcs): - self.funcs = funcs # set of functions that this one may be - if len(funcs) == 1: - self.const, = funcs - -class SomeMethod(SomeObject): - "Stands for a bound Python method (or some method out of a list)." - knowntype = MethodType - def __init__(self, meths): - self.meths = meths # map {python_function: classdef} +#class SomeFunction(SomeObject): +# """Stands for a Python function (or some function out of a list). +# Alternatively, it can be a constant bound or unbound method.""" +# knowntype = FunctionType +# def __init__(self, funcs): +# self.funcs = funcs # set of functions that this one may be +# if len(funcs) == 1: +# self.const, = funcs + +#class SomeMethod(SomeObject): +# "Stands for a bound Python method (or some method out of a list)." +# knowntype = MethodType +# def __init__(self, meths): +# self.meths = meths # map {python_function: classdef} + class SomePrebuiltConstant(SomeObject): """Stands for a global user instance, built prior to the analysis, or a set of such instances.""" def __init__(self, prebuiltinstances): - self.prebuiltinstances = prebuiltinstances # set of Constants - self.knowntype = reduce(commonbase, [x.value.__class__ - for x in prebuiltinstances]) + self.prebuiltinstances = prebuiltinstances + self.knowntype = reduce(commonbase, + [x.__class__ for x in prebuiltinstances]) + class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that @@ -194,12 +207,10 @@ result = SomeTuple(items = [immutablevalue(e) for e in x]) elif ishashable(x) and x in BUILTIN_FUNCTIONS: result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) - elif isinstance(x, (type, ClassType)) and x.__module__ != '__builtin__': - result = SomeClass(x) - elif isinstance(x, (FunctionType, MethodType)): - result = SomeFunction({x: True}) + elif callable(x): + result = SomeCallable({x : True}) elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': - result = SomePrebuiltConstant({Constant(x): True}) # pre-built instances + result = SomePrebuiltConstant({x: True}) # pre-built inst: else: result = SomeObject() result.const = x Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 17 17:03:42 2004 @@ -7,13 +7,13 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass -from pypy.annotation.model import SomeFunction, SomeMethod, SomeIterator +from pypy.annotation.model import SomeInstance, SomeBuiltin +from pypy.annotation.model import SomeCallable, SomeIterator from pypy.annotation.model import SomePrebuiltConstant from pypy.annotation.model import immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper -from pypy.annotation.factory import InstanceFactory, FuncCallFactory +from pypy.annotation.factory import CallableFactory, isclassdef UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'simple_call', @@ -51,7 +51,7 @@ return immutablevalue(getattr(obj.const, attr)) return SomeObject() - def classattribute(obj, classdef): + def bindcallables(obj, classdef): return obj # default unbound __get__ implementation @@ -135,51 +135,46 @@ raise BlockedInference return SomeObject() - class __extend__(SomeBuiltin): - def simple_call(bltn, *args): if bltn.s_self is not None: return bltn.analyser(bltn.s_self, *args) else: return bltn.analyser(*args) +class __extend__(SomeCallable): + def simple_call(cal, *args): + factory = getbookkeeper().getfactory(CallableFactory) + results = [] + for func, classdef in cal.callables.items(): + if isclassdef(classdef): + # create s_self and record the creation in the factory + s_self = SomeInstance(classdef) + classdef.instancefactories[factory] = True + results.append(factory.pycall(func, s_self, *args)) + else: + results.append(factory.pycall(func, *args)) + return unionof(*results) -class __extend__(SomeClass): - - def simple_call(cls, *args): - factory = getbookkeeper().getfactory(InstanceFactory) - return factory.create(cls.cls, *args) - - -class __extend__(SomeFunction): - - def simple_call(fun, *args): - factory = getbookkeeper().getfactory(FuncCallFactory) - results = [factory.pycall(func, *args) for func in fun.funcs] - return unionof(*results) - - def classattribute(fun, classdef): # function -> unbound method + def bindcallables(cal, classdef): + """ turn the callables in the given SomeCallable 'cal' + into bound versions. + """ d = {} - for func in fun.funcs: - assert isinstance(func, FunctionType), ( - "%r should not be read out of class %r" % (func, classdef)) - d[func] = classdef - return SomeMethod(d) - - -class __extend__(SomeMethod): - - def simple_call(met, *args): - factory = getbookkeeper().getfactory(FuncCallFactory) - results = [] - for func, classdef in met.meths.items(): - # create s_self and record the creation in the factory - s_self = SomeInstance(classdef) - classdef.instancefactories[factory] = True - # call func(s_self, *arglist) - results.append(factory.pycall(func, s_self, *args)) - return unionof(*results) + for func, value in cal.callables.items(): + if isinstance(func, FunctionType): + if isclassdef(value): + print ("!!! rebinding an already bound" + " method %r with %r" % (func, value)) + d[func] = classdef + else: + d[func] = value + return SomeCallable(d) + + #def simple_call(fun, *args): + # factory = getbookkeeper().getfactory(CallableFactory) + # results = [factory.pycall(func, *args) for func in fun.funcs] + # return unionof(*results) class __extend__(SomePrebuiltConstant): @@ -191,8 +186,8 @@ actuals = [] for c in pbc.prebuiltinstances: bookkeeper.attrs_read_from_constants.setdefault(c, {})[attr] = True - if hasattr(c.value, attr): - actuals.append(immutablevalue(getattr(c.value, attr))) + if hasattr(c, attr): + actuals.append(immutablevalue(getattr(c, attr))) return unionof(*actuals) def setattr(pbc, s_attr, s_value): Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Wed Nov 17 17:03:42 2004 @@ -44,6 +44,9 @@ assert not isinstance(cache, frozendict) #print "building for key %r" % key return cache.setdefault(key, builder(key, self)) + # note to annotator: we want loadfromcache() to be + # specialized for the different cache types + loadfromcache.specialize = True def make_builtins(self, for_builtins): # initializing builtins may require creating a frame which in Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 17 17:03:42 2004 @@ -158,12 +158,6 @@ #___ interface for annotator.factory _______ def recursivecall(self, func, factory, *args): - # calls to methods: expand the argument - if hasattr(func, 'im_func'): - if func.im_self is not None: - s_self = annmodel.immutablevalue(func.im_self) - args = [s_self] + list(args) - func = func.im_func parent_fn, parent_block, parent_index = factory.position_key graph = self.translator.getflowgraph(func, parent_fn, factory.position_key) Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Wed Nov 17 17:03:42 2004 @@ -6,7 +6,8 @@ from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import mkentrymap from pypy.translator.annrpython import RPythonAnnotator -from pypy.annotation.model import SomeMethod +from pypy.annotation.model import SomeCallable +from pypy.annotation.factory import isclassdef import inspect class Op: @@ -397,8 +398,10 @@ self.indent += 1 empty = True for attr,s_value in cls.attrs.items(): - if isinstance(s_value,SomeMethod): - for py_fun,fun_class in s_value.meths.items(): + if isinstance(s_value, SomeCallable): + for py_fun,fun_class in s_value.callables.items(): + assert isclassdef(fun_class), ( + "%r must have a classdef" % py_fun) delay_methods.setdefault(fun_class,[]).append(py_fun) else: vartype=self._gettypename(s_value.knowntype) From mgedmin at codespeak.net Wed Nov 17 17:06:47 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 17:06:47 +0100 (MET) Subject: [pypy-svn] r7338 - pypy/trunk/src/pypy/appspace Message-ID: <20041117160647.2E5755B039@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 17:06:46 2004 New Revision: 7338 Modified: pypy/trunk/src/pypy/appspace/_formatting.py (contents, props changed) Log: Removed ^Ms and set svn:eol-style to native. Modified: pypy/trunk/src/pypy/appspace/_formatting.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_formatting.py (original) +++ pypy/trunk/src/pypy/appspace/_formatting.py Wed Nov 17 17:06:46 2004 @@ -9,7 +9,7 @@ class _Flags(object): def __repr__(self): - return "<%s>"%(', '.join([f for f in self.__dict__ + return "<%s>"%(', '.join([f for f in self.__dict__ if f[0] == 'f' and getattr(self, f)]),) f_ljust = 0 f_sign = 0 @@ -22,7 +22,7 @@ try: return valueiter.next() except StopIteration: - raise TypeError('not enough arguments for format string') + raise TypeError('not enough arguments for format string') def peel_num(c, fmtiter, valueiter): @@ -109,7 +109,7 @@ self.width = width self.prec = prec self.value = value - + def numeric_preprocess(self, v): # negative zeroes? # * mwh giggles, falls over @@ -117,7 +117,7 @@ import math if v < 0 or v == 0 and math.atan2(0, v) != 0: sign = '-' - v = -v + v = -v else: if self.flags.f_sign: sign = '+' @@ -140,7 +140,7 @@ if self.flags.f_zero: r = sign+padchar*p + r else: - r = padchar*p + sign + r + r = padchar*p + sign + r else: r = sign + r return r @@ -220,7 +220,7 @@ self.prec = 6 r = self._format(v) return self.numeric_postprocess(r, sign) - + class FloatFFormatter(FloatFormatter): def _format(self, v): @@ -336,7 +336,7 @@ '%':funcFormatter(lambda x:'%'), } - + class FmtIter(object): def __init__(self, fmt): self.fmt = fmt @@ -377,12 +377,12 @@ except KeyError: raise ValueError("unsupported format character " "'%s' (%x) at index %d" - %(t[0], ord(t[0]), fmtiter.i)) - # Trying to translate this using the flow space. - # Currently, star args give a problem there, - # so let's be explicit about the args: - # r.append(f(*t).format()) - char, flags, width, prec, value = t + %(t[0], ord(t[0]), fmtiter.i)) + # Trying to translate this using the flow space. + # Currently, star args give a problem there, + # so let's be explicit about the args: + # r.append(f(*t).format()) + char, flags, width, prec, value = t r.append(f(char, flags, width, prec, value).format()) else: # efficiency hack: @@ -398,4 +398,4 @@ raise TypeError('not all arguments converted ' 'during string formatting') return ''.join(r) - + From bob at codespeak.net Wed Nov 17 17:26:26 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 17:26:26 +0100 (MET) Subject: [pypy-svn] r7339 - pypy/trunk/src/pypy/tool Message-ID: <20041117162626.3D6735B03A@thoth.codespeak.net> Author: bob Date: Wed Nov 17 17:26:25 2004 New Revision: 7339 Modified: pypy/trunk/src/pypy/tool/frozendict.py Log: smarter hash implementation Modified: pypy/trunk/src/pypy/tool/frozendict.py ============================================================================== --- pypy/trunk/src/pypy/tool/frozendict.py (original) +++ pypy/trunk/src/pypy/tool/frozendict.py Wed Nov 17 17:26:25 2004 @@ -1,10 +1,16 @@ # hacks += 1 class frozendict(dict): - def __setitem__(self, *args): + _hash_cache = None + def __setitem__(self, *args): raise TypeError, "this dict is already frozen, you are too late!" - __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ + __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ def __hash__(self): - return id(self) + rval = self._hash_cache + if rval is None: + dct = self.items() + dct.sort() + rval = self._hash_cache = hash(tuple(dct)) ^ 0x18293742 + return rval From mwh at codespeak.net Wed Nov 17 17:36:28 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 17:36:28 +0100 (MET) Subject: [pypy-svn] r7340 - pypy/trunk/src/pypy/annotation Message-ID: <20041117163628.CC21B5B03E@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 17:36:28 2004 New Revision: 7340 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: Add a sanity assert. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Wed Nov 17 17:36:28 2004 @@ -158,6 +158,7 @@ s_self = immutablevalue(func.im_self) args = [s_self] + list(args) func = func.im_func + assert isinstance(func, FunctionType), "expected function, got %r"%func return self.bookkeeper.annotator.recursivecall(func, self, *args) #if hasattr(func, 'specialize'): From mwh at codespeak.net Wed Nov 17 17:43:30 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 17:43:30 +0100 (MET) Subject: [pypy-svn] r7341 - pypy/trunk/src/pypy/annotation Message-ID: <20041117164330.2BAD75B042@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 17:43:29 2004 New Revision: 7341 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: builtin_str. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 17:43:29 2004 @@ -51,6 +51,8 @@ #... return SomeObject() +def builtin_str(s_obj): + return SomeString() # collect all functions import __builtin__ From mwh at codespeak.net Wed Nov 17 17:44:52 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 17:44:52 +0100 (MET) Subject: [pypy-svn] r7342 - pypy/trunk/src/pypy/annotation Message-ID: <20041117164452.0D0FF5B045@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 17:44:51 2004 New Revision: 7342 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: Argh, add import. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 17:44:51 2004 @@ -3,6 +3,7 @@ """ from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool +from pypy.annotation.model import SomeString from pypy.annotation.model import immutablevalue from pypy.annotation.factory import ListFactory, getbookkeeper import pypy.objspace.std.restricted_int From hpk at codespeak.net Wed Nov 17 17:57:24 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Wed, 17 Nov 2004 17:57:24 +0100 (MET) Subject: [pypy-svn] r7343 - pypy/trunk/src/pypy/annotation Message-ID: <20041117165724.CF9925B04D@thoth.codespeak.net> Author: hpk Date: Wed Nov 17 17:57:24 2004 New Revision: 7343 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: the beginnings of filling caches and controling it via "allowbuildcache" as a flag on an objectspace Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 17:57:24 2004 @@ -3,6 +3,7 @@ """ from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool +from pypy.annotation.model import SomeTuple from pypy.annotation.model import SomeString from pypy.annotation.model import immutablevalue from pypy.annotation.factory import ListFactory, getbookkeeper @@ -46,6 +47,11 @@ s_obj, s_attr) return s_obj.getattr(s_attr) +def builtin_tuple(s_iterable): + if isinstance(s_iterable, SomeTuple): + return s_iterable + return SomeObject() + def builtin_type(s_obj, *moreargs): if moreargs: raise Exception, 'type() called with more than one argument' From arigo at codespeak.net Wed Nov 17 17:57:48 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 17:57:48 +0100 (MET) Subject: [pypy-svn] r7344 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117165748.0161C5B067@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 17:57:48 2004 New Revision: 7344 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: unpackiterable() on the flow object space cannot succeed, so let's HACK: pretend the iterable cannot have more than 7 items, and forget about the consequences. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Wed Nov 17 17:57:48 2004 @@ -141,8 +141,19 @@ def unpackiterable(self, w_iterable, expected_length=None): if isinstance(w_iterable, Variable) and expected_length is None: - raise UnwrapException, ("cannot unpack a Variable iterable " - "without knowing its length") + print ("*** cannot unpack a Variable iterable " + "without knowing its length, assuming up to 7 items") + w_iterator = self.iter(w_iterable) + items = [] + for i in range(7): + try: + w_item = self.next(w_iterator) + except OperationError, e: + if not e.match(self, self.w_StopIteration): + raise + break # done + items.append(w_item) + return items return ObjSpace.unpackiterable(self, w_iterable, expected_length) # ____________________________________________________________ From arigo at codespeak.net Wed Nov 17 17:58:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 17 Nov 2004 17:58:44 +0100 (MET) Subject: [pypy-svn] r7345 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117165844.9FF405B06B@thoth.codespeak.net> Author: arigo Date: Wed Nov 17 17:58:44 2004 New Revision: 7345 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: This seems necessary. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Wed Nov 17 17:58:44 2004 @@ -141,6 +141,7 @@ def unpackiterable(self, w_iterable, expected_length=None): if isinstance(w_iterable, Variable) and expected_length is None: + # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK print ("*** cannot unpack a Variable iterable " "without knowing its length, assuming up to 7 items") w_iterator = self.iter(w_iterable) @@ -154,6 +155,7 @@ break # done items.append(w_item) return items + # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK return ObjSpace.unpackiterable(self, w_iterable, expected_length) # ____________________________________________________________ From bob at codespeak.net Wed Nov 17 18:07:09 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 18:07:09 +0100 (MET) Subject: [pypy-svn] r7346 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041117170709.76BBF5B06C@thoth.codespeak.net> Author: bob Date: Wed Nov 17 18:07:08 2004 New Revision: 7346 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: fix spelling error in comment Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Wed Nov 17 18:07:08 2004 @@ -260,7 +260,7 @@ #print >> sys.stderr, 'Variable operation', name, args_w w_result = self.do_operation(name, *args_w) if exceptions: - # catch possible exceptions implicitely. If the OperationError + # catch possible exceptions implicitly. If the OperationError # below is not caught in the same function, it will produce an # exception-raising return block in the flow graph. The special # value 'wrap(last_exception)' is used as a marker for this kind From mwh at codespeak.net Wed Nov 17 18:12:38 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 18:12:38 +0100 (MET) Subject: [pypy-svn] r7347 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20041117171238.E68165B077@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 18:12:38 2004 New Revision: 7347 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py Log: Some only slightly scary code for allowing type information recovered by isinstance to flow into the 'then' clauses of if statements. So we can tell that code like: def flow_type_info(i): if isinstance(i, int): a = i + 1 else: a = len(str(i)) return a always returns an integer. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 18:12:38 2004 @@ -3,10 +3,10 @@ """ from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool -from pypy.annotation.model import SomeTuple -from pypy.annotation.model import SomeString -from pypy.annotation.model import immutablevalue +from pypy.annotation.model import SomeList, SomeString, SomeTuple +from pypy.annotation.model import immutablevalue, valueoftype from pypy.annotation.factory import ListFactory, getbookkeeper +from pypy.objspace.flow.model import Constant import pypy.objspace.std.restricted_int @@ -39,6 +39,22 @@ typ = s_type.const if issubclass(s_obj.knowntype, typ): return immutablevalue(True) + else: + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + fn, block, i = getbookkeeper().position_key + annotator = getbookkeeper().annotator + op = block.operations[i] + assert op.opname == "simple_call" + assert len(op.args) == 3 + assert op.args[0] == Constant(isinstance) + assert annotator.binding(op.args[1]) is s_obj + r = SomeBool() + r.knowntypedata = (op.args[1], valueoftype(typ)) + return r return SomeBool() def builtin_getattr(s_obj, s_attr): @@ -58,6 +74,9 @@ #... return SomeObject() +def builtin_list(s_obj): + return SomeList({}) + def builtin_str(s_obj): return SomeString() Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 17 18:12:38 2004 @@ -55,6 +55,10 @@ return obj # default unbound __get__ implementation +class __extend__(SomeBool): + def is_true(self): + return self + class __extend__(SomeTuple): def len(tup): Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 17 18:12:38 2004 @@ -314,8 +314,17 @@ if s_exitswitch.is_constant(): exits = [link for link in exits if link.exitcase == s_exitswitch.const] + knownvar, knownvarvalue = getattr(self.bindings.get(block.exitswitch), + "knowntypedata", (None, None)) for link in exits: - cells = [self.binding(a) for a in link.args] + cells = [] + for a in link.args: + if link.exitcase is True and a is knownvar \ + and self.binding(a).contains(knownvarvalue): + cell = knownvarvalue + else: + cell = self.binding(a) + cells.append(cell) self.addpendingblock(fn, link.target, cells) if block in self.notify: # invalidate some factories when this block is done From mwh at codespeak.net Wed Nov 17 18:13:39 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 17 Nov 2004 18:13:39 +0100 (MET) Subject: [pypy-svn] r7348 - pypy/trunk/src/pypy/annotation Message-ID: <20041117171339.4AAD15B078@thoth.codespeak.net> Author: mwh Date: Wed Nov 17 18:13:38 2004 New Revision: 7348 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: Didn't mean to check this bit in, sorry. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 17 18:13:38 2004 @@ -74,9 +74,6 @@ #... return SomeObject() -def builtin_list(s_obj): - return SomeList({}) - def builtin_str(s_obj): return SomeString() From tismer at codespeak.net Wed Nov 17 18:23:00 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 17 Nov 2004 18:23:00 +0100 (MET) Subject: [pypy-svn] r7349 - pypy/trunk/src/pypy/translator Message-ID: <20041117172300.512625B079@thoth.codespeak.net> Author: tismer Date: Wed Nov 17 18:22:59 2004 New Revision: 7349 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: fixed typo in comment Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 17 18:22:59 2004 @@ -236,7 +236,7 @@ raise CannotSimplify def simplify(self): - # Generic simpliciations + # Generic simplifications from pypy.translator import transform transform.transform_graph(self) From bob at codespeak.net Wed Nov 17 19:25:59 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Wed, 17 Nov 2004 19:25:59 +0100 (MET) Subject: [pypy-svn] r7351 - in pypy/trunk/src/pypy: annotation objspace/std Message-ID: <20041117182559.CD4F75B07A@thoth.codespeak.net> Author: bob Date: Wed Nov 17 19:25:56 2004 New Revision: 7351 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/objspace/std/multimethod.py Log: hack to analyze builtin methods Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 17 19:25:56 2004 @@ -34,7 +34,6 @@ from pypy.annotation.pairtype import pair, extendabletype from pypy.objspace.flow.model import Constant - class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" @@ -138,7 +137,7 @@ # callables is a dictionary containing concrete python # callable objects as keys and - in the case of a method - # the value contains the classdef (see SomeMethod above) - self.callables = callables + self.callables = callables if len(callables) == 1: self.const, = callables @@ -207,8 +206,13 @@ result = SomeTuple(items = [immutablevalue(e) for e in x]) elif ishashable(x) and x in BUILTIN_FUNCTIONS: result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) - elif callable(x): - result = SomeCallable({x : True}) + elif callable(x): + if hasattr(x, '__self__') and x.__self__ is not None: + x_self = immutablevalue(x.__self__) + x_name = immutablevalue(x.__name__) + result = x_self.getattr(x_name, hack=True) + else: + result = SomeCallable({x : True}) elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': result = SomePrebuiltConstant({x: True}) # pre-built inst: else: Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 17 19:25:56 2004 @@ -38,7 +38,7 @@ else: return SomeBool() - def getattr(obj, s_attr): + def getattr(obj, s_attr, hack=False): # get a SomeBuiltin if the SomeObject has # a corresponding method to handle it if s_attr.is_constant() and isinstance(s_attr.const, str): @@ -47,7 +47,7 @@ if analyser is not None: return SomeBuiltin(analyser, obj) # if the SomeObject is itself a constant, allow reading its attrs - if obj.is_constant() and hasattr(obj.const, attr): + if not hack and obj.is_constant() and hasattr(obj.const, attr): return immutablevalue(getattr(obj.const, attr)) return SomeObject() @@ -164,7 +164,7 @@ """ turn the callables in the given SomeCallable 'cal' into bound versions. """ - d = {} + d = cal.callables.copy() for func, value in cal.callables.items(): if isinstance(func, FunctionType): if isclassdef(value): Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Wed Nov 17 19:25:56 2004 @@ -1,4 +1,5 @@ from pypy.interpreter.baseobjspace import OperationError +from pypy.tool.frozendict import frozendict class FailedToImplement(Exception): @@ -61,6 +62,7 @@ try: return self.cache_table[argclasses] except KeyError: + assert not isinstance(self.cache_table, frozendict) calllist = [] self.internal_buildcalllist(argclasses, delegate, calllist) result = self.internal_compilecalllist(argclasses, calllist) From mgedmin at codespeak.net Wed Nov 17 19:45:53 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Wed, 17 Nov 2004 19:45:53 +0100 (MET) Subject: [pypy-svn] r7353 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041117184553.5960E5B07B@thoth.codespeak.net> Author: mgedmin Date: Wed Nov 17 19:45:50 2004 New Revision: 7353 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Added a very simple help window that shows keyboard and mouse bindings. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Wed Nov 17 19:45:50 2004 @@ -62,6 +62,9 @@ STATUSBAR_ALPHA = 0.75 STATUSBAR_FGCOLOR = (255, 255, 80) STATUSBAR_BGCOLOR = (128, 0, 0) + HELP_ALPHA = 0.95 + HELP_FGCOLOR = (255, 255, 80) + HELP_BGCOLOR = (0, 128, 0) KEYS = { 'meta -' : ('zoom', 0.5), @@ -82,9 +85,38 @@ 'shift right' : ('fast_pan', (1, 0)), 'shift up' : ('fast_pan', (0, -1)), 'shift down' : ('fast_pan', (0, 1)), + 'h': 'help', + 'f1': 'help', } - - + + HELP_MSG = """ + Key bindings: + + Meta - Zoom out + Meta + Zoom in + Meta 0 Actual size + Meta 1 Zoom to fit + + Arrows Scroll + Shift+Arrows Scroll faster + + Backspace Go back in history + Meta Left Go back in history + Meta Right Go forward in history + + H This help message + + Esc Quit + Meta Q Quit + + Mouse bindings: + + Click on objects to move around + Drag with the left mouse button to zoom in/out + Drag with the right mouse button to scroll + """.replace('\n ', '\n').strip() # poor man's dedent + + def __init__(self, layout): super(GraphDisplay, self).__init__() self.font = pygame.font.Font(self.STATUSBARFONT, 16) @@ -134,7 +166,32 @@ for key in keys: for mod in permute_mods(basemod, mods): self.key_cache[(key, mod)] = (method, args) - + + def help(self): + margin_x = margin_y = 64 + fgcolor = self.HELP_FGCOLOR + bgcolor = self.HELP_BGCOLOR + helpmsg = self.HELP_MSG + width = self.width - 2*margin_x + height = self.height - 2*margin_y + lines = rendertext(helpmsg, self.font, fgcolor, width) + block = pygame.Surface((width, height), SWSURFACE | SRCALPHA) + block.fill(bgcolor) + sx = sy = 8 + for img in lines: + w, h = img.get_size() + block.blit(img, (sx, sy)) + sy += h + block.set_alpha(int(255 * self.HELP_ALPHA)) + self.screen.blit(block, (margin_x, margin_y)) + + pygame.display.flip() + while 1: + e = pygame.event.wait() + if e.type in (MOUSEBUTTONDOWN, KEYDOWN, QUIT): + break + self.must_redraw = True + def setlayout(self, layout): if self.viewer: self.viewers_history.append(self.viewer) @@ -181,8 +238,7 @@ if self.viewers_history: info = 'Press Backspace to go back to previous screen' else: - info = ('Click to move around, or drag mouse buttons ' - '(left to zoom, right to scroll)') + info = 'Press H for help' self.setstatusbar(info) def updated_viewer(self): @@ -214,25 +270,11 @@ def drawstatusbar(self): text, fgcolor, bgcolor = self.statusbarinfo - words = text.split(' ') - lines = [] + lines = renderline(text, self.font, fgcolor, self.width) totalh = 0 - while words: - line = words.pop(0) - img = self.font.render(line, 1, fgcolor) - while words: - longerline = line + ' ' + words[0] - longerimg = self.font.render(longerline, 1, fgcolor) - w, h = longerimg.get_size() - if w > self.width: - break - words.pop(0) - line = longerline - img = longerimg - lines.append(img) + for img in lines: w, h = img.get_size() totalh += h - y = self.height - totalh self.status_bar_height = totalh + 16 block = pygame.Surface((self.width, self.status_bar_height), SWSURFACE | SRCALPHA) @@ -453,3 +495,36 @@ def shortlabel(label): """Shorten a graph node label.""" return label.replace('\\l', '').splitlines()[0] + + +def renderline(text, font, fgcolor, width): + """Render a single line of text into a list of images. + + Performs word wrapping. + """ + words = text.split(' ') + lines = [] + while words: + line = words.pop(0) + img = font.render(line, 1, fgcolor) + while words: + longerline = line + ' ' + words[0] + longerimg = font.render(longerline, 1, fgcolor) + w, h = longerimg.get_size() + if w > width: + break + words.pop(0) + line = longerline + img = longerimg + lines.append(img) + return lines + + +def rendertext(text, font, fgcolor, width): + """Render a multiline string into a list of images. + + Performs word wrapping for each line individually.""" + lines = [] + for line in text.splitlines(): + lines.extend(renderline(line, font, fgcolor, width)) + return lines From bob at codespeak.net Thu Nov 18 09:38:01 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Thu, 18 Nov 2004 09:38:01 +0100 (MET) Subject: [pypy-svn] r7354 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/std Message-ID: <20041118083801.975355B090@thoth.codespeak.net> Author: bob Date: Thu Nov 18 09:38:00 2004 New Revision: 7354 Modified: pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/std/register_all.py Log: a few spelling corrections in comments Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Thu Nov 18 09:38:00 2004 @@ -167,7 +167,7 @@ # This is similar to a Function object, but not bound to a particular # object space. During the call, the object space is either given - # explicitely as the first argument (for plain function), or is read + # explicitly as the first argument (for plain function), or is read # from 'self.space' for methods. # after initialization the following attributes should be set @@ -262,7 +262,7 @@ return [space.wrap(val) for val in self.staticdefs] def __call__(self, space, *args_w): - # to call the Gateway as a non-method, 'space' must be explicitely + # to call the Gateway as a non-method, 'space' must be explicitly # supplied. We build the Function object and call it. fn = self.get_function(space) return space.call_function(space.wrap(fn), *args_w) Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Nov 18 09:38:00 2004 @@ -265,7 +265,7 @@ # exception-raising return block in the flow graph. The special # value 'wrap(last_exception)' is used as a marker for this kind # of implicit exceptions, and simplify.py will remove it as per - # the RPython definition: implicit exceptions not explicitely + # the RPython definition: implicit exceptions not explicitly # caught in the same function are assumed not to occur. context = self.getexecutioncontext() outcome = context.guessexception(*exceptions) Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 09:38:00 2004 @@ -19,13 +19,13 @@ # # BoundMultiMethod is a MultiMethod or UnboundMultiMethod which # has been found to a specific object space. It is obtained by -# 'space.xxx' or explicitely by calling 'xxx.get(space)'. +# 'space.xxx' or explicitly by calling 'xxx.get(space)'. # # UnboundMultiMethod is a MultiMethod on which one argument # (typically the first one) has been restricted to be of some # statically known type. It is obtained by the syntax # W_XxxType.yyy, where W_XxxType is the static type class, -# or explicitely by calling 'xxx.slice(typeclass, arg_position)'. +# or explicitly by calling 'xxx.slice(typeclass, arg_position)'. # Its dispatch table is always a subset of the dispatch table of # the original MultiMethod; a new function registered in either # one may be automatically registered in the other one to keep Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Thu Nov 18 09:38:00 2004 @@ -382,7 +382,7 @@ # import the common base W_ObjectObject as well as # default implementations of some multimethods for all objects -# that don't explicitely override them or that raise FailedToImplement +# that don't explicitly override them or that raise FailedToImplement from pypy.objspace.std.register_all import register_all import pypy.objspace.std.objectobject import pypy.objspace.std.default Modified: pypy/trunk/src/pypy/objspace/std/register_all.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/register_all.py (original) +++ pypy/trunk/src/pypy/objspace/std/register_all.py Thu Nov 18 09:38:00 2004 @@ -104,7 +104,7 @@ def add_extra_comparisons(): """ - Add the missing comparison operators if they were not explicitely + Add the missing comparison operators if they were not explicitly defined: eq <-> ne and lt <-> le <-> gt <-> ge. We try to add them in the order defined by the OP_CORRESPONDANCES table, thus favouring swapping the arguments over negating the result. From arigo at codespeak.net Thu Nov 18 10:01:17 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 10:01:17 +0100 (MET) Subject: [pypy-svn] r7355 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118090117.B089D5B091@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 10:01:17 2004 New Revision: 7355 Modified: pypy/trunk/src/pypy/objspace/std/dump_multimethod.py pypy/trunk/src/pypy/objspace/std/multimethod.py Log: Automatically reduce the multimethod arity if the extra arguments are always W_ANY. Helps keep the caches smaller. Modified: pypy/trunk/src/pypy/objspace/std/dump_multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dump_multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/dump_multimethod.py Thu Nov 18 10:01:17 2004 @@ -53,9 +53,11 @@ def dump_table(mm, impls): print 'multimethod %r of arity %d.' % (mm.operatorsymbol, mm.arity) + if mm.dispatch_arity < mm.arity: + print 'dispatch arity is actually only %d.' % mm.dispatch_arity delegate = StdObjSpace.delegate versions = {} - for argclasses in cartesian_prod([impls] * mm.arity): + for argclasses in cartesian_prod([impls] * mm.dispatch_arity): calllist = [] mm.internal_buildcalllist(argclasses, delegate, calllist) src, glob = mm.internal_sourcecalllist(argclasses, calllist) @@ -76,22 +78,22 @@ # collapse ranges within argclasses where the last arg is not # relevant i = len(lstargclasses)-1 - m = mm.arity-1 + m = mm.dispatch_arity-1 while i >= 0: if i+len(impls) <= len(lstargclasses): model = lstargclasses[i][:m] for next in lstargclasses[i+1:i+len(impls)]: - if next[:m] == model and next[m+1:] == (W_ANY,)*(mm.arity-1-m): + if next[:m] == model and next[m+1:] == (W_ANY,)*(mm.dispatch_arity-1-m): pass else: break else: - lstargclasses[i:i+len(impls)] = [model + (W_ANY,)*(mm.arity-m)] + lstargclasses[i:i+len(impls)] = [model + (W_ANY,)*(mm.dispatch_arity-m)] if m > 0: m -= 1 continue i -= 1 - m = mm.arity-1 + m = mm.dispatch_arity-1 for argclasses in lstargclasses: print '#', @@ -129,7 +131,7 @@ total = 0 restrict = sys.argv[1:] for name, mm in list_multimethods(): - if not restrict or name in restrict: + if (not restrict and name != 'delegate') or name in restrict: print print '==========', name, '==========' print >> sys.stderr, name # progress bar Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 10:01:17 2004 @@ -17,10 +17,6 @@ # If xxx is a MultiMethod, StdObjSpace.xxx is xxx again, # and space.xxx is a BoundMultiMethod. # -# BoundMultiMethod is a MultiMethod or UnboundMultiMethod which -# has been found to a specific object space. It is obtained by -# 'space.xxx' or explicitly by calling 'xxx.get(space)'. -# # UnboundMultiMethod is a MultiMethod on which one argument # (typically the first one) has been restricted to be of some # statically known type. It is obtained by the syntax @@ -30,6 +26,10 @@ # the original MultiMethod; a new function registered in either # one may be automatically registered in the other one to keep # them in sync. +# +# BoundMultiMethod is a MultiMethod or UnboundMultiMethod which +# has been bound to a specific object space. It is obtained by +# 'space.xxx' or explicitly by calling 'xxx.get(space)'. class AbstractMultiMethod(object): @@ -42,15 +42,24 @@ self.dispatch_table = {} self.cache_table = {} self.cache_delegator_key = None + self.dispatch_arity = 0 def __repr__(self): return '<%s %s>' % (self.__class__.__name__, self.operatorsymbol) def register(self, function, *types): + assert len(types) == self.arity functions = self.dispatch_table.setdefault(types, []) if function not in functions: functions.append(function) self.cache_table.clear() + self.adjust_dispatch_arity(types) + + def adjust_dispatch_arity(self, types): + width = len(types) + while width > self.dispatch_arity and types[width-1] is W_ANY: + width -= 1 + self.dispatch_arity = width def compile_calllist(self, argclasses, delegate): """Compile a list of calls to try for the given classes of the @@ -158,7 +167,7 @@ argument, with [] meaning that no conversion is needed for that argument.""" # look for an exact match first - arity = self.arity + arity = self.dispatch_arity assert arity == len(argclasses) dispatchclasses = tuple([(c,) for c in argclasses]) choicelist = self.buildchoices(dispatchclasses) @@ -248,7 +257,8 @@ pass def internal_buildchoices(self, initialtypes, currenttypes, result): - if len(currenttypes) == self.arity: + if len(currenttypes) == self.dispatch_arity: + currenttypes += (W_ANY,) * (self.arity - self.dispatch_arity) for func in self.dispatch_table.get(currenttypes, []): if func not in result: # ignore duplicates result.append((currenttypes, func)) @@ -295,7 +305,7 @@ def register(self, function, *types): AbstractMultiMethod.register(self, function, *types) - # register the function is unbound versions that match + # register the function into unbound versions that match for m in self.unbound_versions.values(): if m.match(types): AbstractMultiMethod.register(m, function, *types) @@ -366,6 +376,7 @@ for types, functions in basemultimethod.dispatch_table.iteritems(): if self.match(types): self.dispatch_table[types] = functions + self.adjust_dispatch_arity(types) #print basemultimethod.operatorsymbol, typeclass, self.dispatch_table def register(self, function, *types): @@ -422,7 +433,7 @@ else: # raise a TypeError for a FailedToImplement initialtypes = [a.__class__ - for a in args[:self.multimethod.arity]] + for a in args[:self.multimethod.dispatch_arity]] if len(initialtypes) <= 1: plural = "" else: @@ -439,7 +450,7 @@ assert isinstance(a, self.ASSERT_BASE_TYPE), ( "'%s' multimethod got a non-wrapped argument: %r" % ( self.multimethod.operatorsymbol, a)) - arity = self.multimethod.arity + arity = self.multimethod.dispatch_arity argclasses = tuple([a.__class__ for a in args[:arity]]) delegate = self.space.delegate.multimethod fn = self.multimethod.compile_calllist(argclasses, delegate) From arigo at codespeak.net Thu Nov 18 10:37:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 10:37:18 +0100 (MET) Subject: [pypy-svn] r7356 - pypy/trunk/src/pypy/annotation Message-ID: <20041118093718.62B8F5B093@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 10:37:17 2004 New Revision: 7356 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Removed the 'hack' argument. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 10:37:17 2004 @@ -208,9 +208,10 @@ result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) elif callable(x): if hasattr(x, '__self__') and x.__self__ is not None: - x_self = immutablevalue(x.__self__) - x_name = immutablevalue(x.__name__) - result = x_self.getattr(x_name, hack=True) + s_self = immutablevalue(x.__self__) + del s_self.const # stop infinite recursion getattr<->immutablevalue + s_name = immutablevalue(x.__name__) + result = s_self.getattr(s_name) else: result = SomeCallable({x : True}) elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu Nov 18 10:37:17 2004 @@ -38,7 +38,7 @@ else: return SomeBool() - def getattr(obj, s_attr, hack=False): + def getattr(obj, s_attr): # get a SomeBuiltin if the SomeObject has # a corresponding method to handle it if s_attr.is_constant() and isinstance(s_attr.const, str): @@ -47,7 +47,7 @@ if analyser is not None: return SomeBuiltin(analyser, obj) # if the SomeObject is itself a constant, allow reading its attrs - if not hack and obj.is_constant() and hasattr(obj.const, attr): + if obj.is_constant() and hasattr(obj.const, attr): return immutablevalue(getattr(obj.const, attr)) return SomeObject() From bob at codespeak.net Thu Nov 18 11:04:43 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Thu, 18 Nov 2004 11:04:43 +0100 (MET) Subject: [pypy-svn] r7357 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118100443.60A705B09B@thoth.codespeak.net> Author: bob Date: Thu Nov 18 11:04:42 2004 New Revision: 7357 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py Log: Change the return signature of register so that we can be smarter about invalidating caches and calling lots of functions that will do nothing. Rewrite comments slightly to be a big clearer about what is going on. Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 11:04:42 2004 @@ -12,7 +12,7 @@ # This file defines three major classes: # -# MultiMethod is the class you instanciate explicitly. +# MultiMethod is the class you instantiate explicitly. # It is essentially just a collection of registered functions. # If xxx is a MultiMethod, StdObjSpace.xxx is xxx again, # and space.xxx is a BoundMultiMethod. @@ -22,10 +22,13 @@ # statically known type. It is obtained by the syntax # W_XxxType.yyy, where W_XxxType is the static type class, # or explicitly by calling 'xxx.slice(typeclass, arg_position)'. -# Its dispatch table is always a subset of the dispatch table of -# the original MultiMethod; a new function registered in either -# one may be automatically registered in the other one to keep -# them in sync. +# Its dispatch table is always a subset of the original MultiMethod's +# dispatch table. +# +# The registration of a new function to a MultiMethod will be propagated +# to all of its matching UnboundMultiMethod instances. The registration of +# a function directly to an UnboundMultiMethod will register the function +# to its base MultiMethod and invoke the same behavior. # # BoundMultiMethod is a MultiMethod or UnboundMultiMethod which # has been bound to a specific object space. It is obtained by @@ -50,10 +53,12 @@ def register(self, function, *types): assert len(types) == self.arity functions = self.dispatch_table.setdefault(types, []) - if function not in functions: - functions.append(function) - self.cache_table.clear() - self.adjust_dispatch_arity(types) + if function in functions: + return False + functions.append(function) + self.cache_table.clear() + self.adjust_dispatch_arity(types) + return True def adjust_dispatch_arity(self, types): width = len(types) @@ -304,11 +309,13 @@ return m def register(self, function, *types): - AbstractMultiMethod.register(self, function, *types) + if not AbstractMultiMethod.register(self, function, *types): + return False # register the function into unbound versions that match for m in self.unbound_versions.values(): if m.match(types): AbstractMultiMethod.register(m, function, *types) + return True class DelegateMultiMethod(MultiMethod): @@ -318,8 +325,10 @@ self.key = object() def register(self, function, *types): - AbstractMultiMethod.register(self, function, *types) + if not AbstractMultiMethod.register(self, function, *types): + return False self.key = object() # change the key to force recomputation + return True def postprocessresult(self, allowedtypes, result): # add delegation from a class to the *first* immediate parent class @@ -380,10 +389,12 @@ #print basemultimethod.operatorsymbol, typeclass, self.dispatch_table def register(self, function, *types): - AbstractMultiMethod.register(self, function, *types) + if not AbstractMultiMethod.register(self, function, *types): + return False # propagate the function registeration to the base multimethod # and possibly other UnboundMultiMethods self.basemultimethod.register(function, *types) + return True def match(self, types): # check if the 'types' signature statically corresponds to the From arigo at codespeak.net Thu Nov 18 11:12:30 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 11:12:30 +0100 (MET) Subject: [pypy-svn] r7358 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20041118101230.8B6BA5B09E@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 11:12:30 2004 New Revision: 7358 Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Log: If all the XXXs where printed instead of being just comments, PyPy would quickly fill up your terminal with Xes :-) Modified: pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_typeobject.py Thu Nov 18 11:12:30 2004 @@ -186,7 +186,9 @@ except TypeError: pass except AttributeError: - print 'XXX - Python raises TypeError for several descriptors, we always raise AttributeError.' + # XXX - Python raises TypeError for several descriptors, + # we always raise AttributeError. + pass else: raise AssertionError, '__doc__ should not be writable' From mgedmin at codespeak.net Thu Nov 18 11:18:11 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 11:18:11 +0100 (MET) Subject: [pypy-svn] r7359 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118101811.77D045B09F@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 11:18:10 2004 New Revision: 7359 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: When showing the origin of an annotation in variable binding history graph, also show the operation itself. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Thu Nov 18 11:18:10 2004 @@ -54,8 +54,8 @@ self.linkinfo[linkname] = position_key # It would be nice to get the block name somehow blockname = block.__class__.__name__ - self.links[linkname] = '%s, %s, position %r' % (basename, blockname, - pos) + self.links[linkname] = '%s, %s, position %r:\n%s' % (basename, + blockname, pos, block.operations[pos]) return '%s %s' % (wording, linkname) def followlink(self, funcname): @@ -187,7 +187,7 @@ source = inspect.getsource(func) except IOError: # e.g. when func is defined interactively source = func.func_name - data = '%s:%d %s' % (func.func_globals.get('__name__', '?'), + data = '%s:%d\n%s' % (func.func_globals.get('__name__', '?'), func.func_code.co_firstlineno, source.split('\n')[0]) self.links[name] = data Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 11:18:10 2004 @@ -270,7 +270,7 @@ def drawstatusbar(self): text, fgcolor, bgcolor = self.statusbarinfo - lines = renderline(text, self.font, fgcolor, self.width) + lines = rendertext(text, self.font, fgcolor, self.width) totalh = 0 for img in lines: w, h = img.get_size() From hpk at codespeak.net Thu Nov 18 11:18:30 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 11:18:30 +0100 (MET) Subject: [pypy-svn] r7360 - in pypy/trunk/src: goal pypy/annotation pypy/interpreter pypy/interpreter/test pypy/objspace/flow pypy/objspace/std pypy/tool pypy/tool/test Message-ID: <20041118101830.D5BDD5B0A3@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 11:18:30 2004 New Revision: 7360 Added: pypy/trunk/src/pypy/tool/cache.py - copied, changed from r7351, pypy/trunk/src/pypy/tool/frozendict.py pypy/trunk/src/pypy/tool/test/test_cache.py Removed: pypy/trunk/src/pypy/tool/frozendict.py Modified: pypy/trunk/src/goal/buildcache.py pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/pycode.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/interpreter/test/test_code.py pypy/trunk/src/pypy/objspace/flow/specialcase.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: frozendict is dead, long live the freezable Cache class. for any code reachable by the annotator/translator you need to/should use pypy.tool.cache.Cache(). When the annotator sees such a cache it calls the "freeze()" method on it after which it cannot be modified anymore and also becomes hashable as a side effect. A Cache has a getorbuild() method where you pass in a key, a builder and a space. In case the key is not in the cache yet and the cache is not frozen, builder(key, space) will be called to obtain the value. Various places now use Cache instead of plain dictionaries. Modified: pypy/trunk/src/goal/buildcache.py ============================================================================== --- pypy/trunk/src/goal/buildcache.py (original) +++ pypy/trunk/src/goal/buildcache.py Thu Nov 18 11:18:30 2004 @@ -1,6 +1,5 @@ from pypy.tool import option, autopath, testit from pypy.interpreter import gateway -from pypy.tool.frozendict import frozendict import os ####################################################### @@ -32,14 +31,21 @@ gateway.importall(globals()) # app_xxx() -> xxx() ####################################################### +from pypy.objspace.std import stdtypedef def buildcache(space): print "triggering cache build for %r" % space triggerall(space) triggerexec(space) - space._typecache = frozendict(space._typecache) - space._faketypecache = frozendict(space._faketypecache) - space._gatewaycache = frozendict(space._gatewaycache) + #testit.main(os.path.join(autopath.pypydir, 'objspace', 'std')) + #Cache.freeze() + #space._typecache = frozendict(space._typecache) + #space._faketypecache = frozendict(space._faketypecache) + #space._gatewaycache = frozendict(space._gatewaycache) + #space = option.objspace('std') + #buildcache(space) + #for x in stdtypedef._temp: + # x.cache_table = frozendict(x.cache_table) print "cache build finished, caches are 'frozen' now" if __name__ == '__main__': Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Thu Nov 18 11:18:30 2004 @@ -6,9 +6,9 @@ from pypy.objspace.std.intobject import W_IntObject from pypy.translator.translator import Translator from pypy.annotation import model as annmodel +from pypy.tool.cache import Cache -import buildcache - +#from buildcache import buildcache # __________ Entry point __________ def entry_point(): @@ -22,12 +22,13 @@ def analyse(entry_point=entry_point): global t, space space = StdObjSpace() - buildcache.buildcache(space) + # call the entry_point once to trigger building of all + # caches (as far as analyzing the entry_point is concerned) + entry_point() t = Translator(entry_point, verbose=True, simplifying=True) a = t.annotate([]) a.simplify() - if __name__ == '__main__': def about(x): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 11:18:30 2004 @@ -33,6 +33,7 @@ import pypy from pypy.annotation.pairtype import pair, extendabletype from pypy.objspace.flow.model import Constant +from pypy.tool.cache import Cache class SomeObject: """The set of all objects. Each instance stands @@ -215,6 +216,8 @@ else: result = SomeCallable({x : True}) elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': + if isinstance(x, Cache) and not x.frozen: + x.freeze() result = SomePrebuiltConstant({x: True}) # pre-built inst: else: result = SomeObject() Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Thu Nov 18 11:18:30 2004 @@ -2,7 +2,7 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.miscutils import getthreadlocals from pypy.interpreter.argument import Arguments -from pypy.tool.frozendict import frozendict +from pypy.tool.cache import Cache __all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'BaseWrappable', 'W_Root'] @@ -33,21 +33,10 @@ def __init__(self): "Basic initialization of objects." - self._gatewaycache = {} + self._gatewaycache = Cache() # sets all the internal descriptors self.initialize() - def loadfromcache(self, key, builder, cache): - try: - return cache[key] - except KeyError: - assert not isinstance(cache, frozendict) - #print "building for key %r" % key - return cache.setdefault(key, builder(key, self)) - # note to annotator: we want loadfromcache() to be - # specialized for the different cache types - loadfromcache.specialize = True - def make_builtins(self, for_builtins): # initializing builtins may require creating a frame which in # turn already accesses space.w_builtins, provide a dummy one ... @@ -101,6 +90,10 @@ """Abstract method that should put some minimal content into the w_builtins.""" + def loadfromcache(self, key, builder, cache): + return cache.getorbuild(key, builder, self) + loadfromcache.specialize = True + def getexecutioncontext(self): "Return what we consider to be the active execution context." ec = getthreadlocals().executioncontext Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Thu Nov 18 11:18:30 2004 @@ -15,7 +15,7 @@ from pypy.interpreter.function import Function, Method from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.argument import Arguments - +from pypy.tool.cache import Cache class BuiltinCode(eval.Code): "The code object implementing a built-in (interpreter-level) hook." @@ -358,10 +358,10 @@ # temporary/initialization purposes class app2interp_temp(app2interp): def getcache(self, space): - return self.__dict__.setdefault(space, {}) + return self.__dict__.setdefault(space, Cache()) # ^^^^^ # armin suggested this class interp2app_temp(interp2app): def getcache(self, space): - return self.__dict__.setdefault(space, {}) + return self.__dict__.setdefault(space, Cache()) Modified: pypy/trunk/src/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pycode.py (original) +++ pypy/trunk/src/pypy/interpreter/pycode.py Thu Nov 18 11:18:30 2004 @@ -6,6 +6,7 @@ import dis from pypy.interpreter import eval +from pypy.tool.cache import Cache # code object contants, for co_flags below CO_OPTIMIZED = 0x0001 @@ -130,7 +131,7 @@ code.co_cellvars = space.unwrap(w_cellvars) return space.wrap(code) -def enhanceclass(baseclass, newclass, cache={}): +def enhanceclass(baseclass, newclass, cache=Cache()): # this is a bit too dynamic for RPython, but it looks nice # and I assume that we can easily change it into a static # pre-computed table @@ -140,20 +141,8 @@ try: return cache[baseclass, newclass] except KeyError: + assert not cache.frozen class Mixed(newclass, baseclass): pass cache[baseclass, newclass] = Mixed return Mixed - -def keys(): - from pypy.interpreter.pyopcode import PyInterpFrame as Frame - from pypy.interpreter.nestedscope import PyNestedScopeFrame - from pypy.interpreter.generator import GeneratorFrame - - return [ - (Frame, PyNestedScopeFrame), - (Frame, GeneratorFrame), - (enhanceclass(Frame, PyNestedScopeFrame), GeneratorFrame), - ] - -enhanceclass.keys = keys Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Thu Nov 18 11:18:30 2004 @@ -342,7 +342,7 @@ w_globals = f.valuestack.pop() w_prog = f.valuestack.pop() w_resulttuple = f.prepare_exec(w_prog, w_globals, w_locals) - w_prog, w_globals, w_locals = f.space.unpacktuple(w_resulttuple) + w_prog, w_globals, w_locals = f.space.unpacktuple(w_resulttuple, 3) plain = f.space.is_true(f.space.is_(w_locals, f.w_locals)) if plain: Modified: pypy/trunk/src/pypy/interpreter/test/test_code.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_code.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_code.py Thu Nov 18 11:18:30 2004 @@ -92,15 +92,5 @@ exec co in d self.assertEquals(d['c'], 3) -class TestCodeEnhanceClass(testit.IntTestCase): - def test_enhanceclass_for_translator(self): - from pypy.interpreter.pycode import enhanceclass - assert hasattr(enhanceclass, 'keys') - arglist = enhanceclass.keys() - for args in arglist: - enhanceclass(*args) - - - if __name__ == '__main__': testit.main() Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Thu Nov 18 11:18:30 2004 @@ -43,15 +43,6 @@ # this function returns a real tuple that can be handled # by FlowObjSpace.unpacktuple() -def loadfromcache(space, args): - # XXX need some way to know how to fully initialize the cache - print space, args - assert len(args.args_w) == 2 and args.kwds_w == {} - w_key, w_builder = args.args_w - w_cache = Constant('space_cache') # temporary - return space.do_operation('getitem', w_cache, w_key) - - def import_(space, args): assert len(args.args_w) == 4 and args.kwds_w == {} unwrapped_args = [] @@ -63,6 +54,4 @@ def setup(space): fn = pyframe.normalize_exception.get_function(space) space.specialcases[fn] = normalize_exception - fn = baseobjspace.ObjSpace.loadfromcache.im_func - space.specialcases[fn] = loadfromcache space.specialcases[__import__] = import_ Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Thu Nov 18 11:18:30 2004 @@ -4,6 +4,7 @@ from pypy.objspace.std.stdtypedef import * from pypy.objspace.std.objspace import W_Object, StdObjSpace from pypy.objspace.std.default import UnwrapError +from pypy.tool.cache import Cache # this file automatically generates non-reimplementations of CPython # types that we do not yet implement in the standard object space @@ -11,7 +12,7 @@ import sys -_fake_type_cache = {} +_fake_type_cache = Cache() # real-to-wrapped exceptions def wrap_exception(space): @@ -35,6 +36,7 @@ assert type(cpy_type) is type if cpy_type in _fake_type_cache: return _fake_type_cache[cpy_type] + assert not _fake_type_cache.frozen print 'faking %r'%(cpy_type,) kw = {} for s, v in cpy_type.__dict__.items(): Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 11:18:30 2004 @@ -1,6 +1,5 @@ from pypy.interpreter.baseobjspace import OperationError -from pypy.tool.frozendict import frozendict - +from pypy.tool.cache import Cache class FailedToImplement(Exception): "Signals the dispatcher to try harder." @@ -43,7 +42,7 @@ self.arity = arity self.operatorsymbol = operatorsymbol self.dispatch_table = {} - self.cache_table = {} + self.cache_table = Cache() self.cache_delegator_key = None self.dispatch_arity = 0 @@ -76,7 +75,7 @@ try: return self.cache_table[argclasses] except KeyError: - assert not isinstance(self.cache_table, frozendict) + assert not self.cache_table.frozen calllist = [] self.internal_buildcalllist(argclasses, delegate, calllist) result = self.internal_compilecalllist(argclasses, calllist) Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Thu Nov 18 11:18:30 2004 @@ -2,6 +2,7 @@ from pypy.interpreter.baseobjspace import * from pypy.interpreter.typedef import get_unique_interplevel_subclass from pypy.interpreter.typedef import instantiate +from pypy.tool.cache import Cache from pypy.objspace.std.multimethod import * from pypy.objspace.descroperation import DescrOperation from pypy.objspace.std import stdtypedef @@ -135,8 +136,8 @@ return done def initialize(self): - self._typecache = {} - self._faketypecache = {} + self._typecache = Cache() + self._faketypecache = Cache() # The object implementations that we want to 'link' into PyPy must be # imported here. This registers them into the multimethod tables, Copied: pypy/trunk/src/pypy/tool/cache.py (from r7351, pypy/trunk/src/pypy/tool/frozendict.py) ============================================================================== --- pypy/trunk/src/pypy/tool/frozendict.py (original) +++ pypy/trunk/src/pypy/tool/cache.py Thu Nov 18 11:18:30 2004 @@ -1,16 +1,36 @@ +class basecache(dict): + pass + # hacks += 1 -class frozendict(dict): - _hash_cache = None - def __setitem__(self, *args): - raise TypeError, "this dict is already frozen, you are too late!" - __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ +class Cache(dict): + frozen = True + + def __init__(self, *args): + self.frozen = False + dict.__init__(self, *args) + for x in ('__setitem__', '__delitem__', 'setdefault', 'update', + 'pop', 'popitem', 'clear'): + l=["def %s(self, *args):", + " assert not self.frozen, 'cache already frozen'", + " return dict.%s(self, *args)"] + exec "\n".join(l) % (x,x) + def __hash__(self): - rval = self._hash_cache - if rval is None: - dct = self.items() - dct.sort() - rval = self._hash_cache = hash(tuple(dct)) ^ 0x18293742 - return rval + if not self.frozen: + raise TypeError, "cannot get hash of un-frozen cache" + return id(self) + + def getorbuild(self, key, builder, space): + try: + return self[key] + except KeyError: + assert not self.frozen, "cannot build %r, cache already frozen" % key + return self.setdefault(key, builder(key, space)) + # note to annotator: we want loadfromcache() to be + # specialized for the different cache types + getorbuild.specialize = True + def freeze(self): + del self.frozen Deleted: /pypy/trunk/src/pypy/tool/frozendict.py ============================================================================== --- /pypy/trunk/src/pypy/tool/frozendict.py Thu Nov 18 11:18:30 2004 +++ (empty file) @@ -1,16 +0,0 @@ - -# hacks += 1 -class frozendict(dict): - _hash_cache = None - def __setitem__(self, *args): - raise TypeError, "this dict is already frozen, you are too late!" - __delitem__ = setdefault = update = pop = popitem = clear = __setitem__ - - def __hash__(self): - rval = self._hash_cache - if rval is None: - dct = self.items() - dct.sort() - rval = self._hash_cache = hash(tuple(dct)) ^ 0x18293742 - return rval - Added: pypy/trunk/src/pypy/tool/test/test_cache.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/tool/test/test_cache.py Thu Nov 18 11:18:30 2004 @@ -0,0 +1,17 @@ +import autopath +import unittest +from pypy.tool.cache import Cache + +class TestCache(unittest.TestCase): + def test_getorbuild(self): + cache = Cache() + cache.getorbuild(1, lambda k,s: 42, None) + assert 1 in cache + assert cache[1] == 42 + assert cache.getorbuild(1, lambda k,s: 44, None) == 42 + self.assertRaises(TypeError, hash, cache) + cache.freeze() + hash(cache) + +if __name__ == '__main__': + unittest.main() From arigo at codespeak.net Thu Nov 18 11:28:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 11:28:34 +0100 (MET) Subject: [pypy-svn] r7361 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118102834.A349C5B0A1@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 11:28:34 2004 New Revision: 7361 Modified: pypy/trunk/src/pypy/objspace/std/dump_multimethod.py pypy/trunk/src/pypy/objspace/std/multimethod.py Log: Some more multimethod hackery. We need to figure out a better way to handle multimethods of high arity; str.replace() is of arity 4 and needs 40 minutes alone to have its cache fully populated :-((( Modified: pypy/trunk/src/pypy/objspace/std/dump_multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dump_multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/dump_multimethod.py Thu Nov 18 11:28:34 2004 @@ -35,11 +35,16 @@ result.append(getattr(module, clsname)) return result -def list_multimethods(): - result = [] - for name, value in StdObjSpace.MM.__dict__.iteritems(): +def list_multimethods(impls=[]): + collected = {} + for name, value in (StdObjSpace.MM.__dict__.items() + + StdObjSpace.__dict__.items()): if isinstance(value, MultiMethod): - result.append((name, value)) + collected[value] = name + for impl in impls: + for mm in impl.typedef.local_multimethods: + collected[mm] = '%s.%s' % (impl.typedef.name, mm.operatorsymbol) + result = [(name, value) for value, name in collected.iteritems()] result.sort() return result @@ -57,19 +62,25 @@ print 'dispatch arity is actually only %d.' % mm.dispatch_arity delegate = StdObjSpace.delegate versions = {} + sourcecache = {} for argclasses in cartesian_prod([impls] * mm.dispatch_arity): calllist = [] mm.internal_buildcalllist(argclasses, delegate, calllist) - src, glob = mm.internal_sourcecalllist(argclasses, calllist) - if 'FailedToImplement' in glob: - del glob['FailedToImplement'] - order = len(glob) - else: - order = 0.5 - glob = glob.items() - glob.sort() - glob = tuple(glob) - versions.setdefault((order, src, glob), []).append(argclasses) + calllist = tuple(calllist) + try: + key = sourcecache[calllist] + except KeyError: + src, glob = mm.internal_sourcecalllist(calllist) + if 'FailedToImplement' in glob: + del glob['FailedToImplement'] + order = len(glob) + else: + order = 0.5 + glob = glob.items() + glob.sort() + glob = tuple(glob) + key = sourcecache[calllist] = order, src, glob + versions.setdefault(key, []).append(argclasses) versions = versions.items() versions.sort() versions.reverse() @@ -130,7 +141,7 @@ impls = import_implementations() total = 0 restrict = sys.argv[1:] - for name, mm in list_multimethods(): + for name, mm in list_multimethods(impls): if (not restrict and name != 'delegate') or name in restrict: print print '==========', name, '==========' Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 11:28:34 2004 @@ -43,6 +43,7 @@ self.operatorsymbol = operatorsymbol self.dispatch_table = {} self.cache_table = Cache() + self.compilation_cache_table = {} self.cache_delegator_key = None self.dispatch_arity = 0 @@ -56,6 +57,7 @@ return False functions.append(function) self.cache_table.clear() + self.compilation_cache_table.clear() self.adjust_dispatch_arity(types) return True @@ -71,6 +73,7 @@ actual arguments.""" if delegate.key is not self.cache_delegator_key: self.cache_table.clear() + self.compilation_cache_table.clear() self.cache_delegator_key = delegate.key try: return self.cache_table[argclasses] @@ -78,40 +81,45 @@ assert not self.cache_table.frozen calllist = [] self.internal_buildcalllist(argclasses, delegate, calllist) - result = self.internal_compilecalllist(argclasses, calllist) + calllist = tuple(calllist) + try: + result = self.compilation_cache_table[calllist] + except KeyError: + result = self.internal_compilecalllist(calllist) + self.compilation_cache_table[calllist] = result self.cache_table[argclasses] = result return result - def internal_compilecalllist(self, argclasses, calllist): - source, glob = self.internal_sourcecalllist(argclasses, calllist) + def internal_compilecalllist(self, calllist): + source, glob = self.internal_sourcecalllist(calllist) # compile the function exec source in glob return glob['do'] - def internal_sourcecalllist(self, argclasses, calllist): + def internal_sourcecalllist(self, calllist): """Translate a call list into the source of a Python function which is optimized and doesn't do repeated conversions on the same arguments.""" if len(calllist) == 1: fn, conversions = calllist[0] - if conversions.count([]) == len(conversions): + if conversions == ((),) * len(conversions): # no conversion, just calling a single function: return # that function directly return '', {'do': fn} #print '**** compile **** ', self.operatorsymbol, [ # t.__name__ for t in argclasses] - arglist = ['a%d'%i for i in range(len(argclasses))] + ['*extraargs'] + arglist = ['a%d'%i for i in range(self.dispatch_arity)] + ['*extraargs'] source = ['def do(space,%s):' % ','.join(arglist)] - converted = [{(): ('a%d'%i, False)} for i in range(len(argclasses))] + converted = [{(): ('a%d'%i, False)} for i in range(self.dispatch_arity)] - def make_conversion(argi, convlist): - if tuple(convlist) in converted[argi]: - return converted[argi][tuple(convlist)] + def make_conversion(argi, convtuple): + if convtuple in converted[argi]: + return converted[argi][convtuple] else: - prev, can_fail = make_conversion(argi, convlist[:-1]) + prev, can_fail = make_conversion(argi, convtuple[:-1]) new = '%s_%d' % (prev, len(converted[argi])) - fname = all_functions.setdefault(convlist[-1], + fname = all_functions.setdefault(convtuple[-1], 'd%d' % len(all_functions)) if can_fail: source.append(' if isinstance(%s, FailedToImplement):' % prev) @@ -121,8 +129,8 @@ else: indent = ' ' source.append('%s%s = %s(space,%s)' % (indent, new, fname, prev)) - can_fail = can_fail or getattr(convlist[-1], 'can_fail', False) - converted[argi][tuple(convlist)] = new, can_fail + can_fail = can_fail or getattr(convtuple[-1], 'can_fail', False) + converted[argi][convtuple] = new, can_fail return new, can_fail all_functions = {} @@ -132,7 +140,7 @@ fname = all_functions.setdefault(fn, 'f%d' % len(all_functions)) arglist = [] failcheck = [] - for i in range(len(argclasses)): + for i in range(self.dispatch_arity): argname, can_fail = make_conversion(i, conversions[i]) arglist.append(argname) if can_fail: @@ -176,9 +184,9 @@ dispatchclasses = tuple([(c,) for c in argclasses]) choicelist = self.buildchoices(dispatchclasses) seen_functions = {} - no_conversion = [[]] * arity + no_conversion = [()] * arity for signature, function in choicelist: - calllist.append((function, no_conversion)) + calllist.append((function, tuple(no_conversion))) seen_functions[function] = 1 # proceed by expanding the last argument by delegation, step by step @@ -230,14 +238,14 @@ if function not in seen_functions: seen_functions[function] = 1 # collect arguments: arguments after position argi... - after_argi = [expanded_args[j][signature[j]] + after_argi = [tuple(expanded_args[j][signature[j]]) for j in range(argi+1-arity, 0)] # nb. j<0 # collect arguments: argument argi... - arg_argi = curargs[signature[argi]] + arg_argi = tuple(curargs[signature[argi]]) # collect all arguments newargs = no_conversion + [arg_argi] + after_argi # record the call - calllist.append((function, newargs)) + calllist.append((function, tuple(newargs))) # end of while 1: try on delegating the same argument i # proceed to the next argument From mwh at codespeak.net Thu Nov 18 11:51:21 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 11:51:21 +0100 (MET) Subject: [pypy-svn] r7362 - in pypy/trunk/src/pypy: annotation/test appspace appspace/test interpreter interpreter/test module/test objspace/flow/test objspace/std objspace/std/test objspace/test tool tool/test translator translator/test translator/tool translator/tool/pygame Message-ID: <20041118105121.370E75B0A0@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 11:51:20 2004 New Revision: 7362 Modified: pypy/trunk/src/pypy/annotation/test/autopath.py pypy/trunk/src/pypy/appspace/autopath.py pypy/trunk/src/pypy/appspace/test/autopath.py pypy/trunk/src/pypy/interpreter/autopath.py pypy/trunk/src/pypy/interpreter/test/autopath.py pypy/trunk/src/pypy/module/test/autopath.py pypy/trunk/src/pypy/objspace/flow/test/autopath.py pypy/trunk/src/pypy/objspace/std/autopath.py pypy/trunk/src/pypy/objspace/std/test/autopath.py pypy/trunk/src/pypy/objspace/test/autopath.py pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/tool/test/autopath.py pypy/trunk/src/pypy/translator/autopath.py pypy/trunk/src/pypy/translator/test/autopath.py pypy/trunk/src/pypy/translator/tool/autopath.py pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Log: There's indeed not much point in having autopath if it doesn't do what it's supposed to do! Remove directories up path from the pypy dir from sys.path (again). Modified: pypy/trunk/src/pypy/annotation/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/autopath.py (original) +++ pypy/trunk/src/pypy/annotation/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/appspace/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/appspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/interpreter/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/interpreter/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/module/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/module/test/autopath.py (original) +++ pypy/trunk/src/pypy/module/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/objspace/flow/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/objspace/std/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/objspace/std/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/objspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/autopath.py (original) +++ pypy/trunk/src/pypy/tool/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/tool/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/autopath.py (original) +++ pypy/trunk/src/pypy/tool/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/translator/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/autopath.py (original) +++ pypy/trunk/src/pypy/translator/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/translator/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/autopath.py (original) +++ pypy/trunk/src/pypy/translator/test/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/translator/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) Modified: pypy/trunk/src/pypy/translator/tool/pygame/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Thu Nov 18 11:51:20 2004 @@ -35,13 +35,14 @@ while head: partdir = head + try: + sys.path.remove(head) + except ValueError: + pass head, tail = os.path.split(head) if tail == part: - try: - sys.path.remove(head) - except ValueError: - pass - sys.path.insert(0, head) + if head not in sys.path: + sys.path.insert(0, head) return partdir, this_dir raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) From mwh at codespeak.net Thu Nov 18 12:06:47 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 12:06:47 +0100 (MET) Subject: [pypy-svn] r7363 - pypy/trunk/src/pypy/annotation Message-ID: <20041118110647.0A8AE5B0A2@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 12:06:47 2004 New Revision: 7363 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: Add support for type((const a)) -> (const (type(a))), and similar for isinstance. There should probably be some more general solution for this... Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 18 12:06:47 2004 @@ -37,7 +37,9 @@ # XXX simple case only if s_type.is_constant(): typ = s_type.const - if issubclass(s_obj.knowntype, typ): + if s_obj.is_constant(): + return immutablevalue(isinstance(s_obj.const, typ)) + elif issubclass(s_obj.knowntype, typ): return immutablevalue(True) else: # XXX HACK HACK HACK @@ -71,7 +73,8 @@ def builtin_type(s_obj, *moreargs): if moreargs: raise Exception, 'type() called with more than one argument' - #... + if s_obj.is_constant(): + return immutablevalue(type(s_obj.const)) return SomeObject() def builtin_str(s_obj): From arigo at codespeak.net Thu Nov 18 12:07:01 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 12:07:01 +0100 (MET) Subject: [pypy-svn] r7364 - in pypy/trunk/src/pypy: appspace appspace/test module/test Message-ID: <20041118110701.A61195B0AB@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 12:07:01 2004 New Revision: 7364 Added: pypy/trunk/src/pypy/appspace/test/no_test_stringmodule.py - copied unchanged from r7360, pypy/trunk/src/pypy/appspace/test/test_stringmodule.py pypy/trunk/src/pypy/module/test/applevel_in_cpython.py Removed: pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Modified: pypy/trunk/src/pypy/appspace/cmathmodule.py pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py pypy/trunk/src/pypy/appspace/test/test_complexobject.py Log: Fixed the tests in appspace; most of them didn't import. Directly testing the class 'complex' buried in __builtin__module.py is funny, beacuse it's difficult to import this __builtin__module.py directly into CPython. Well, it's not impossible, given sufficiently obscure hacks. Yadda yadda boum. Committing applevel_in_cpython.py for that purpose, i.e.: testing directly in CPython some of the app-level code written in the module/*module.py files. That's obviously a wrong solution. We need something more like splitting the module/*module.py into several files (e.g. class complex:...) and most of them could just be imported in CPython too. Modified: pypy/trunk/src/pypy/appspace/cmathmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/cmathmodule.py (original) +++ pypy/trunk/src/pypy/appspace/cmathmodule.py Thu Nov 18 12:07:01 2004 @@ -6,7 +6,6 @@ # much code borrowed from mathmodule.c import math -from complexobject import complex M_PI = 3.141592653589793239 Modified: pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_cmathmodule.py Thu Nov 18 12:07:01 2004 @@ -15,20 +15,22 @@ import unittest import autopath -#try: from pypy.tool import testit from pypy.appspace import cmathmodule -from pypy.appspace.complexobject import complex as pycomplex -#except ImportError: -# import cmathmodule -# from pypy.complexobject import complex as pycomplex +from pypy.appspace.test.test_complexobject import equal -from pypy.appspace.test.test_complexobject import equal, enumerate +def enumerate(): + valueRange = [-12.34, -3, -1, -0.5, 0, 0.5, 1, 3, 12.34] + res = [] + for x0 in valueRange: + for y0 in valueRange: + z = complex(x0,y0) + res.append(z) + return res -if 0: # DISABLED -- we know it works all right and don't want to see them - # take time any more for the time being - class TestCMathModule(testit.TestCase): + +class TestCMathModule(testit.TestCase): def assertAEqual(self, a, b): if not equal(a, b): @@ -37,35 +39,26 @@ def test_funcs(self): "Compare many functions with CPython." - for (z0c, z1c, z0p, z1p) in enumerate(): - mc = z0c*z1c - mp = z0p*z1p - self.assertAEqual(mc, mp) + for z in enumerate(): for op in "sqrt acos acosh asin asinh atan atanh cos cosh exp".split(): - if op == "atan" and equal(z0c, complex(0,-1)) or equal(z0c, complex(0,1)): + if op == "atan" and equal(z, complex(0,-1)) or equal(z, complex(0,1)): continue - if op == "atanh" and equal(z0c, complex(-1,0)) or equal(z0c, complex(1,0)): + if op == "atanh" and equal(z, complex(-1,0)) or equal(z, complex(1,0)): continue - op0 = cmath.__dict__[op](z0c) - op1 = cmathmodule.__dict__[op](z0p) + op0 = cmath.__dict__[op](z) + op1 = cmathmodule.__dict__[op](z) self.assertAEqual(op0, op1) - # check divisions - if equal(z0c, complex(0,0)) or equal(z1c, complex(0,0)): - continue - self.assertAEqual(mc/z0c, mp/z0p) - self.assertAEqual(mc/z1c, mp/z1p) - def test_log_log10(self): "Compare log/log10 functions with CPython." - for (z0c, z1c, z0p, z1p) in enumerate(): + for z in enumerate(): for op in "log log10".split(): - if z0p != 0: - op0 = cmath.__dict__[op](z0c) - op1 = cmathmodule.__dict__[op](z0p) + if z != 0: + op0 = cmath.__dict__[op](z) + op1 = cmathmodule.__dict__[op](z) self.assertAEqual(op0, op1) Modified: pypy/trunk/src/pypy/appspace/test/test_complexobject.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_complexobject.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_complexobject.py Thu Nov 18 12:07:01 2004 @@ -27,7 +27,10 @@ import unittest from pypy.tool import testit -from pypy.appspace.complexobject import complex as pycomplex +#from pypy.appspace.complexobject import complex as pycomplex +from pypy.module.test.applevel_in_cpython import applevel_in_cpython +our_own_builtin = applevel_in_cpython('__builtin__') +pycomplex = our_own_builtin.complex try: @@ -60,7 +63,7 @@ def enumerate(): - valueRange = xrange(-3, 3) + valueRange = [-3, -0.5, 0, 1] res = [] for x0 in valueRange: for y0 in valueRange: @@ -76,9 +79,7 @@ -if 0: # DISABLED -- we know it works all right and don't want to see them - # take time any more for the time being - class TestComplex(unittest.TestCase): +class TestComplex(unittest.TestCase): def assertAEqual(self, a, b): if not equal(a, b): Deleted: /pypy/trunk/src/pypy/appspace/test/test_stringmodule.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/test/test_stringmodule.py Thu Nov 18 12:07:01 2004 +++ (empty file) @@ -1,39 +0,0 @@ -#!/usr/bin/env python - - -""" -Test module for functions in stringmodule.py - -""" - -import string as c_py_string -import unittest - -import autopath -from pypy.tool import testit -from pypy.appspace import string as pypy_string - -class TestStringmodule(unittest.TestCase): - def regression(self, sFuncname, *args, **kwargs): - try: - c_py_res = getattr(c_py_string, sFuncname)(*args, **kwargs) - except Exception, ce: - c_py_res = ce.__class__ - - try: - pypy_res = getattr(pypy_string, sFuncname)(*args, **kwargs) - except Exception, pe: - pypy_res = pe.__class__ - - self.assertEqual(c_py_res, pypy_res, 'not equal \n1:<%s>\n2:<%s>' % (c_py_res, pypy_res)) - - - def test_maketrans(self): - self.regression('maketrans','','') - self.regression('maketrans','a','b') - self.regression('maketrans','aa','bb') - self.regression('maketrans','aa','') - - -if __name__ == "__main__": - testit.main() \ No newline at end of file Added: pypy/trunk/src/pypy/module/test/applevel_in_cpython.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/applevel_in_cpython.py Thu Nov 18 12:07:01 2004 @@ -0,0 +1,55 @@ +""" +Hack to (partially) import the app-level parts of PyPy modules +directly in CPython, when the goal is to test these app-level parts and +not necessarily PyPy's interpretation of them. +""" + +import autopath, new, sys + + +def applevel_in_cpython(modulename): + try: + real_mod = __import__(modulename) + except ImportError: + real_mod = None + + class DunnoType: + def __repr__(self): + return "" + Dunno = DunnoType() + + def ouack_eval(s): + return { + 'space.w_None': None, + 'space.w_False': False, + 'space.w_True': True, + 'space.w_type': type, + 'space.w_object': object, + 'space.wrap(unicode)': unicode, + 'space.wrap(file)': file, + }.get(s, Dunno) + + def ouack_execfile(s): + pass + + class OuackModule: + def __getattr__(self, name): + return getattr(real_mod, name, Dunno) + ouack_module = OuackModule() + ouack_module._issubtype = issubclass + + + from os.path import join + filename = join(autopath.pypydir, 'module', '%smodule.py' % modulename) + mod = new.module('applevel_in_cpython:%s' % modulename) + mod.__dict__.update({ + '__file__': filename, + '__interplevel__eval': ouack_eval, + '__interplevel__execfile': ouack_execfile, + }) + sys.modules['__interplevel__'] = ouack_module + try: + execfile(filename, mod.__dict__) + finally: + del sys.modules['__interplevel__'] + return mod From mwh at codespeak.net Thu Nov 18 12:40:12 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 12:40:12 +0100 (MET) Subject: [pypy-svn] r7365 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20041118114012.62D585B0A8@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 12:40:11 2004 New Revision: 7365 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Code to flow identity information into code like if x is None: # x is annotated as None in here else: # but not here. Tests for same. Also, tests for the similar isinstance hacks which somehow seem to have not been checked in yesterday (sorry about that). To make the flow_identity_info test work, I had to hack the constructor of SomeTuple somewhat. If this is the wrong thing to have done, the test can be written another way -- but this seems natural. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 18 12:40:11 2004 @@ -10,7 +10,7 @@ from pypy.annotation.model import SomeBuiltin, SomeIterator from pypy.annotation.model import SomePrebuiltConstant, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation -from pypy.annotation.factory import generalize, isclassdef +from pypy.annotation.factory import generalize, isclassdef, getbookkeeper from pypy.objspace.flow.model import Constant @@ -64,7 +64,36 @@ def ne((obj1, obj2)): return SomeBool() def gt((obj1, obj2)): return SomeBool() def ge((obj1, obj2)): return SomeBool() - def is_((obj1, obj2)): return SomeBool() + + def is_((obj1, obj2)): + const = None + vararg = None + if obj1.is_constant(): + const = obj1 + var = obj2 + vararg = 1 + if obj2.is_constant(): + const = obj2 + var = obj1 + vararg = 0 + if const is not None: + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + fn, block, i = getbookkeeper().position_key + annotator = getbookkeeper().annotator + op = block.operations[i] + assert op.opname == "is_" + assert len(op.args) == 2 + assert annotator.binding(op.args[vararg]) is var + assert op.args[1-vararg].value is const.const + r = SomeBool() + r.knowntypedata = (op.args[vararg], const) + return r + + return SomeBool() class __extend__(pairtype(SomeInteger, SomeInteger)): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 12:40:11 2004 @@ -103,6 +103,11 @@ knowntype = tuple def __init__(self, items): self.items = tuple(items) # tuple of s_xxx elements + for i in items: + if not i.is_constant(): + break + else: + self.const = tuple([i.const for i in items]) class SomeDict(SomeObject): "Stands for a dict with known keys." Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Thu Nov 18 12:40:11 2004 @@ -454,7 +454,25 @@ def global_badinit(): return global_bi.read() - + +def flow_type_info(i): + if isinstance(i, int): + a = i + 1 + else: + a = len(str(i)) + return a + +def flow_identity_info(x=object, y=object): + if x is None: + if None is y: + return (x, y) + else: + return (x, None) + else: + if y is None: + return (None, y) + else: + return (None, None) def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Thu Nov 18 12:40:11 2004 @@ -7,6 +7,8 @@ from pypy.translator.translator import Translator from pypy.objspace.flow.model import * +from pypy.annotation.model import immutablevalue + from pypy.translator.test import snippet class AnnonateTestCase(testit.IntTestCase): @@ -273,6 +275,21 @@ s = a.build_types(snippet.call_cpbc, []) self.assertEquals(s, annmodel.immutablevalue(42)) + def test_flow_type_info(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_type_info, [object]) + a.translator.simplify() + a.simplify() + #a.translator.view() + self.assertEquals(s.knowntype, int) + + def test_flow_identity_info(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_identity_info, [object, object]) + a.translator.simplify() + a.simplify() + #a.translator.view() + self.assertEquals(s, immutablevalue((None, None))) def g(n): return [0,1,2,n] From arigo at codespeak.net Thu Nov 18 12:46:19 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 12:46:19 +0100 (MET) Subject: [pypy-svn] r7366 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118114619.0E36A5B0AD@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 12:46:18 2004 New Revision: 7366 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Don't render empty strings, it crashes old pygame libs. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 12:46:18 2004 @@ -506,7 +506,7 @@ lines = [] while words: line = words.pop(0) - img = font.render(line, 1, fgcolor) + img = font.render(line or ' ', 1, fgcolor) while words: longerline = line + ' ' + words[0] longerimg = font.render(longerline, 1, fgcolor) From arigo at codespeak.net Thu Nov 18 12:47:02 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 12:47:02 +0100 (MET) Subject: [pypy-svn] r7367 - pypy/trunk/src/pypy/annotation Message-ID: <20041118114702.6D7445B0B1@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 12:47:01 2004 New Revision: 7367 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: Specialize functions taking a *arg by the number of arguments actually provided in a call. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Thu Nov 18 12:47:01 2004 @@ -7,11 +7,13 @@ """ from __future__ import generators +import new from types import FunctionType, ClassType, MethodType from pypy.annotation.model import SomeImpossibleValue, SomeList, SomeDict from pypy.annotation.model import SomeObject, SomeInstance from pypy.annotation.model import unionof, immutablevalue from pypy.interpreter.miscutils import getthreadlocals +from pypy.interpreter.pycode import CO_VARARGS class BlockedInference(Exception): @@ -39,6 +41,7 @@ self.userclasses = {} # map classes to ClassDefs self.userclasseslist = []# userclasses.keys() in creation order self.attrs_read_from_constants = {} + self.cachespecializedfunctions = {} def enter(self, position_key): """Start of an operation. @@ -159,19 +162,29 @@ args = [s_self] + list(args) func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func + # do we need to specialize this function in several versions? + if getattr(func, 'specialize', False): + # fully specialize: create one version per call position + func = self.specialize_by_key(func, self.position_key) + elif func.func_code.co_flags & CO_VARARGS: + # calls to *arg functions: create one version per number of args + func = self.specialize_by_key(func, len(args), + name='%s__%d' % (func.func_name, + len(args))) return self.bookkeeper.annotator.recursivecall(func, self, *args) - #if hasattr(func, 'specialize'): - # key = func, factory.position_key - # try: - # func = self._cachespecializedfunctions[key] - # except KeyError: - # func = new.function(func.func_code, - # func.func_globals, - # func.func_name, - # func.func_defaults, - # func.func_closure) - # self._cachespecializedfunctions[key] = func + def specialize_by_key(self, func, key, name=None): + key = func, key + try: + func = self.bookkeeper.cachespecializedfunctions[key] + except KeyError: + func = new.function(func.func_code, + func.func_globals, + name or func.func_name, + func.func_defaults, + func.func_closure) + self.bookkeeper.cachespecializedfunctions[key] = func + return func class ClassDef: "Wraps a user class." From mgedmin at codespeak.net Thu Nov 18 12:48:27 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 12:48:27 +0100 (MET) Subject: [pypy-svn] r7368 - pypy/trunk/src/pypy/annotation Message-ID: <20041118114827.A54415B0B3@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 12:48:27 2004 New Revision: 7368 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Fix the recent assertion to be less, well, stupid. (mwh) Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 18 12:48:27 2004 @@ -88,7 +88,7 @@ assert op.opname == "is_" assert len(op.args) == 2 assert annotator.binding(op.args[vararg]) is var - assert op.args[1-vararg].value is const.const + assert annotator.binding(op.args[1-vararg]).const is const.const r = SomeBool() r.knowntypedata = (op.args[vararg], const) return r From bob at codespeak.net Thu Nov 18 12:54:25 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Thu, 18 Nov 2004 12:54:25 +0100 (MET) Subject: [pypy-svn] r7369 - in pypy/trunk/src/pypy: annotation/test appspace appspace/test interpreter interpreter/test module/test objspace/flow/test objspace/std objspace/std/test objspace/test tool tool/test translator translator/test translator/tool translator/tool/pygame Message-ID: <20041118115425.E1EBF5B0B4@thoth.codespeak.net> Author: bob Date: Thu Nov 18 12:54:25 2004 New Revision: 7369 Modified: pypy/trunk/src/pypy/annotation/test/autopath.py pypy/trunk/src/pypy/appspace/autopath.py pypy/trunk/src/pypy/appspace/test/autopath.py pypy/trunk/src/pypy/interpreter/autopath.py pypy/trunk/src/pypy/interpreter/test/autopath.py pypy/trunk/src/pypy/module/test/autopath.py pypy/trunk/src/pypy/objspace/flow/test/autopath.py pypy/trunk/src/pypy/objspace/std/autopath.py pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/test/autopath.py pypy/trunk/src/pypy/objspace/test/autopath.py pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/tool/test/autopath.py pypy/trunk/src/pypy/translator/autopath.py pypy/trunk/src/pypy/translator/test/autopath.py pypy/trunk/src/pypy/translator/tool/autopath.py pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Log: smarter implementation of autopath Modified: pypy/trunk/src/pypy/annotation/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/autopath.py (original) +++ pypy/trunk/src/pypy/annotation/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/appspace/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/appspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/interpreter/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/interpreter/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/module/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/module/test/autopath.py (original) +++ pypy/trunk/src/pypy/module/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/objspace/flow/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/objspace/std/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 12:54:25 2004 @@ -33,6 +33,81 @@ # has been bound to a specific object space. It is obtained by # 'space.xxx' or explicitly by calling 'xxx.get(space)'. +class SourceCallList(object): + def __new__(cls, operatorsymbol, callist, dispatch_arity): + self = super(SourceCallList, cls).__new__() + if len(calllist) == 1: + fn, conversions = calllist[0] + if conversions == ((),) * len(conversions): + # no conversion, just calling a single function: return + # that function directly + return fn + + def do(space, *args): + args, extraargs = args[:dispatch_arity], args[dispatch_arity:] + if len(args) < dispatch_arity: + raise TypeError, 'MultiMethod %s has an arity of %d (%d given)' % (operatorsymbol, len(args)) + + converted = [{(): (i, False)} for i in range(dispatch_arity)] + all_functions = {} + + def make_conversion(dct, convtuple): + rval = dct.get(convtuple) + if rval is not None: + return rval + prev, can_fail = make_conversion(dct, convtuple[:-1]) + new = '%s_%d' % (prev, len(dct)) + fname = all_functions.setdefault(convtuple[-1], + 'd%d' % len(all_functions)) + if can_fail: + source.append(' if isinstance(%s, FailedToImplement):' % prev) + source.append(' %s = %s' % (new, prev)) + source.append(' else:') + indent = ' ' + else: + indent = ' ' + source.append('%s%s = %s(space,%s)' % (indent, new, fname, prev)) + can_fail = can_fail or getattr(convtuple[-1], 'can_fail', False) + dct[convtuple] = new, can_fail + return new, can_fail + + all_functions = {} + has_firstfailure = False + for fn, conversions in calllist: + # make the required conversions + fname = all_functions.setdefault(fn, 'f%d' % len(all_functions)) + arglist = [] + failcheck = [] + for i in range(dispatch_arity): + argname, can_fail = make_conversion(i, conversions[i]) + arglist.append(argname) + if can_fail: + failcheck.append(argname) + arglist.append('*extraargs') + source.append( ' try:') + for argname in failcheck: + source.append(' if isinstance(%s, FailedToImplement):' % argname) + source.append(' raise %s' % argname) + source.append( ' return %s(space,%s)' % ( + fname, ','.join(arglist))) + if has_firstfailure: + source.append(' except FailedToImplement:') + else: + source.append(' except FailedToImplement, firstfailure:') + has_firstfailure = True + source.append( ' pass') + + # complete exhaustion + if has_firstfailure: + source.append(' raise firstfailure') + else: + source.append(' raise FailedToImplement()') + source.append('') + + glob = {'FailedToImplement': FailedToImplement} + for fn, fname in all_functions.items(): + glob[fname] = fn + return '\n'.join(source), glob class AbstractMultiMethod(object): """Abstract base class for MultiMethod and UnboundMultiMethod @@ -92,6 +167,8 @@ def internal_compilecalllist(self, calllist): source, glob = self.internal_sourcecalllist(calllist) + print glob + print source # compile the function exec source in glob return glob['do'] Modified: pypy/trunk/src/pypy/objspace/std/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/objspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/autopath.py (original) +++ pypy/trunk/src/pypy/tool/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/tool/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/autopath.py (original) +++ pypy/trunk/src/pypy/tool/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/translator/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/autopath.py (original) +++ pypy/trunk/src/pypy/translator/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/translator/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/autopath.py (original) +++ pypy/trunk/src/pypy/translator/test/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/translator/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ Modified: pypy/trunk/src/pypy/translator/tool/pygame/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Thu Nov 18 12:54:25 2004 @@ -24,28 +24,32 @@ def __dirinfo(part): """ return (partdir, this_dir) and insert parent of partdir - into sys.path. If the parent directories dont have the part + into sys.path. If the parent directories don't have the part an EnvironmentError is raised.""" - import sys, os + import sys, os try: - head = this_dir = os.path.abspath(os.path.dirname(__file__)) + head = this_dir = os.path.realpath(os.path.dirname(__file__)) except NameError: - head = this_dir = os.path.abspath(os.path.dirname(sys.argv[0])) + head = this_dir = os.path.realpath(os.path.dirname(sys.argv[0])) while head: partdir = head - try: - sys.path.remove(head) - except ValueError: - pass head, tail = os.path.split(head) if tail == part: - if head not in sys.path: - sys.path.insert(0, head) - return partdir, this_dir - - raise EnvironmentError, "'%s' missing in '%r'" % (pathpart,this_path) + break + else: + raise EnvironmentError, "'%s' missing in '%r'" % (partdir, this_dir) + + checkpaths = sys.path[:] + pypy_root = os.path.join(head, '') + + while checkpaths: + orig = checkpaths.pop() + if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): + sys.path.remove(orig) + sys.path.insert(0, head) + return partdir, this_dir def __clone(): """ clone master version of autopath.py into all subdirs """ From arigo at codespeak.net Thu Nov 18 12:54:39 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 12:54:39 +0100 (MET) Subject: [pypy-svn] r7370 - pypy/trunk/src/pypy/annotation Message-ID: <20041118115439.85B9E5B0B5@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 12:54:39 2004 New Revision: 7370 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Return constant bools for comparisons between constant objects. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 18 12:54:39 2004 @@ -58,12 +58,41 @@ def inplace_sub((obj1, obj2)): return pair(obj1, obj2).sub() # default - def lt((obj1, obj2)): return SomeBool() - def le((obj1, obj2)): return SomeBool() - def eq((obj1, obj2)): return SomeBool() - def ne((obj1, obj2)): return SomeBool() - def gt((obj1, obj2)): return SomeBool() - def ge((obj1, obj2)): return SomeBool() + def lt((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const < obj2.const) + else: + return SomeBool() + + def le((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const <= obj2.const) + else: + return SomeBool() + + def eq((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const == obj2.const) + else: + return SomeBool() + + def ne((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const != obj2.const) + else: + return SomeBool() + + def gt((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const > obj2.const) + else: + return SomeBool() + + def ge((obj1, obj2)): + if obj1.is_constant() and obj2.is_constant(): + return immutablevalue(obj1.const >= obj2.const) + else: + return SomeBool() def is_((obj1, obj2)): const = None @@ -73,6 +102,8 @@ var = obj2 vararg = 1 if obj2.is_constant(): + if const is not None: + return immutablevalue(obj1.const is obj2.const) const = obj2 var = obj1 vararg = 0 From tismer at codespeak.net Thu Nov 18 13:06:08 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Thu, 18 Nov 2004 13:06:08 +0100 (MET) Subject: [pypy-svn] r7371 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041118120608.476F95B0B6@thoth.codespeak.net> Author: tismer Date: Thu Nov 18 13:06:07 2004 New Revision: 7371 Modified: pypy/trunk/src/pypy/objspace/flow/model.py Log: fixed typo in comment Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Thu Nov 18 13:06:07 2004 @@ -55,7 +55,7 @@ self.exits = [] # list of Link(s) def getvariables(self): - "Return all variables mentionned in this Block." + "Return all variables mentioned in this Block." result = self.inputargs[:] for op in self.operations: result += op.args From arigo at codespeak.net Thu Nov 18 13:17:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 13:17:45 +0100 (MET) Subject: [pypy-svn] r7372 - pypy/trunk/src/pypy/annotation Message-ID: <20041118121745.01B6E5B0B7@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 13:17:45 2004 New Revision: 7372 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: builtin_list() -> SomeList() Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 18 13:17:45 2004 @@ -80,6 +80,12 @@ def builtin_str(s_obj): return SomeString() +def builtin_list(s_iterable): + factory = getbookkeeper().getfactory(ListFactory) + s_iter = s_iterable.iter() + factory.generalize(s_iter.next()) + return factory.create() + # collect all functions import __builtin__ BUILTIN_FUNCTIONS = {} From arigo at codespeak.net Thu Nov 18 13:18:47 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 13:18:47 +0100 (MET) Subject: [pypy-svn] r7373 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041118121847.900495B0B8@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 13:18:47 2004 New Revision: 7373 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: More hacking of unpackiterable() to use len() and getitem() instead of iter() and next(). Helps with unpacking tuples of a length known (later) by the annotator. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Nov 18 13:18:47 2004 @@ -22,7 +22,8 @@ self.w_None = Constant(None) self.w_False = Constant(False) self.w_True = Constant(True) - for exc in [KeyError, ValueError, IndexError, StopIteration]: + for exc in [KeyError, ValueError, IndexError, StopIteration, + AssertionError]: clsname = exc.__name__ setattr(self, 'w_'+clsname, Constant(exc)) self.specialcases = {} @@ -143,17 +144,22 @@ if isinstance(w_iterable, Variable) and expected_length is None: # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK print ("*** cannot unpack a Variable iterable " - "without knowing its length, assuming up to 7 items") - w_iterator = self.iter(w_iterable) + "without knowing its length,") + print " assuming a list or tuple with up to 7 items" items = [] - for i in range(7): - try: - w_item = self.next(w_iterator) - except OperationError, e: - if not e.match(self, self.w_StopIteration): - raise + w_len = self.len(w_iterable) + i = 0 + while True: + w_i = self.wrap(i) + w_cond = self.eq(w_len, w_i) + if self.is_true(w_cond): break # done + if i == 7: + # too many values + raise OperationError(self.w_AssertionError, self.w_None) + w_item = self.do_operation('getitem', w_iterable, w_i) items.append(w_item) + i += 1 return items # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK return ObjSpace.unpackiterable(self, w_iterable, expected_length) From arigo at codespeak.net Thu Nov 18 14:59:57 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 14:59:57 +0100 (MET) Subject: [pypy-svn] r7374 - in pypy/trunk/src/pypy/objspace/flow: . test Message-ID: <20041118135957.3D9405B0BA@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 14:59:56 2004 New Revision: 7374 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/flow/specialcase.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Log: Special-casing operators in the flow object space. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Nov 18 14:59:56 2004 @@ -193,11 +193,12 @@ def call_args(self, w_callable, args): try: - sc = self.specialcases[self.unwrap(w_callable)] + fn = self.unwrap(w_callable) + sc = self.specialcases[fn] except (UnwrapException, KeyError): pass else: - return sc(self, args) + return sc(self, fn, args) if args.kwds_w: w_args, w_kwds = args.pack() Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Thu Nov 18 14:59:56 2004 @@ -1,4 +1,4 @@ -import types +import types, operator from pypy.interpreter import pyframe, baseobjspace from pypy.interpreter.error import OperationError from pypy.objspace.flow.objspace import UnwrapException @@ -16,7 +16,7 @@ return None -def normalize_exception(space, args): +def sc_normalize_exception(space, fn, args): """Special-case for 'raise' statements. Only accept the following syntaxes: @@ -43,7 +43,7 @@ # this function returns a real tuple that can be handled # by FlowObjSpace.unpacktuple() -def import_(space, args): +def sc_import(space, fn, args): assert len(args.args_w) == 4 and args.kwds_w == {} unwrapped_args = [] for w_arg in args.args_w: @@ -51,7 +51,15 @@ unwrapped_args.append(space.unwrap(w_arg)) return space.wrap(__import__(*unwrapped_args)) +def sc_operator(space, fn, args): + # XXX do this more cleanly + assert args.kwds_w == {} + opname = fn.__name__.replace('__', '') + return space.do_operation(opname, *args.args_w) + def setup(space): fn = pyframe.normalize_exception.get_function(space) - space.specialcases[fn] = normalize_exception - space.specialcases[__import__] = import_ + space.specialcases[fn] = sc_normalize_exception + space.specialcases[__import__] = sc_import + for opname in ['lt', 'le', 'eq', 'ne', 'gt', 'ge', 'is_']: + space.specialcases[getattr(operator, opname)] = sc_operator Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Thu Nov 18 14:59:56 2004 @@ -267,6 +267,33 @@ x = self.codetest(self.globalconstdict) self.show(x) + #__________________________________________________________ + def specialcases(): + import operator + operator.lt(2,3) + operator.le(2,3) + operator.eq(2,3) + operator.ne(2,3) + operator.gt(2,3) + operator.ge(2,3) + operator.is_(2,3) + operator.__lt__(2,3) + operator.__le__(2,3) + operator.__eq__(2,3) + operator.__ne__(2,3) + operator.__gt__(2,3) + operator.__ge__(2,3) + + def test_specialcases(self): + x = self.codetest(self.specialcases) + self.assertEquals(len(x.startblock.operations), 13) + for op in x.startblock.operations: + self.assert_(op.opname in ['lt', 'le', 'eq', 'ne', + 'gt', 'ge', 'is_']) + self.assertEquals(len(op.args), 2) + self.assertEquals(op.args[0].value, 2) + self.assertEquals(op.args[1].value, 3) + DATA = {'x': 5, 'y': 6} From hpk at codespeak.net Thu Nov 18 15:03:09 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 15:03:09 +0100 (MET) Subject: [pypy-svn] r7375 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20041118140309.505545B0BC@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 15:03:08 2004 New Revision: 7375 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Fix a thinko in union(SomeCallable, SomeCallable). Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 18 15:03:08 2004 @@ -280,7 +280,8 @@ raise Exception( "union failed for %r with classdefs %r and %r" % (cal, classdef, d[cal])) - classdef = classdef.commonbase(d[cal]) + if isclassdef(classdef): + classdef = classdef.commonbase(d[cal]) d[cal] = classdef return SomeCallable(d) Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Thu Nov 18 15:03:08 2004 @@ -539,3 +539,15 @@ x = H() return x.m(42) +def func1(): + pass + +def func2(): + pass + +def mergefunctions(cond): + if cond: + x = func1 + else: + x = func2 + return x Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Thu Nov 18 15:03:08 2004 @@ -7,7 +7,7 @@ from pypy.translator.translator import Translator from pypy.objspace.flow.model import * -from pypy.annotation.model import immutablevalue +from pypy.annotation.model import immutablevalue, SomeCallable from pypy.translator.test import snippet @@ -291,6 +291,13 @@ #a.translator.view() self.assertEquals(s, immutablevalue((None, None))) + def test_mergefunctions(self): + a = RPythonAnnotator() + s = a.build_types(snippet.mergefunctions, [int]) + # the test is mostly that the above line hasn't blown up + # but let's at least check *something* + self.assert_(isinstance(s, SomeCallable)) + def g(n): return [0,1,2,n] From bob at codespeak.net Thu Nov 18 15:05:21 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Thu, 18 Nov 2004 15:05:21 +0100 (MET) Subject: [pypy-svn] r7376 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118140521.695795B0BE@thoth.codespeak.net> Author: bob Date: Thu Nov 18 15:05:20 2004 New Revision: 7376 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py Log: revert Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Thu Nov 18 15:05:20 2004 @@ -33,82 +33,6 @@ # has been bound to a specific object space. It is obtained by # 'space.xxx' or explicitly by calling 'xxx.get(space)'. -class SourceCallList(object): - def __new__(cls, operatorsymbol, callist, dispatch_arity): - self = super(SourceCallList, cls).__new__() - if len(calllist) == 1: - fn, conversions = calllist[0] - if conversions == ((),) * len(conversions): - # no conversion, just calling a single function: return - # that function directly - return fn - - def do(space, *args): - args, extraargs = args[:dispatch_arity], args[dispatch_arity:] - if len(args) < dispatch_arity: - raise TypeError, 'MultiMethod %s has an arity of %d (%d given)' % (operatorsymbol, len(args)) - - converted = [{(): (i, False)} for i in range(dispatch_arity)] - all_functions = {} - - def make_conversion(dct, convtuple): - rval = dct.get(convtuple) - if rval is not None: - return rval - prev, can_fail = make_conversion(dct, convtuple[:-1]) - new = '%s_%d' % (prev, len(dct)) - fname = all_functions.setdefault(convtuple[-1], - 'd%d' % len(all_functions)) - if can_fail: - source.append(' if isinstance(%s, FailedToImplement):' % prev) - source.append(' %s = %s' % (new, prev)) - source.append(' else:') - indent = ' ' - else: - indent = ' ' - source.append('%s%s = %s(space,%s)' % (indent, new, fname, prev)) - can_fail = can_fail or getattr(convtuple[-1], 'can_fail', False) - dct[convtuple] = new, can_fail - return new, can_fail - - all_functions = {} - has_firstfailure = False - for fn, conversions in calllist: - # make the required conversions - fname = all_functions.setdefault(fn, 'f%d' % len(all_functions)) - arglist = [] - failcheck = [] - for i in range(dispatch_arity): - argname, can_fail = make_conversion(i, conversions[i]) - arglist.append(argname) - if can_fail: - failcheck.append(argname) - arglist.append('*extraargs') - source.append( ' try:') - for argname in failcheck: - source.append(' if isinstance(%s, FailedToImplement):' % argname) - source.append(' raise %s' % argname) - source.append( ' return %s(space,%s)' % ( - fname, ','.join(arglist))) - if has_firstfailure: - source.append(' except FailedToImplement:') - else: - source.append(' except FailedToImplement, firstfailure:') - has_firstfailure = True - source.append( ' pass') - - # complete exhaustion - if has_firstfailure: - source.append(' raise firstfailure') - else: - source.append(' raise FailedToImplement()') - source.append('') - - glob = {'FailedToImplement': FailedToImplement} - for fn, fname in all_functions.items(): - glob[fname] = fn - return '\n'.join(source), glob - class AbstractMultiMethod(object): """Abstract base class for MultiMethod and UnboundMultiMethod i.e. the classes that are not bound to a specific space instance.""" @@ -167,8 +91,6 @@ def internal_compilecalllist(self, calllist): source, glob = self.internal_sourcecalllist(calllist) - print glob - print source # compile the function exec source in glob return glob['do'] From mgedmin at codespeak.net Thu Nov 18 15:29:10 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 15:29:10 +0100 (MET) Subject: [pypy-svn] r7377 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118142910.9759C5B0BD@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 15:29:10 2004 New Revision: 7377 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Added a simple textual search facility to the pygame graph viewer. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Thu Nov 18 15:29:10 2004 @@ -426,6 +426,13 @@ for cmd in self.draw_commands(): cmd() + def search_for_node(self, searchstr): + """Find a node that contains a search string.""" + for node in self.graphlayout.nodes.itervalues(): + if searchstr in node.label: + return node + return None + def at_position(self, (x, y)): """Figure out the word under the cursor.""" for rx, ry, rw, rh, word in self.textzones: @@ -443,6 +450,7 @@ def edge_at_position(self, (x, y), distmax=14): """Return the Edge near the cursor.""" + # XXX this function is very CPU-intensive and makes the display kinda sluggish distmax /= self.scale xy = self.revmap(x, y) closest_edge = None Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 15:29:10 2004 @@ -65,6 +65,9 @@ HELP_ALPHA = 0.95 HELP_FGCOLOR = (255, 255, 80) HELP_BGCOLOR = (0, 128, 0) + INPUT_ALPHA = 0.75 + INPUT_FGCOLOR = (255, 255, 80) + INPUT_BGCOLOR = (0, 0, 128) KEYS = { 'meta -' : ('zoom', 0.5), @@ -77,6 +80,8 @@ 'meta left': 'layout_back', 'p' : 'layout_back', 'backspace' : 'layout_back', + 'f': 'search', + '/': 'search', 'left' : ('pan', (-1, 0)), 'right' : ('pan', (1, 0)), 'up' : ('pan', (0, -1)), @@ -104,6 +109,8 @@ Meta Left Go back in history Meta Right Go forward in history + F or / Search for text + H This help message Esc Quit @@ -168,16 +175,19 @@ self.key_cache[(key, mod)] = (method, args) def help(self): + """Show a help window and wait for a key or a mouse press.""" margin_x = margin_y = 64 + padding_x = padding_y = 8 fgcolor = self.HELP_FGCOLOR bgcolor = self.HELP_BGCOLOR helpmsg = self.HELP_MSG width = self.width - 2*margin_x height = self.height - 2*margin_y - lines = rendertext(helpmsg, self.font, fgcolor, width) + lines = rendertext(helpmsg, self.font, fgcolor, width - 2*padding_x) block = pygame.Surface((width, height), SWSURFACE | SRCALPHA) block.fill(bgcolor) - sx = sy = 8 + sx = padding_x + sy = padding_y for img in lines: w, h = img.get_size() block.blit(img, (sx, sy)) @@ -186,12 +196,71 @@ self.screen.blit(block, (margin_x, margin_y)) pygame.display.flip() - while 1: + while True: e = pygame.event.wait() if e.type in (MOUSEBUTTONDOWN, KEYDOWN, QUIT): break self.must_redraw = True + def input(self, prompt): + """Ask the user to input something. + + Returns the string that the user entered, or None if the user pressed + Esc. + """ + + def draw(text): + margin_x = margin_y = 0 + padding_x = padding_y = 8 + fgcolor = self.INPUT_FGCOLOR + bgcolor = self.INPUT_BGCOLOR + width = self.width - 2*margin_x + lines = renderline(text, self.font, fgcolor, width - 2*padding_x) + height = totalheight(lines) + 2 * padding_y + block = pygame.Surface((width, height), SWSURFACE | SRCALPHA) + block.fill(bgcolor) + sx = padding_x + sy = padding_y + for img in lines: + w, h = img.get_size() + block.blit(img, (sx, sy)) + sy += h + block.set_alpha(int(255 * self.INPUT_ALPHA)) + self.viewer.render() + if self.statusbarinfo: + self.drawstatusbar() + self.screen.blit(block, (margin_x, margin_y)) + pygame.display.flip() + + draw(prompt) + text = "" + self.must_redraw = True + while True: + e = pygame.event.wait() + if e.type == QUIT: + return None + elif e.type == KEYDOWN: + if e.key == K_ESCAPE: + return None + elif e.key == K_RETURN: + return text + elif e.key == K_BACKSPACE: + text = text[:-1] + draw(prompt + text) + elif e.unicode: + text += e.unicode + draw(prompt + text) + + def search(self): + searchstr = self.input('Find: ') + if not searchstr: + return + node = self.viewer.search_for_node(searchstr) + if node: + self.look_at_node(node) + else: + self.setstatusbar('Not found: %s' % searchstr) + def setlayout(self, layout): if self.viewer: self.viewers_history.append(self.viewer) @@ -271,10 +340,7 @@ def drawstatusbar(self): text, fgcolor, bgcolor = self.statusbarinfo lines = rendertext(text, self.font, fgcolor, self.width) - totalh = 0 - for img in lines: - w, h = img.get_size() - totalh += h + totalh = totalheight(lines) y = self.height - totalh self.status_bar_height = totalh + 16 block = pygame.Surface((self.width, self.status_bar_height), SWSURFACE | SRCALPHA) @@ -528,3 +594,12 @@ for line in text.splitlines(): lines.extend(renderline(line, font, fgcolor, width)) return lines + + +def totalheight(lines): + """Calculate the total height of a list of images.""" + totalh = 0 + for img in lines: + w, h = img.get_size() + totalh += h + return totalh From mwh at codespeak.net Thu Nov 18 15:36:02 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 15:36:02 +0100 (MET) Subject: [pypy-svn] r7378 - pypy/trunk/src/pypy/annotation Message-ID: <20041118143602.B874B5B0C3@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 15:36:02 2004 New Revision: 7378 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: yadda yadda builtin_issubclass yadda yadda builtin_hasattr yadda Pretty simplistic, improvements certainly possible. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 18 15:36:02 2004 @@ -59,12 +59,24 @@ return r return SomeBool() +def builtin_issubclass(s_cls1, s_cls2): + if s_cls1.is_constant() and s_cls2.is_constant(): + return immutablevalue(issubclass(s_cls1, s_cls2)) + else: + return SomeBool() + def builtin_getattr(s_obj, s_attr): if not s_attr.is_constant() or not isinstance(s_attr.const, str): raise Exception, 'getattr(%r, %r) is not RPythonic enough' % ( s_obj, s_attr) return s_obj.getattr(s_attr) +def builtin_hasattr(s_obj, s_attr): + if not s_attr.is_constant() or not isinstance(s_attr.const, str): + raise Exception, 'hasattr(%r, %r) is not RPythonic enough' % ( + s_obj, s_attr) + return SomeBool() + def builtin_tuple(s_iterable): if isinstance(s_iterable, SomeTuple): return s_iterable From mgedmin at codespeak.net Thu Nov 18 15:37:14 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 15:37:14 +0100 (MET) Subject: [pypy-svn] r7379 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118143714.E87265B0C5@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 15:37:14 2004 New Revision: 7379 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Highlight the node that is found. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 15:37:14 2004 @@ -257,7 +257,9 @@ return node = self.viewer.search_for_node(searchstr) if node: - self.look_at_node(node) + self.sethighlight(obj=node) + self.look_at_node(node, keep_highlight=True) + self.sethighlight(obj=node) else: self.setstatusbar('Not found: %s' % searchstr) @@ -310,9 +312,10 @@ info = 'Press H for help' self.setstatusbar(info) - def updated_viewer(self): + def updated_viewer(self, keep_highlight=False): self.reoffset() - self.sethighlight() + if not keep_highlight: + self.sethighlight() self.statusbarinfo = None self.must_redraw = True self.update_status_bar() @@ -432,7 +435,7 @@ cx2, cy2 = node.x, node.y return (cx2-cx1)*(cx2-cx1) + (cy2-cy1)*(cy2-cy1) - def look_at_node(self, node): + def look_at_node(self, node, keep_highlight=False): """Shift the node in view.""" endscale = min(float(self.width-40) / node.w, float(self.height-40) / node.h, @@ -452,12 +455,13 @@ else: bumpscale = 0.0 self.statusbarinfo = None - self.sethighlight() + if not keep_highlight: + self.sethighlight() for t in self.animation(): self.viewer.setscale(startscale*(1-t) + endscale*t + bumpscale*t*(1-t)) self.viewer.setcenter(cx1*(1-t) + cx2*t, cy1*(1-t) + cy2*t) - self.updated_viewer() + self.updated_viewer(keep_highlight=keep_highlight) self.viewer.render() pygame.display.flip() return moving From mgedmin at codespeak.net Thu Nov 18 15:42:36 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 15:42:36 +0100 (MET) Subject: [pypy-svn] r7380 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118144236.943715B0C9@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 15:42:36 2004 New Revision: 7380 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Added find next. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Thu Nov 18 15:42:36 2004 @@ -426,9 +426,15 @@ for cmd in self.draw_commands(): cmd() - def search_for_node(self, searchstr): + def search_for_node(self, searchstr, start_at=None): """Find a node that contains a search string.""" - for node in self.graphlayout.nodes.itervalues(): + iter = self.graphlayout.nodes.itervalues() + if start_at: + # Skip all nodes up to and including 'start_at' + for node in iter: + if node is start_at: + break + for node in iter: if searchstr in node.label: return node return None Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 15:42:36 2004 @@ -82,6 +82,7 @@ 'backspace' : 'layout_back', 'f': 'search', '/': 'search', + 'n': 'find_next', 'left' : ('pan', (-1, 0)), 'right' : ('pan', (1, 0)), 'up' : ('pan', (0, -1)), @@ -110,6 +111,7 @@ Meta Right Go forward in history F or / Search for text + N Find next occurrence H This help message @@ -135,6 +137,8 @@ self.method_cache = {} self.key_cache = {} self.status_bar_height = 0 + self.searchstr = None + self.searchpos = None self.initialize_keys() self.setlayout(layout) @@ -255,13 +259,22 @@ searchstr = self.input('Find: ') if not searchstr: return - node = self.viewer.search_for_node(searchstr) + self.searchstr = searchstr + self.searchpos = None + self.find_next() + + def find_next(self): + if not self.searchstr: + return + node = self.viewer.search_for_node(self.searchstr, + start_at=self.searchpos) if node: + self.searchpos = node self.sethighlight(obj=node) self.look_at_node(node, keep_highlight=True) self.sethighlight(obj=node) else: - self.setstatusbar('Not found: %s' % searchstr) + self.setstatusbar('Not found: %s' % self.searchstr) def setlayout(self, layout): if self.viewer: From arigo at codespeak.net Thu Nov 18 15:54:48 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 15:54:48 +0100 (MET) Subject: [pypy-svn] r7381 - pypy/trunk/src/pypy/annotation Message-ID: <20041118145448.8E7955B0CE@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 15:54:48 2004 New Revision: 7381 Modified: pypy/trunk/src/pypy/annotation/model.py Log: Support for constant lists and dicts. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 15:54:48 2004 @@ -202,14 +202,23 @@ def immutablevalue(x): "The most precise SomeValue instance that contains the immutable value x." - if isinstance(bool, type) and isinstance(x, bool): + tp = type(x) + if tp is bool: result = SomeBool() - elif isinstance(x, int): + elif tp is int: result = SomeInteger(nonneg = x>=0) - elif isinstance(x, str): + elif tp is str: result = SomeString() - elif isinstance(x, tuple): + elif tp is tuple: result = SomeTuple(items = [immutablevalue(e) for e in x]) + elif tp is list: + items_s = [immutablevalue(e) for e in x] + result = SomeList({}, unionof(*items_s)) + elif tp is dict: # exactly a dict, not a subclass like Cache + items = {} + for key, value in x.items(): + items[key] = immutablevalue(value) + result = SomeDict({}, items) elif ishashable(x) and x in BUILTIN_FUNCTIONS: result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) elif callable(x): From hpk at codespeak.net Thu Nov 18 16:00:58 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 16:00:58 +0100 (MET) Subject: [pypy-svn] r7382 - in pypy/trunk/src/pypy: annotation objspace/std Message-ID: <20041118150058.620595B0D1@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 16:00:57 2004 New Revision: 7382 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: - convert annotator/builtin's getattr/hasattr raising of RPython-Errors into printing warnings - added builtin_callable() (returning just SomeBool()) - it seems genc.py is started now! Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 18 16:00:57 2004 @@ -65,16 +65,20 @@ else: return SomeBool() -def builtin_getattr(s_obj, s_attr): +def builtin_getattr(s_obj, s_attr, s_default=None): if not s_attr.is_constant() or not isinstance(s_attr.const, str): - raise Exception, 'getattr(%r, %r) is not RPythonic enough' % ( - s_obj, s_attr) + print "UN-RPYTHONIC-WARNING", \ + 'getattr(%r, %r) is not RPythonic enough' % (s_obj, s_attr) + return SomeObject() return s_obj.getattr(s_attr) def builtin_hasattr(s_obj, s_attr): if not s_attr.is_constant() or not isinstance(s_attr.const, str): - raise Exception, 'hasattr(%r, %r) is not RPythonic enough' % ( - s_obj, s_attr) + print "UN-RPYTHONIC-WARNING", \ + 'hasattr(%r, %r) is not RPythonic enough' % (s_obj, s_attr) + return SomeBool() + +def builtin_callable(s_obj): return SomeBool() def builtin_tuple(s_iterable): Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Thu Nov 18 16:00:57 2004 @@ -254,7 +254,9 @@ # anything below this line is implicitly XXX'ed if isinstance(x, type(Exception)) and issubclass(x, Exception): if hasattr(self, 'w_' + x.__name__): - return getattr(self, 'w_' + x.__name__) + w_result = getattr(self, 'w_' + x.__name__) + assert isinstance(w_result, W_TypeObject) + return w_result if isinstance(x, type): ft = self.loadfromcache(x, fake_type, self._faketypecache) return self.gettypeobject(ft.typedef) From mgedmin at codespeak.net Thu Nov 18 16:02:35 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 16:02:35 +0100 (MET) Subject: [pypy-svn] r7383 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118150235.8F37B5B0F9@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 16:02:35 2004 New Revision: 7383 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: Minor nicety. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Thu Nov 18 16:02:35 2004 @@ -429,7 +429,7 @@ def search_for_node(self, searchstr, start_at=None): """Find a node that contains a search string.""" iter = self.graphlayout.nodes.itervalues() - if start_at: + if start_at is not None: # Skip all nodes up to and including 'start_at' for node in iter: if node is start_at: From hpk at codespeak.net Thu Nov 18 16:20:44 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 16:20:44 +0100 (MET) Subject: [pypy-svn] r7384 - pypy/trunk/src/pypy/translator Message-ID: <20041118152044.1B6EC5B0A6@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 16:20:43 2004 New Revision: 7384 Modified: pypy/trunk/src/pypy/translator/genc.py Log: added a few types changed a few errors to warnings ... (mwh) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Thu Nov 18 16:20:43 2004 @@ -123,7 +123,9 @@ def nameof_function(self, func): if self.translator.frozen: - assert func in self.translator.flowgraphs, func + if func not in self.translator.flowgraphs: + print "NOT GENERATING", func + return self.nameof(None) name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' @@ -239,13 +241,16 @@ tuple: 'PyTuple_Type', dict: 'PyDict_Type', str: 'PyString_Type', + float: 'PyFloat_Type', + type: 'PyType_Type', + complex:'PyComplex_Type', } def nameof_type(self, cls): if cls in self.typename_mapping: return '(PyObject*) &%s' % self.typename_mapping[cls] - assert hasattr(cls, '__weakref__'), ( - "built-in class %r not found in typename_mapping" % (cls,)) + assert cls.__module__ != '__builtin__', \ + "built-in class %r not found in typename_mapping" % (cls,) return self.nameof_classobj(cls) def nameof_tuple(self, tup): From mgedmin at codespeak.net Thu Nov 18 16:21:55 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 16:21:55 +0100 (MET) Subject: [pypy-svn] r7385 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118152155.4EED45B0A9@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 16:21:54 2004 New Revision: 7385 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Limit the height of the status bar to 1/2 of the total window height. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 16:21:54 2004 @@ -62,6 +62,7 @@ STATUSBAR_ALPHA = 0.75 STATUSBAR_FGCOLOR = (255, 255, 80) STATUSBAR_BGCOLOR = (128, 0, 0) + STATUSBAR_OVERFLOWCOLOR = (255, 0, 0) HELP_ALPHA = 0.95 HELP_FGCOLOR = (255, 255, 80) HELP_BGCOLOR = (0, 128, 0) @@ -187,7 +188,8 @@ helpmsg = self.HELP_MSG width = self.width - 2*margin_x height = self.height - 2*margin_y - lines = rendertext(helpmsg, self.font, fgcolor, width - 2*padding_x) + lines = rendertext(helpmsg, self.font, fgcolor, width - 2*padding_x, + height - 2*padding_y) block = pygame.Surface((width, height), SWSURFACE | SRCALPHA) block.fill(bgcolor) sx = padding_x @@ -355,7 +357,9 @@ def drawstatusbar(self): text, fgcolor, bgcolor = self.statusbarinfo - lines = rendertext(text, self.font, fgcolor, self.width) + maxheight = self.height / 2 + lines = rendertext(text, self.font, fgcolor, self.width, maxheight, + self.STATUSBAR_OVERFLOWCOLOR) totalh = totalheight(lines) y = self.height - totalh self.status_bar_height = totalh + 16 @@ -580,11 +584,14 @@ return label.replace('\\l', '').splitlines()[0] -def renderline(text, font, fgcolor, width): +def renderline(text, font, fgcolor, width, maxheight=sys.maxint, + overflowcolor=None): """Render a single line of text into a list of images. Performs word wrapping. """ + if overflowcolor is None: + overflowcolor = fgcolor words = text.split(' ') lines = [] while words: @@ -599,17 +606,31 @@ words.pop(0) line = longerline img = longerimg + w, h = img.get_size() + if h > maxheight: + img = font.render('...', 1, overflowcolor) + w, h = img.get_size() + while lines and h > maxheight: + maxheight += lines.pop().get_size()[1] + lines.append(img) + break + maxheight -= h lines.append(img) return lines -def rendertext(text, font, fgcolor, width): +def rendertext(text, font, fgcolor, width, maxheight=sys.maxint, + overflowcolor=None): """Render a multiline string into a list of images. Performs word wrapping for each line individually.""" lines = [] for line in text.splitlines(): - lines.extend(renderline(line, font, fgcolor, width)) + l = renderline(line, font, fgcolor, width, maxheight, overflowcolor) + lines.extend(l) + maxheight -= totalheight(l) + if maxheight <= 0: + break return lines From mgedmin at codespeak.net Thu Nov 18 16:31:09 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 16:31:09 +0100 (MET) Subject: [pypy-svn] r7386 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118153109.DFC635B0BB@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 16:31:09 2004 New Revision: 7386 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Show the label of the highlighted node in the status bar. It is useful when the graph is very big and node labels do not fit. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 16:31:09 2004 @@ -382,6 +382,7 @@ return node = self.viewer.node_at_position(pos) if node: + self.setstatusbar(shortlabel(node.label)) self.sethighlight(obj=node) return edge = self.viewer.edge_at_position(pos) From arigo at codespeak.net Thu Nov 18 16:31:42 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 16:31:42 +0100 (MET) Subject: [pypy-svn] r7387 - in pypy/trunk/src/pypy: annotation translator/tool/pygame Message-ID: <20041118153142.50D745B0EA@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 16:31:41 2004 New Revision: 7387 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Debugging: for SomeObjects created by unionof(), remember the objects that this one is the union of. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 16:31:41 2004 @@ -62,11 +62,17 @@ except AttributeError: pass else: - SomeObject._coming_from[id(self)] = position_key + SomeObject._coming_from[id(self)] = position_key, None return self def origin(self): - return SomeObject._coming_from.get(id(self), None) + return SomeObject._coming_from.get(id(self), (None, None))[0] origin = property(origin) + def caused_by_merge(self): + return SomeObject._coming_from.get(id(self), (None, None))[1] + def set_caused_by_merge(self, nvalue): + SomeObject._coming_from[id(self)] = self.origin, nvalue + caused_by_merge = property(caused_by_merge, set_caused_by_merge) + del set_caused_by_merge class SomeInteger(SomeObject): @@ -190,6 +196,8 @@ for s2 in somevalues: if s1 != s2: s1 = pair(s1, s2).union() + if s1.caused_by_merge is None and len(somevalues) > 1: + s1.caused_by_merge = somevalues return s1 def ishashable(x): Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Thu Nov 18 16:31:41 2004 @@ -30,6 +30,10 @@ label += "\\n" + self.createlink(info.origin, 'Originated at') if caused_by is not None: label += '\\n' + self.createlink(caused_by.position_key) + if info.caused_by_merge is not None: + data = 'unionof%r' % (info.caused_by_merge,) + label += '\\n%s' % nottoowide(data) + dotgen.emit_node('0', shape="box", color="red", label=label) for n, (data, caused_by) in zip(range(len(history)), history): label = nottoowide(data) From hpk at codespeak.net Thu Nov 18 17:29:44 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 17:29:44 +0100 (MET) Subject: [pypy-svn] r7388 - in pypy/trunk/src/pypy: annotation objspace/std Message-ID: <20041118162944.964BA5B09A@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 17:29:44 2004 New Revision: 7388 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: specialize objspace.wrap by argument types (gets rid of lots of SomeObjects()) IOW, you can use "function.specialize = 'argtypes'" to cause the annotator to specialize for argument types Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Thu Nov 18 17:29:44 2004 @@ -163,9 +163,16 @@ func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? - if getattr(func, 'specialize', False): - # fully specialize: create one version per call position - func = self.specialize_by_key(func, self.position_key) + x = getattr(func, 'specialize', False) + if x: + if x == 'argtypes': + key = "_".join([arg.__class__.__name__ for arg in args]) + name = func.__name__+'_'+key + func = self.specialize_by_key(func, key, name) + else: + # fully specialize: create one version per call position + func = self.specialize_by_key(func, self.position_key) + elif func.func_code.co_flags & CO_VARARGS: # calls to *arg functions: create one version per number of args func = self.specialize_by_key(func, len(args), Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Thu Nov 18 17:29:44 2004 @@ -262,6 +262,7 @@ return self.gettypeobject(ft.typedef) ft = self.loadfromcache(type(x), fake_type, self._faketypecache) return ft(self, x) + wrap.specialize = "argtypes" def newint(self, intval): return W_IntObject(self, intval) From mwh at codespeak.net Thu Nov 18 17:34:07 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 17:34:07 +0100 (MET) Subject: [pypy-svn] r7389 - pypy/trunk/src/pypy/translator Message-ID: <20041118163407.2F8D45B09D@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 17:34:06 2004 New Revision: 7389 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Assorted large and small hacks to allow compilation to finish. Doesn't work, of course, but hey, it's a start. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Thu Nov 18 17:34:06 2004 @@ -10,6 +10,8 @@ from pypy.translator.simplify import remove_direct_loops from types import FunctionType +from pypy.objspace.std.restricted_int import r_int, r_uint + # ____________________________________________________________ def uniquemodulename(name, SEEN={}): @@ -197,11 +199,15 @@ return name def nameof_classobj(self, cls): - if issubclass(cls, Exception) and cls.__module__ == 'exceptions': - return 'PyExc_%s'%cls.__name__ + if issubclass(cls, Exception): + if cls.__module__ == 'exceptions': + return 'PyExc_%s'%cls.__name__ + else: + assert cls.__name__ == "OperationError" + return 'PyExc_%s'%cls.__name__ + name = self.uniquename('gcls_' + cls.__name__) - bases = [base for base in cls.__bases__ if base is not object] - basenames = [self.nameof(base) for base in bases] + basenames = [self.nameof(base) for base in cls.__bases__] def initclassobj(): content = cls.__dict__.items() content.sort() @@ -213,6 +219,7 @@ # XXX some __NAMES__ are important... nicer solution sought #raise Exception, "unexpected name %r in class %s"%(key, cls) if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: + print value continue yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( @@ -225,7 +232,7 @@ self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) &PyType_Type,' %(name,)) self.initcode.append('\t\t"s(%s){}", "%s"%s))' - %("O"*len(bases), cls.__name__, baseargs)) + %("O"*len(basenames), cls.__name__, baseargs)) self.latercode.append(initclassobj()) return name @@ -244,6 +251,8 @@ float: 'PyFloat_Type', type: 'PyType_Type', complex:'PyComplex_Type', + r_int: 'PyInt_Type', + r_uint: 'PyInt_Type', } def nameof_type(self, cls): From mwh at codespeak.net Thu Nov 18 17:39:04 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 17:39:04 +0100 (MET) Subject: [pypy-svn] r7390 - pypy/trunk/src/pypy/translator Message-ID: <20041118163904.5B91C5B0AC@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 17:39:03 2004 New Revision: 7390 Modified: pypy/trunk/src/pypy/translator/genc.h Log: Oops, meant to check this in last time! Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Thu Nov 18 17:39:03 2004 @@ -72,6 +72,12 @@ #define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) goto err; #define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) goto err; \ r=Py_None; Py_INCREF(r); +#define OP_CONTAINS(x,y,r,err) switch (PySequence_Contains(x,y)) { \ + case 1: \ + Py_INCREF(Py_True); r = Py_True; break; \ + case 0: \ + Py_INCREF(Py_False); r = Py_False; break; \ + default: goto err; } #define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; #define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) goto err; \ @@ -169,7 +175,8 @@ #define SETUP_MODULE \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ - PyType_Ready(&PyGenCFunction_Type); + PyType_Ready(&PyGenCFunction_Type); \ + PyExc_OperationError = PyErr_NewException("bah.OperationError", NULL, NULL); /*** operations with a variable number of arguments ***/ @@ -287,6 +294,7 @@ } #endif +static PyObject* PyExc_OperationError; /************************************************************/ /*** The rest is produced by genc.py ***/ From mgedmin at codespeak.net Thu Nov 18 17:39:05 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 17:39:05 +0100 (MET) Subject: [pypy-svn] r7391 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118163905.AD05E5B0AC@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 17:39:05 2004 New Revision: 7391 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Speed up text entry somewhat. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Thu Nov 18 17:39:05 2004 @@ -232,6 +232,8 @@ block.blit(img, (sx, sy)) sy += h block.set_alpha(int(255 * self.INPUT_ALPHA)) + # This can be slow. It would be better to take a screenshot + # and use it as the background. self.viewer.render() if self.statusbarinfo: self.drawstatusbar() @@ -242,20 +244,23 @@ text = "" self.must_redraw = True while True: - e = pygame.event.wait() - if e.type == QUIT: - return None - elif e.type == KEYDOWN: - if e.key == K_ESCAPE: + events = [pygame.event.wait()] + events.extend(pygame.event.get()) + old_text = text + for e in events: + if e.type == QUIT: return None - elif e.key == K_RETURN: - return text - elif e.key == K_BACKSPACE: - text = text[:-1] - draw(prompt + text) - elif e.unicode: - text += e.unicode - draw(prompt + text) + elif e.type == KEYDOWN: + if e.key == K_ESCAPE: + return None + elif e.key == K_RETURN: + return text + elif e.key == K_BACKSPACE: + text = text[:-1] + elif e.unicode and ord(e.unicode) >= ord(' '): + text += e.unicode + if text != old_text: + draw(prompt + text) def search(self): searchstr = self.input('Find: ') From arigo at codespeak.net Thu Nov 18 17:47:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 17:47:58 +0100 (MET) Subject: [pypy-svn] r7392 - pypy/trunk/src/pypy/annotation Message-ID: <20041118164758.7C94E5B0B0@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 17:47:58 2004 New Revision: 7392 Modified: pypy/trunk/src/pypy/annotation/unaryop.py Log: - print a warning for simple_call(SomeObject()) - support for list.reverse() Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu Nov 18 17:47:58 2004 @@ -54,6 +54,11 @@ def bindcallables(obj, classdef): return obj # default unbound __get__ implementation + def simple_call(*obj_and_args): + #raise Exception, "cannot follow simple_call%r" % (obj_and_args,) + print "*** cannot follow simple_call%r" % (obj_and_args,) + return SomeObject() + class __extend__(SomeBool): def is_true(self): @@ -76,6 +81,9 @@ def method_append(lst, s_item): pair(lst, SomeInteger()).setitem(s_item) + def method_reverse(lst): + pass + def iter(lst): return SomeIterator(lst.s_item) From hpk at codespeak.net Thu Nov 18 18:00:07 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 18:00:07 +0100 (MET) Subject: [pypy-svn] r7393 - pypy/trunk/src/pypy/annotation Message-ID: <20041118170007.8561B5B0B2@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 18:00:07 2004 New Revision: 7393 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: allow the analysis of "SomeXXX is None" to return immutablevalue(False) if SomeXXX is not of class SomeObject (all other classes should not be None) Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 18 18:00:07 2004 @@ -104,6 +104,9 @@ if obj2.is_constant(): if const is not None: return immutablevalue(obj1.const is obj2.const) + # we are in the case "SomeXXX is None" here + if obj2.const is None and obj1.__class__ != SomeObject: + return immutablevalue(False) const = obj2 var = obj1 vararg = 0 From arigo at codespeak.net Thu Nov 18 18:01:59 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 18:01:59 +0100 (MET) Subject: [pypy-svn] r7394 - pypy/trunk/src/pypy/translator Message-ID: <20041118170159.42F245B0FC@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 18:01:58 2004 New Revision: 7394 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/transform.py Log: Fix for removing dead code. Actually we need to remove dead links, and not just links going to dead blocks, because the blocks in question could be reachable from somewhere else too. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Thu Nov 18 18:01:58 2004 @@ -23,6 +23,7 @@ self.pendingblocks = [] # list of (fn, block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen + self.links_followed = {} # set of links that have ever been followed self.why_not_annotated = {} # {block: (exc_type, exc_value, traceback)} # records the location of BlockedInference # exceptions that blocked some blocks. @@ -317,6 +318,7 @@ knownvar, knownvarvalue = getattr(self.bindings.get(block.exitswitch), "knowntypedata", (None, None)) for link in exits: + self.links_followed[link] = True cells = [] for a in link.args: if link.exitcase is True and a is knownvar \ Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Thu Nov 18 18:01:58 2004 @@ -306,7 +306,7 @@ them.""" for block in self.annotated: for link in block.exits: - if link.target not in self.annotated: + if link not in self.links_followed: lst = list(block.exits) lst.remove(link) block.exits = tuple(lst) From mwh at codespeak.net Thu Nov 18 18:06:19 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 18:06:19 +0100 (MET) Subject: [pypy-svn] r7395 - pypy/trunk/src/pypy/annotation Message-ID: <20041118170619.117005B101@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 18:06:19 2004 New Revision: 7395 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: hack to notice specialized functions. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Thu Nov 18 18:06:19 2004 @@ -185,6 +185,8 @@ try: func = self.bookkeeper.cachespecializedfunctions[key] except KeyError: + # XXX XXX XXX HAAAAAAAAAAAACK + self.bookkeeper.annotator.translator.getflowgraph(func) func = new.function(func.func_code, func.func_globals, name or func.func_name, From mwh at codespeak.net Thu Nov 18 18:30:57 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 18:30:57 +0100 (MET) Subject: [pypy-svn] r7396 - pypy/trunk/src/goal Message-ID: <20041118173057.D58025B103@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 18:30:57 2004 New Revision: 7396 Modified: pypy/trunk/src/goal/translate_pypy.py Log: now that the entry_point compiles and imports (some of the time, anyway) we should try to run it, too! Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Thu Nov 18 18:30:57 2004 @@ -87,6 +87,8 @@ print '-'*60 print 'Generating C code...' t.ccompile() + ep = sys.modules['entry_point_1'] + ep.entry_point() except: debug() else: From mwh at codespeak.net Thu Nov 18 18:31:48 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 18:31:48 +0100 (MET) Subject: [pypy-svn] r7397 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20041118173148.AB1125B104@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 18:31:48 2004 New Revision: 7397 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/genc.py Log: Some nasty and probably wrong hacks around the area we call 'staticmethods' Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu Nov 18 18:31:48 2004 @@ -148,7 +148,7 @@ def __init__(self, callables): # callables is a dictionary containing concrete python # callable objects as keys and - in the case of a method - - # the value contains the classdef (see SomeMethod above) + # the value contains the classdef (see SomeMethod below) self.callables = callables if len(callables) == 1: self.const, = callables @@ -229,7 +229,7 @@ result = SomeDict({}, items) elif ishashable(x) and x in BUILTIN_FUNCTIONS: result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) - elif callable(x): + elif callable(x) or isinstance(x, staticmethod): # XXX if hasattr(x, '__self__') and x.__self__ is not None: s_self = immutablevalue(x.__self__) del s_self.const # stop infinite recursion getattr<->immutablevalue Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu Nov 18 18:31:48 2004 @@ -179,6 +179,8 @@ print ("!!! rebinding an already bound" " method %r with %r" % (func, value)) d[func] = classdef + elif isinstance(func, staticmethod): + d[func.__get__(43)] = value else: d[func] = value return SomeCallable(d) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Thu Nov 18 18:31:48 2004 @@ -218,6 +218,9 @@ continue # XXX some __NAMES__ are important... nicer solution sought #raise Exception, "unexpected name %r in class %s"%(key, cls) + if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen: + print value + continue if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: print value continue From mgedmin at codespeak.net Thu Nov 18 18:50:49 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 18:50:49 +0100 (MET) Subject: [pypy-svn] r7398 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041118175049.B83C05B106@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 18:50:49 2004 New Revision: 7398 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: Use the name of the function (rather than the name of the code block) to name flow graphs. This makes a difference when functions are specialized. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Thu Nov 18 18:50:49 2004 @@ -120,7 +120,7 @@ constargs, closure) self.setup_executioncontext(ec) ec.build_flow() - name = ec.graph.name + name = func.func_name for c in "<>&!": name = name.replace(c, '_') ec.graph.name = name From hpk at codespeak.net Thu Nov 18 18:53:08 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 18:53:08 +0100 (MET) Subject: [pypy-svn] r7399 - pypy/trunk/src/pypy/annotation Message-ID: <20041118175308.352AB5B10C@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 18:53:07 2004 New Revision: 7399 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: if two SomeXXX's knowntype is reasonably disjunct from a constant type then isinstance(SomeXXXinstance, const_type) will analyse as immutable(False) -> yet some more branches cut out ... Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Thu Nov 18 18:53:07 2004 @@ -41,6 +41,8 @@ return immutablevalue(isinstance(s_obj.const, typ)) elif issubclass(s_obj.knowntype, typ): return immutablevalue(True) + elif not issubclass(typ, s_obj.knowntype): + return immutablevalue(False) else: # XXX HACK HACK HACK # XXX HACK HACK HACK From mwh at codespeak.net Thu Nov 18 18:56:38 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 18:56:38 +0100 (MET) Subject: [pypy-svn] r7400 - pypy/trunk/src/pypy/translator Message-ID: <20041118175638.551EE5B10D@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 18:56:37 2004 New Revision: 7400 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: this was never right\!? Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Thu Nov 18 18:56:37 2004 @@ -100,8 +100,7 @@ yield v def getpbcattrs(self, pbc): - c = Constant(pbc) - return self.bookkeeper.attrs_read_from_constants.get(c, {}) + return self.bookkeeper.attrs_read_from_constants.get(pbc, {}) #___ medium-level interface ____________________________ From mgedmin at codespeak.net Thu Nov 18 18:58:49 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 18:58:49 +0100 (MET) Subject: [pypy-svn] r7401 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041118175849.73A265B10E@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 18:58:48 2004 New Revision: 7401 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Make function flow graph name the function properly (instead of always appending '2' to the name). Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Thu Nov 18 18:58:48 2004 @@ -79,7 +79,7 @@ functions = functions or translator.functions graphs = [translator.getflowgraph(func) for func in functions] gs = [(graph.name, graph) for graph in graphs] - fn = make_dot_graphs(graphs[0].name, gs, target='plain') + fn = make_dot_graphs(graphs[0].name + "_graph", gs, target='plain') GraphLayout.__init__(self, fn) # make the dictionary of links -- one per annotated variable self.binding_history = {} From arigo at codespeak.net Thu Nov 18 18:59:24 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 18:59:24 +0100 (MET) Subject: [pypy-svn] r7402 - pypy/trunk/src/goal Message-ID: <20041118175924.073D35B14C@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 18:59:23 2004 New Revision: 7402 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Command-line options for translate_pypy: -text Don't start the Pygame viewer -no-c Don't generate the C code -c Generate the C code, but don't compile it -o Generate and compile the C code, but don't run it Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Thu Nov 18 18:59:23 2004 @@ -1,7 +1,7 @@ # # # -import autopath, sys +import autopath, sys, threading, pdb from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.objspace.std.intobject import W_IntObject from pypy.translator.translator import Translator @@ -31,6 +31,15 @@ if __name__ == '__main__': + options = {'-text': False, + '-no-c': False, + '-c': False, + '-o': False, + } + for arg in sys.argv[1:]: + assert arg in options, "unknown option %r" % (arg,) + options[arg] = True + def about(x): """ interactive debugging helper """ from pypy.objspace.flow.model import Block, flatten @@ -59,37 +68,52 @@ display = GraphDisplay(TranslatorLayout(t)) display.run() - def debug(): - import traceback - exc, val, tb = sys.exc_info() - print >> sys.stderr - traceback.print_exception(exc, val, tb) - print >> sys.stderr - - block = getattr(val, '__annotator_block', None) - if block: - print '-'*60 - about(block) + def debug(got_error): + if got_error: + import traceback + exc, val, tb = sys.exc_info() + print >> sys.stderr + traceback.print_exception(exc, val, tb) + print >> sys.stderr + + block = getattr(val, '__annotator_block', None) + if block: + print '-'*60 + about(block) + print '-'*60 + + print >> sys.stderr + th = threading.Thread(target=pdb.post_mortem, args=(tb,)) + else: print '-'*60 - - print >> sys.stderr - import threading - import pdb - t = threading.Thread(target=pdb.post_mortem, args=(tb,)) - t.start() - run_server() - import pygame - pygame.quit() + print 'Done.' + print + th = threading.Thread(target=pdb.set_trace, args=()) + th.start() + if options['-text']: + th.join() + else: + run_server() + import pygame + pygame.quit() try: analyse() t.frozen = True print '-'*60 - print 'Generating C code...' - t.ccompile() - ep = sys.modules['entry_point_1'] - ep.entry_point() + if options['-no-c']: + print 'Not generating C code.' + elif options['-c']: + print 'Generating C code without compiling it...' + filename = t.ccompile(really_compile=False) + print 'Written %s.' % (filename,) + else: + print 'Generating and compiling C code...' + c_entry_point = t.ccompile() + if not options['-o']: + print 'Running!' + c_entry_point() except: - debug() + debug(True) else: - run_server() + debug(False) From arigo at codespeak.net Thu Nov 18 19:04:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 18 Nov 2004 19:04:18 +0100 (MET) Subject: [pypy-svn] r7403 - pypy/trunk/src/pypy/translator Message-ID: <20041118180418.60E395B110@thoth.codespeak.net> Author: arigo Date: Thu Nov 18 19:04:08 2004 New Revision: 7403 Modified: pypy/trunk/src/pypy/translator/translator.py Log: Forgot to check this in. Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Thu Nov 18 19:04:08 2004 @@ -221,7 +221,7 @@ mod = make_module_from_pyxstring(name, udir, pyxcode) return getattr(mod, name) - def ccompile(self): + def ccompile(self, really_compile=True): """Returns compiled function, compiled using the C generator. """ from pypy.tool.udir import udir @@ -230,6 +230,8 @@ f = cfile.open('w') GenC(f, self, name) f.close() + if not really_compile: + return cfile mod = make_module_from_c(cfile) return getattr(mod, self.entrypoint.func_name) From mgedmin at codespeak.net Thu Nov 18 19:12:25 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Thu, 18 Nov 2004 19:12:25 +0100 (MET) Subject: [pypy-svn] r7404 - pypy/trunk/src/goal Message-ID: <20041118181225.4F5335B151@thoth.codespeak.net> Author: mgedmin Date: Thu Nov 18 19:12:21 2004 New Revision: 7404 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Added a simple help message (copied straight from Armin's commit message). Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Thu Nov 18 19:12:21 2004 @@ -1,6 +1,14 @@ # # # +""" +Command-line options for translate_pypy: + + -text Don't start the Pygame viewer + -no-c Don't generate the C code + -c Generate the C code, but don't compile it + -o Generate and compile the C code, but don't run it +""" import autopath, sys, threading, pdb from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.objspace.std.intobject import W_IntObject @@ -37,6 +45,9 @@ '-o': False, } for arg in sys.argv[1:]: + if arg in ('-h', '--help'): + print __doc__.strip() + sys.exit() assert arg in options, "unknown option %r" % (arg,) options[arg] = True From jacob at codespeak.net Thu Nov 18 19:47:09 2004 From: jacob at codespeak.net (jacob at codespeak.net) Date: Thu, 18 Nov 2004 19:47:09 +0100 (MET) Subject: [pypy-svn] r7405 - in pypy/trunk/src/pypy/appspace: . test Message-ID: <20041118184709.1E4335B154@thoth.codespeak.net> Author: jacob Date: Thu Nov 18 19:47:08 2004 New Revision: 7405 Added: pypy/trunk/src/pypy/appspace/pymd5.py pypy/trunk/src/pypy/appspace/pysha.py pypy/trunk/src/pypy/appspace/test/test_md5.py pypy/trunk/src/pypy/appspace/test/test_sha.py Log: Python implementations of MD5 and SHA. Added: pypy/trunk/src/pypy/appspace/pymd5.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/pymd5.py Thu Nov 18 19:47:08 2004 @@ -0,0 +1,423 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 + +"""A sample implementation of MD5 in pure Python. + +This is an implementation of the MD5 hash function, as specified by +RFC 1321, in pure Python. It was implemented using Bruce Schneier's +excellent book "Applied Cryptography", 2nd ed., 1996. + +Surely this is not meant to compete with the existing implementation +of the Python standard library (written in C). Rather, it should be +seen as a Python complement that is more readable than C and can be +used more conveniently for learning and experimenting purposes in +the field of cryptography. + +This module tries very hard to follow the API of the existing Python +standard library's "md5" module, but although it seems to work fine, +it has not been extensively tested! (But note that there is a test +module, test_md5py.py, that compares this Python implementation with +the C one of the Python standard library. + +BEWARE: this comes with no guarantee whatsoever about fitness and/or +other properties! Specifically, do not use this in any production +code! License is Python License! + +Special thanks to Aurelian Coman who fixed some nasty bugs! + +Dinu C. Gherman +""" + + +__date__ = '2004-11-17' +__version__ = 0.91 # Modernised by J. Hall?n and L. Creighton for Pypy + + +import struct, copy + + +# ====================================================================== +# Bit-Manipulation helpers +# +# _long2bytes() was contributed by Barry Warsaw +# and is reused here with tiny modifications. +# ====================================================================== + +def _long2bytes(n, blocksize=0): + """Convert a long integer to a byte string. + + If optional blocksize is given and greater than zero, pad the front + of the byte string with binary zeros so that the length is a multiple + of blocksize. + """ + + # After much testing, this algorithm was deemed to be the fastest. + s = '' + pack = struct.pack + while n > 0: + ### CHANGED FROM '>I' TO '> 32 + + # Strip off leading zeros. + for i in range(len(s)): + if s[i] <> '\000': + break + else: + # Only happens when n == 0. + s = '\000' + i = 0 + + s = s[i:] + + # Add back some pad bytes. This could be done more efficiently + # w.r.t. the de-padding being done above, but sigh... + if blocksize > 0 and len(s) % blocksize: + s = (blocksize - len(s) % blocksize) * '\000' + s + + return s + + +def _bytelist2long(list): + "Transform a list of characters into a list of longs." + + imax = len(list)/4 + hl = [0L] * imax + + j = 0 + i = 0 + while i < imax: + b0 = long(ord(list[j])) + b1 = (long(ord(list[j+1]))) << 8 + b2 = (long(ord(list[j+2]))) << 16 + b3 = (long(ord(list[j+3]))) << 24 + hl[i] = b0 | b1 |b2 | b3 + i = i+1 + j = j+4 + + return hl + + +def _rotateLeft(x, n): + "Rotate x (32 bit) left n bits circularly." + + return (x << n) | (x >> (32-n)) + + +# ====================================================================== +# The real MD5 meat... +# +# Implemented after "Applied Cryptography", 2nd ed., 1996, +# pp. 436-441 by Bruce Schneier. +# ====================================================================== + +# F, G, H and I are basic MD5 functions. + +def F(x, y, z): + return (x & y) | ((~x) & z) + +def G(x, y, z): + return (x & z) | (y & (~z)) + +def H(x, y, z): + return x ^ y ^ z + +def I(x, y, z): + return y ^ (x | (~z)) + + +def XX(func, a, b, c, d, x, s, ac): + """Wrapper for call distribution to functions F, G, H and I. + + This replaces functions FF, GG, HH and II from "Appl. Crypto." + Rotation is separate from addition to prevent recomputation + (now summed-up in one function). + """ + + res = 0L + res = res + a + func(b, c, d) + res = res + x + res = res + ac + res = res & 0xffffffffL + res = _rotateLeft(res, s) + res = res & 0xffffffffL + res = res + b + + return res & 0xffffffffL + + +class MD5: + "An implementation of the MD5 hash function in pure Python." + + def __init__(self): + "Initialisation." + + # Initial message length in bits(!). + self.length = 0L + self.count = [0, 0] + + # Initial empty message as a sequence of bytes (8 bit characters). + self.input = [] + + # Call a separate init function, that can be used repeatedly + # to start from scratch on the same object. + self.init() + + + def init(self): + "Initialize the message-digest and set all fields to zero." + + self.length = 0L + self.input = [] + + # Load magic initialization constants. + self.A = 0x67452301L + self.B = 0xefcdab89L + self.C = 0x98badcfeL + self.D = 0x10325476L + + + def _transform(self, inp): + """Basic MD5 step transforming the digest based on the input. + + Note that if the Mysterious Constants are arranged backwards + in little-endian order and decrypted with the DES they produce + OCCULT MESSAGES! + """ + + a, b, c, d = A, B, C, D = self.A, self.B, self.C, self.D + + # Round 1. + + S11, S12, S13, S14 = 7, 12, 17, 22 + + a = XX(F, a, b, c, d, inp[ 0], S11, 0xD76AA478L) # 1 + d = XX(F, d, a, b, c, inp[ 1], S12, 0xE8C7B756L) # 2 + c = XX(F, c, d, a, b, inp[ 2], S13, 0x242070DBL) # 3 + b = XX(F, b, c, d, a, inp[ 3], S14, 0xC1BDCEEEL) # 4 + a = XX(F, a, b, c, d, inp[ 4], S11, 0xF57C0FAFL) # 5 + d = XX(F, d, a, b, c, inp[ 5], S12, 0x4787C62AL) # 6 + c = XX(F, c, d, a, b, inp[ 6], S13, 0xA8304613L) # 7 + b = XX(F, b, c, d, a, inp[ 7], S14, 0xFD469501L) # 8 + a = XX(F, a, b, c, d, inp[ 8], S11, 0x698098D8L) # 9 + d = XX(F, d, a, b, c, inp[ 9], S12, 0x8B44F7AFL) # 10 + c = XX(F, c, d, a, b, inp[10], S13, 0xFFFF5BB1L) # 11 + b = XX(F, b, c, d, a, inp[11], S14, 0x895CD7BEL) # 12 + a = XX(F, a, b, c, d, inp[12], S11, 0x6B901122L) # 13 + d = XX(F, d, a, b, c, inp[13], S12, 0xFD987193L) # 14 + c = XX(F, c, d, a, b, inp[14], S13, 0xA679438EL) # 15 + b = XX(F, b, c, d, a, inp[15], S14, 0x49B40821L) # 16 + + # Round 2. + + S21, S22, S23, S24 = 5, 9, 14, 20 + + a = XX(G, a, b, c, d, inp[ 1], S21, 0xF61E2562L) # 17 + d = XX(G, d, a, b, c, inp[ 6], S22, 0xC040B340L) # 18 + c = XX(G, c, d, a, b, inp[11], S23, 0x265E5A51L) # 19 + b = XX(G, b, c, d, a, inp[ 0], S24, 0xE9B6C7AAL) # 20 + a = XX(G, a, b, c, d, inp[ 5], S21, 0xD62F105DL) # 21 + d = XX(G, d, a, b, c, inp[10], S22, 0x02441453L) # 22 + c = XX(G, c, d, a, b, inp[15], S23, 0xD8A1E681L) # 23 + b = XX(G, b, c, d, a, inp[ 4], S24, 0xE7D3FBC8L) # 24 + a = XX(G, a, b, c, d, inp[ 9], S21, 0x21E1CDE6L) # 25 + d = XX(G, d, a, b, c, inp[14], S22, 0xC33707D6L) # 26 + c = XX(G, c, d, a, b, inp[ 3], S23, 0xF4D50D87L) # 27 + b = XX(G, b, c, d, a, inp[ 8], S24, 0x455A14EDL) # 28 + a = XX(G, a, b, c, d, inp[13], S21, 0xA9E3E905L) # 29 + d = XX(G, d, a, b, c, inp[ 2], S22, 0xFCEFA3F8L) # 30 + c = XX(G, c, d, a, b, inp[ 7], S23, 0x676F02D9L) # 31 + b = XX(G, b, c, d, a, inp[12], S24, 0x8D2A4C8AL) # 32 + + # Round 3. + + S31, S32, S33, S34 = 4, 11, 16, 23 + + a = XX(H, a, b, c, d, inp[ 5], S31, 0xFFFA3942L) # 33 + d = XX(H, d, a, b, c, inp[ 8], S32, 0x8771F681L) # 34 + c = XX(H, c, d, a, b, inp[11], S33, 0x6D9D6122L) # 35 + b = XX(H, b, c, d, a, inp[14], S34, 0xFDE5380CL) # 36 + a = XX(H, a, b, c, d, inp[ 1], S31, 0xA4BEEA44L) # 37 + d = XX(H, d, a, b, c, inp[ 4], S32, 0x4BDECFA9L) # 38 + c = XX(H, c, d, a, b, inp[ 7], S33, 0xF6BB4B60L) # 39 + b = XX(H, b, c, d, a, inp[10], S34, 0xBEBFBC70L) # 40 + a = XX(H, a, b, c, d, inp[13], S31, 0x289B7EC6L) # 41 + d = XX(H, d, a, b, c, inp[ 0], S32, 0xEAA127FAL) # 42 + c = XX(H, c, d, a, b, inp[ 3], S33, 0xD4EF3085L) # 43 + b = XX(H, b, c, d, a, inp[ 6], S34, 0x04881D05L) # 44 + a = XX(H, a, b, c, d, inp[ 9], S31, 0xD9D4D039L) # 45 + d = XX(H, d, a, b, c, inp[12], S32, 0xE6DB99E5L) # 46 + c = XX(H, c, d, a, b, inp[15], S33, 0x1FA27CF8L) # 47 + b = XX(H, b, c, d, a, inp[ 2], S34, 0xC4AC5665L) # 48 + + # Round 4. + + S41, S42, S43, S44 = 6, 10, 15, 21 + + a = XX(I, a, b, c, d, inp[ 0], S41, 0xF4292244L) # 49 + d = XX(I, d, a, b, c, inp[ 7], S42, 0x432AFF97L) # 50 + c = XX(I, c, d, a, b, inp[14], S43, 0xAB9423A7L) # 51 + b = XX(I, b, c, d, a, inp[ 5], S44, 0xFC93A039L) # 52 + a = XX(I, a, b, c, d, inp[12], S41, 0x655B59C3L) # 53 + d = XX(I, d, a, b, c, inp[ 3], S42, 0x8F0CCC92L) # 54 + c = XX(I, c, d, a, b, inp[10], S43, 0xFFEFF47DL) # 55 + b = XX(I, b, c, d, a, inp[ 1], S44, 0x85845DD1L) # 56 + a = XX(I, a, b, c, d, inp[ 8], S41, 0x6FA87E4FL) # 57 + d = XX(I, d, a, b, c, inp[15], S42, 0xFE2CE6E0L) # 58 + c = XX(I, c, d, a, b, inp[ 6], S43, 0xA3014314L) # 59 + b = XX(I, b, c, d, a, inp[13], S44, 0x4E0811A1L) # 60 + a = XX(I, a, b, c, d, inp[ 4], S41, 0xF7537E82L) # 61 + d = XX(I, d, a, b, c, inp[11], S42, 0xBD3AF235L) # 62 + c = XX(I, c, d, a, b, inp[ 2], S43, 0x2AD7D2BBL) # 63 + b = XX(I, b, c, d, a, inp[ 9], S44, 0xEB86D391L) # 64 + + A = (A + a) & 0xffffffffL + B = (B + b) & 0xffffffffL + C = (C + c) & 0xffffffffL + D = (D + d) & 0xffffffffL + + self.A, self.B, self.C, self.D = A, B, C, D + + + # Down from here all methods follow the Python Standard Library + # API of the md5 module. + + def update(self, inBuf): + """Add to the current message. + + Update the md5 object with the string arg. Repeated calls + are equivalent to a single call with the concatenation of all + the arguments, i.e. m.update(a); m.update(b) is equivalent + to m.update(a+b). + + The hash is immediately calculated for all full blocks. The final + calculation is made in digest(). This allows us to keep an + intermediate value for the hash, so that we only need to make + minimal recalculation if we call update() to add moredata to + the hashed string. + """ + + leninBuf = long(len(inBuf)) + + # Compute number of bytes mod 64. + index = (self.count[0] >> 3) & 0x3FL + + # Update number of bits. + self.count[0] = self.count[0] + (leninBuf << 3) + if self.count[0] < (leninBuf << 3): + self.count[1] = self.count[1] + 1 + self.count[1] = self.count[1] + (leninBuf >> 29) + + partLen = 64 - index + + if leninBuf >= partLen: + self.input[index:] = list(inBuf[:partLen]) + self._transform(_bytelist2long(self.input)) + i = partLen + while i + 63 < leninBuf: + self._transform(_bytelist2long(list(inBuf[i:i+64]))) + i = i + 64 + else: + self.input = list(inBuf[i:leninBuf]) + else: + i = 0 + self.input = self.input + list(inBuf) + + + def digest(self): + """Terminate the message-digest computation and return digest. + + Return the digest of the strings passed to the update() + method so far. This is a 16-byte string which may contain + non-ASCII characters, including null bytes. + """ + + A = self.A + B = self.B + C = self.C + D = self.D + input = [] + self.input + count = [] + self.count + + index = (self.count[0] >> 3) & 0x3fL + + if index < 56: + padLen = 56 - index + else: + padLen = 120 - index + + padding = ['\200'] + ['\000'] * 63 + self.update(padding[:padLen]) + + # Append length (before padding). + bits = _bytelist2long(self.input[:56]) + count + + self._transform(bits) + + # Store state in digest. + digest = _long2bytes(self.A << 96, 16)[:4] + \ + _long2bytes(self.B << 64, 16)[4:8] + \ + _long2bytes(self.C << 32, 16)[8:12] + \ + _long2bytes(self.D, 16)[12:] + + self.A = A + self.B = B + self.C = C + self.D = D + self.input = input + self.count = count + + return digest + + + def hexdigest(self): + """Terminate and return digest in HEX form. + + Like digest() except the digest is returned as a string of + length 32, containing only hexadecimal digits. This may be + used to exchange the value safely in email or other non- + binary environments. + """ + + return ''.join(['%02x' % ord(c) for c in self.digest()]) + + def copy(self): + """Return a clone object. + + Return a copy ('clone') of the md5 object. This can be used + to efficiently compute the digests of strings that share + a common initial substring. + """ + + return copy.deepcopy(self) + + +# ====================================================================== +# Mimic Python top-level functions from standard library API +# for consistency with the md5 module of the standard library. +# ====================================================================== + +digest_size = 16 + +def new(arg=None): + """Return a new md5 object. + + If arg is present, the method call update(arg) is made. + """ + + md5 = MD5() + if arg: + md5.update(arg) + + return md5 + + +def md5(arg=None): + """Same as new(). + + For backward compatibility reasons, this is an alternative + name for the new() function. + """ + + return new(arg) Added: pypy/trunk/src/pypy/appspace/pysha.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/pysha.py Thu Nov 18 19:47:08 2004 @@ -0,0 +1,341 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 + +"""A sample implementation of SHA-1 in pure Python. + + Framework adapted from Dinu Gherman's MD5 implementation by + J. Hall?n and L. Creighton. SHA-1 implementation based directly on + the text of the NIST standard FIPS PUB 180-1. +""" + + +__date__ = '2004-11-17' +__version__ = 0.91 # Modernised by J. Hall?n and L. Creighton for Pypy + + +import struct, copy + + +# ====================================================================== +# Bit-Manipulation helpers +# +# _long2bytes() was contributed by Barry Warsaw +# and is reused here with tiny modifications. +# ====================================================================== + +def _long2bytesBigEndian(n, blocksize=0): + """Convert a long integer to a byte string. + + If optional blocksize is given and greater than zero, pad the front + of the byte string with binary zeros so that the length is a multiple + of blocksize. + """ + + # After much testing, this algorithm was deemed to be the fastest. + s = '' + pack = struct.pack + while n > 0: + s = pack('>I', n & 0xffffffffL) + s + n = n >> 32 + + # Strip off leading zeros. + for i in range(len(s)): + if s[i] <> '\000': + break + else: + # Only happens when n == 0. + s = '\000' + i = 0 + + s = s[i:] + + # Add back some pad bytes. This could be done more efficiently + # w.r.t. the de-padding being done above, but sigh... + if blocksize > 0 and len(s) % blocksize: + s = (blocksize - len(s) % blocksize) * '\000' + s + + return s + + +def _bytelist2longBigEndian(list): + "Transform a list of characters into a list of longs." + + imax = len(list)/4 + hl = [0L] * imax + + j = 0 + i = 0 + while i < imax: + b0 = long(ord(list[j])) << 24 + b1 = long(ord(list[j+1])) << 16 + b2 = long(ord(list[j+2])) << 8 + b3 = long(ord(list[j+3])) + hl[i] = b0 | b1 | b2 | b3 + i = i+1 + j = j+4 + + return hl + + +def _rotateLeft(x, n): + "Rotate x (32 bit) left n bits circularly." + + return (x << n) | (x >> (32-n)) + + +# ====================================================================== +# The SHA transformation functions +# +# ====================================================================== + +def f0_19(B, C, D): + return (B & C) | ((~ B) & D) + +def f20_39(B, C, D): + return B ^ C ^ D + +def f40_59(B, C, D): + return (B & C) | (B & D) | (C & D) + +def f60_79(B, C, D): + return B ^ C ^ D + + +f = [f0_19, f20_39, f40_59, f60_79] + +# Constants to be used +K = [ + 0x5A827999L, # ( 0 <= t <= 19) + 0x6ED9EBA1L, # (20 <= t <= 39) + 0x8F1BBCDCL, # (40 <= t <= 59) + 0xCA62C1D6L # (60 <= t <= 79) + ] + +class MD5: + "An implementation of the MD5 hash function in pure Python." + + def __init__(self): + "Initialisation." + + # Initial message length in bits(!). + self.length = 0L + self.count = [0, 0] + + # Initial empty message as a sequence of bytes (8 bit characters). + self.input = [] + + # Call a separate init function, that can be used repeatedly + # to start from scratch on the same object. + self.init() + + + def init(self): + "Initialize the message-digest and set all fields to zero." + + self.length = 0L + self.input = [] + + # Initial 160 bit message digest (5 times 32 bit). + self.H0 = 0x67452301L + self.H1 = 0xEFCDAB89L + self.H2 = 0x98BADCFEL + self.H3 = 0x10325476L + self.H4 = 0xC3D2E1F0L + + def _transform(self, W): + + for t in range(16, 80): + W.append(_rotateLeft( + W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1) & 0xffffffffL) + + A = self.H0 + B = self.H1 + C = self.H2 + D = self.H3 + E = self.H4 + + """ + This loop was unrolled to gain about 10% in speed + for t in range(0, 80): + TEMP = _rotateLeft(A, 5) + f[t/20] + E + W[t] + K[t/20] + E = D + D = C + C = _rotateLeft(B, 30) & 0xffffffffL + B = A + A = TEMP & 0xffffffffL + """ + + for t in range(0, 20): + TEMP = _rotateLeft(A, 5) + ((B & C) | ((~ B) & D)) + E + W[t] + K[0] + E = D + D = C + C = _rotateLeft(B, 30) & 0xffffffffL + B = A + A = TEMP & 0xffffffffL + + for t in range(20, 40): + TEMP = _rotateLeft(A, 5) + (B ^ C ^ D) + E + W[t] + K[1] + E = D + D = C + C = _rotateLeft(B, 30) & 0xffffffffL + B = A + A = TEMP & 0xffffffffL + + for t in range(40, 60): + TEMP = _rotateLeft(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2] + E = D + D = C + C = _rotateLeft(B, 30) & 0xffffffffL + B = A + A = TEMP & 0xffffffffL + + for t in range(60, 80): + TEMP = _rotateLeft(A, 5) + (B ^ C ^ D) + E + W[t] + K[3] + E = D + D = C + C = _rotateLeft(B, 30) & 0xffffffffL + B = A + A = TEMP & 0xffffffffL + + + self.H0 = (self.H0 + A) & 0xffffffffL + self.H1 = (self.H1 + B) & 0xffffffffL + self.H2 = (self.H2 + C) & 0xffffffffL + self.H3 = (self.H3 + D) & 0xffffffffL + self.H4 = (self.H4 + E) & 0xffffffffL + + + # Down from here all methods follow the Python Standard Library + # API of the sha module. + + def update(self, inBuf): + """Add to the current message. + + Update the md5 object with the string arg. Repeated calls + are equivalent to a single call with the concatenation of all + the arguments, i.e. m.update(a); m.update(b) is equivalent + to m.update(a+b). + + The hash is immediately calculated for all full blocks. The final + calculation is made in digest(). It will calculate 1-2 blocks, + depending on how much padding we have to add. This allows us to + keep an intermediate value for the hash, so that we only need to + make minimal recalculation if we call update() to add more data + to the hashed string. + """ + + leninBuf = long(len(inBuf)) + + # Compute number of bytes mod 64. + index = (self.count[1] >> 3) & 0x3FL + + # Update number of bits. + self.count[1] = self.count[1] + (leninBuf << 3) + if self.count[1] < (leninBuf << 3): + self.count[0] = self.count[0] + 1 + self.count[0] = self.count[0] + (leninBuf >> 29) + + partLen = 64 - index + + if leninBuf >= partLen: + self.input[index:] = list(inBuf[:partLen]) + self._transform(_bytelist2longBigEndian(self.input)) + i = partLen + while i + 63 < leninBuf: + self._transform(_bytelist2longBigEndian(list(inBuf[i:i+64]))) + i = i + 64 + else: + self.input = list(inBuf[i:leninBuf]) + else: + i = 0 + self.input = self.input + list(inBuf) + + + def digest(self): + """Terminate the message-digest computation and return digest. + + Return the digest of the strings passed to the update() + method so far. This is a 16-byte string which may contain + non-ASCII characters, including null bytes. + """ + + H0 = self.H0 + H1 = self.H1 + H2 = self.H2 + H3 = self.H3 + H4 = self.H4 + input = [] + self.input + count = [] + self.count + + index = (self.count[1] >> 3) & 0x3fL + + if index < 56: + padLen = 56 - index + else: + padLen = 120 - index + + padding = ['\200'] + ['\000'] * 63 + self.update(padding[:padLen]) + + # Append length (before padding). + bits = _bytelist2longBigEndian(self.input[:56]) + count + + self._transform(bits) + + # Store state in digest. + digest = _long2bytesBigEndian(self.H0, 4) + \ + _long2bytesBigEndian(self.H1, 4) + \ + _long2bytesBigEndian(self.H2, 4) + \ + _long2bytesBigEndian(self.H3, 4) + \ + _long2bytesBigEndian(self.H4, 4) + + self.H0 = H0 + self.H1 = H1 + self.H2 = H2 + self.H3 = H3 + self.H4 = H4 + self.input = input + self.count = count + + return digest + + + def hexdigest(self): + """Terminate and return digest in HEX form. + + Like digest() except the digest is returned as a string of + length 32, containing only hexadecimal digits. This may be + used to exchange the value safely in email or other non- + binary environments. + """ + return ''.join(['%02x' % ord(c) for c in self.digest()]) + + def copy(self): + """Return a clone object. + + Return a copy ('clone') of the md5 object. This can be used + to efficiently compute the digests of strings that share + a common initial substring. + """ + + return copy.deepcopy(self) + + +# ====================================================================== +# Mimic Python top-level functions from standard library API +# for consistency with the md5 module of the standard library. +# ====================================================================== + +digest_size = 16 + +def new(arg=None): + """Return a new md5 object. + + If arg is present, the method call update(arg) is made. + """ + + md5 = MD5() + if arg: + md5.update(arg) + + return md5 Added: pypy/trunk/src/pypy/appspace/test/test_md5.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test/test_md5.py Thu Nov 18 19:47:08 2004 @@ -0,0 +1,240 @@ +"""A test script to compare MD5 implementations. + +A note about performance: the pure Python MD5 takes roughly +160 sec. per MB of data on a 233 MHz Intel Pentium CPU. +""" + +import string, unittest +import md5 # Python's implementation in C. +import pymd5 # The pure Python implementation. + + +# Helpers... + +def formatHex(str): + "Print a string's HEX code in groups of two digits." + + d = map(None, str) + d = map(ord, d) + d = map(lambda x:"%02x" % x, d) + return string.join(d, " ") + + +def format(str): + "Print a string as-is in groups of two characters." + + s = '' + for i in range(0, len(str)-1, 2): + s = s + "%03s" % str[i:i+2] + return s[1:] + + +def printDiff(message, d1, d2, expectedResult=None): + "Print different outputs for same message." + + print "Message: '%s'" % message + print "Message length: %d" % len(message) + if expectedResult: + print "%-48s (expected)" % format(expectedResult) + print "%-48s (Std. lib. MD5)" % formatHex(d1) + print "%-48s (Pure Python MD5)" % formatHex(d2) + print + + +# The real comparison function. + +def compareImp(message): + """Compare two MD5 implementations, C vs. pure Python module. + + For equal digests this returns None, otherwise it returns + a tuple of both digests. + """ + + # Use Python's standard library MD5 compiled C module. + m1 = md5.md5() + m1.update(message) + d1 = m1.digest() + d1h = m1.hexdigest() + + # Use MD5 module in pure Python. + m2 = pymd5.md5() + m2.update(message) + d2 = m2.digest() + d2h = m2.hexdigest() + + # Return None if equal or the different digests if not equal. + if d1 == d2 and d1h == d2h: + return + else: + return d1, d2 + + +class MD5CompareTestCase(unittest.TestCase): + "Compare pure Python MD5 against Python's std. lib. version." + + def test1(self): + "Test cases with known digest result." + + cases = ( + ("", + "d41d8cd98f00b204e9800998ecf8427e"), + ("a", + "0cc175b9c0f1b6a831c399e269772661"), + ("abc", + "900150983cd24fb0d6963f7d28e17f72"), + ("message digest", + "f96b697d7cb7938d525a2f31aaf161d0"), + ("abcdefghijklmnopqrstuvwxyz", + "c3fcd3d76192e4007dfb496cca67e13b"), + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "d174ab98d277d9f5a5611c2c9f419d9f"), + ("1234567890"*8, + "57edf4a22be3c955ac49da2e2107b67a"), + ) + + for i in xrange(len(cases)): + res = compareImp(cases[i][0]) + try: + assert res == None + except AssertionError, details: + d1, d2 = res + message, expectedResult = cases[i][0], None + if len(cases[i]) == 2: + expectedResult = cases[i][1] + printDiff(message, d1, d2, expectedResult) + + + def test2(self): + "Test cases without known digest result." + + cases = ( + "123", + "1234", + "12345", + "123456", + "1234567", + "12345678", + "123456789 123456789 123456789 ", + "123456789 123456789 ", + "123456789 123456789 1", + "123456789 123456789 12", + "123456789 123456789 123", + "123456789 123456789 1234", + "123456789 123456789 123456789 1", + "123456789 123456789 123456789 12", + "123456789 123456789 123456789 123", + "123456789 123456789 123456789 1234", + "123456789 123456789 123456789 12345", + "123456789 123456789 123456789 123456", + "123456789 123456789 123456789 1234567", + "123456789 123456789 123456789 12345678", + ) + + for i in xrange(len(cases)): + res = compareImp(cases[i][0]) + try: + assert res == None + except AssertionError, details: + d1, d2 = res + message = cases[i][0] + printDiff(message, d1, d2) + + + def test3(self): + "Test cases with long messages (can take a while)." + + cases = ( + (2**10*'a',), + (2**10*'abcd',), +## (2**20*'a',), ## 1 MB, takes about 160 sec. on a 233 Mhz Pentium. + ) + + for i in xrange(len(cases)): + res = compareImp(cases[i][0]) + try: + assert res == None + except AssertionError, details: + d1, d2 = res + message = cases[i][0] + printDiff(message, d1, d2) + + + def test4(self): + "Test cases with increasingly growing message lengths." + + i = 0 + while i < 2**5: + message = i * 'a' + res = compareImp(message) + try: + assert res == None + except AssertionError, details: + d1, d2 = res + printDiff(message, d1, d2) + i = i + 1 + + + def test5(self): + "Test updating cloned objects." + + cases = ( + "123", + "1234", + "12345", + "123456", + "1234567", + "12345678", + "123456789 123456789 123456789 ", + "123456789 123456789 ", + "123456789 123456789 1", + "123456789 123456789 12", + "123456789 123456789 123", + "123456789 123456789 1234", + "123456789 123456789 123456789 1", + "123456789 123456789 123456789 12", + "123456789 123456789 123456789 123", + "123456789 123456789 123456789 1234", + "123456789 123456789 123456789 12345", + "123456789 123456789 123456789 123456", + "123456789 123456789 123456789 1234567", + "123456789 123456789 123456789 12345678", + ) + + # Load both with same prefix. + prefix1 = 2**10 * 'a' + + m1 = md5.md5() + m1.update(prefix1) + m1c = m1.copy() + + m2 = pymd5.md5() + m2.update(prefix1) + m2c = m2.copy() + + # Update and compare... + for i in xrange(len(cases)): + message = cases[i][0] + + m1c.update(message) + d1 = m1c.hexdigest() + + m2c.update(message) + d2 = m2c.hexdigest() + + assert d1 == d2 + + +def makeSuite(): + suite = unittest.TestSuite() + + suite.addTest(MD5CompareTestCase('test1')) + suite.addTest(MD5CompareTestCase('test2')) + suite.addTest(MD5CompareTestCase('test3')) + suite.addTest(MD5CompareTestCase('test4')) + suite.addTest(MD5CompareTestCase('test5')) + + return suite + + +if __name__ == "__main__": + unittest.TextTestRunner().run(makeSuite()) Added: pypy/trunk/src/pypy/appspace/test/test_sha.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test/test_sha.py Thu Nov 18 19:47:08 2004 @@ -0,0 +1,32 @@ +# Testing sha module (NIST's Secure Hash Algorithm) + +# use the three examples from Federal Information Processing Standards +# Publication 180-1, Secure Hash Standard, 1995 April 17 +# http://www.itl.nist.gov/div897/pubs/fip180-1.htm + +import pysha as sha +import unittest + +class SHATestCase(unittest.TestCase): + def check(self, data, digest): + computed = sha.new(data).hexdigest() + self.assert_(computed == digest) + + def test_case_1(self): + self.check("abc", + "a9993e364706816aba3e25717850c26c9cd0d89d") + + def test_case_2(self): + self.check("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "84983e441c3bd26ebaae4aa1f95129e5e54670f1") + + def test_case_3(self): + self.check("a" * 1000000, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f") + +def test_main(): + unittest.main() + + +if __name__ == "__main__": + test_main() From hpk at codespeak.net Thu Nov 18 19:47:54 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 18 Nov 2004 19:47:54 +0100 (MET) Subject: [pypy-svn] r7406 - pypy/trunk/src/pypy/translator Message-ID: <20041118184754.BE19D5B155@thoth.codespeak.net> Author: hpk Date: Thu Nov 18 19:47:54 2004 New Revision: 7406 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/transform.py Log: a small first hack at removing dead "simple_call" operations watch some of the specialized wrap_..._SomeXXX getting very small, yay Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Thu Nov 18 19:47:54 2004 @@ -239,6 +239,9 @@ # Generic simplifications from pypy.translator import transform transform.transform_graph(self) + from pypy.translator import simplify + for graph in self.translator.flowgraphs.values(): + simplify.eliminate_empty_blocks(graph) #___ flowing annotations in blocks _____________________ Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Thu Nov 18 19:47:54 2004 @@ -106,6 +106,7 @@ CanRemove = {'newtuple': True, 'newlist': True, 'newdict': True, + 'is_': True, 'is_true': True} read_vars = {} # set of variables really used variable_flow = {} # map {Var: list-of-Vars-it-depends-on} @@ -155,8 +156,14 @@ # look for removable operations whose result is never used for i in range(len(block.operations)-1, -1, -1): op = block.operations[i] - if op.opname in CanRemove and op.result not in read_vars: - del block.operations[i] + if op.result not in read_vars: + if op.opname in CanRemove: + del block.operations[i] + elif op.opname == 'simple_call': + if op.args and isinstance(op.args[0], Constant): + func = op.args[0].value + if func is isinstance: + del block.operations[i] # look for output variables never used # warning: this must be completely done *before* we attempt to From mwh at codespeak.net Thu Nov 18 23:58:17 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Thu, 18 Nov 2004 23:58:17 +0100 (MET) Subject: [pypy-svn] r7408 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118225817.CB9625B15E@thoth.codespeak.net> Author: mwh Date: Thu Nov 18 23:58:17 2004 New Revision: 7408 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py Log: >From the 'I should really be in bed' school of hacking, change the implementation of dicts to be an array of 'Entry's as opposed to an array of lists, the theory being that the annotator has some hope of being able to analyze this situation. It can't yet, but it's a bit better. I had to comment out an assertion as the improved annotation mentioned above tickled a new-ish bug (the interaction between the special processing of r_uint and isinstance in builtin.py). I'll bang some heads together about that tomorrow :) This was also another opportunity to remind myself how getting things wrong in the implementation of dicts can lead to really, really inscrutable behaviour (space instantation failing with ImportErrors, for example...). Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Thu Nov 18 23:58:17 2004 @@ -12,6 +12,14 @@ dummy = object() +class Entry: + def __init__(self): + self.hash = 0 + self.w_key = None + self.w_value = None + def __repr__(self): + return ''%(self.hash, self.w_key, self.w_value) + class W_DictObject(W_Object): from pypy.objspace.std.dicttype import dict_typedef as typedef @@ -33,12 +41,14 @@ return r_uint(space.unwrap(space.hash(w_obj))) def insert(self, h, w_key, w_value): - cell = self.lookdict(h, w_key) - if cell[2] is None: + entry = self.lookdict(h, w_key) + if entry.w_value is None: self.used += 1 - cell[:] = [h, w_key, w_value] + entry.hash = h + entry.w_key = w_key + entry.w_value = w_value else: - cell[2] = w_value + entry.w_value = w_value def resize(self, minused): newsize = 4 @@ -47,28 +57,29 @@ od = self.data self.used = 0 - self.data = [[r_uint(0), None, None] for i in range(newsize)] - for h, k, v in od: - if v is not None: - self.insert(h, k, v) + self.data = [Entry() for i in range(newsize)] + for entry in od: + if entry.w_value is not None: + self.insert(entry.hash, entry.w_key, entry.w_value) def non_empties(self): - return [(h, w_k, w_v) for (h, w_k, w_v) in self.data if w_v is not None] + return [(entry.hash, entry.w_key, entry.w_value) + for entry in self.data if entry.w_value is not None] def lookdict(self, lookup_hash, w_lookup): - assert isinstance(lookup_hash, r_uint) +# assert isinstance(lookup_hash, r_uint) space = self.space i = lookup_hash % len(self.data) entry = self.data[i] - if entry[1] is None or \ - space.is_true(space.is_(w_lookup, entry[1])): + if entry.w_key is None or \ + space.is_true(space.is_(w_lookup, entry.w_key)): return entry - if entry[1] is dummy: + if entry.w_key is dummy: freeslot = entry else: - if entry[0] == lookup_hash and space.is_true( - space.eq(entry[1], w_lookup)): + if entry.hash == lookup_hash and space.is_true( + space.eq(entry.w_key, w_lookup)): return entry freeslot = None @@ -82,16 +93,16 @@ ## pdb.set_trace() i = (i << 2) + i + perturb + 1 entry = self.data[i%len(self.data)] - if entry[1] is None: + if entry.w_value is None: if freeslot: return freeslot else: return entry - if entry[0] == lookup_hash and entry[1] is not dummy \ + if entry.hash == lookup_hash and entry.w_key is not dummy \ and space.is_true( - space.eq(entry[1], w_lookup)): + space.eq(entry.w_key, w_lookup)): return entry - if entry[1] is dummy and freeslot is None: + if entry.w_key is dummy and freeslot is None: freeslot = entry perturb >>= 5 @@ -132,8 +143,8 @@ def getitem__Dict_ANY(space, w_dict, w_lookup): entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup) - if entry[2] is not None: - return entry[2] + if entry.w_value is not None: + return entry.w_value else: raise OperationError(space.w_KeyError, w_lookup) @@ -144,10 +155,10 @@ def delitem__Dict_ANY(space, w_dict, w_lookup): entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup) - if entry[2] is not None: + if entry.w_value is not None: w_dict.used -= 1 - entry[1] = dummy - entry[2] = None + entry.w_key = dummy + entry.w_value = None else: raise OperationError(space.w_KeyError, w_lookup) @@ -156,7 +167,7 @@ def contains__Dict_ANY(space, w_dict, w_lookup): entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup) - return space.newbool(entry[2] is not None) + return space.newbool(entry.w_value is not None) dict_has_key__Dict_ANY = contains__Dict_ANY @@ -209,33 +220,33 @@ raise OperationError(space.w_TypeError,space.wrap("dict objects are unhashable")) def dict_copy__Dict(space, w_self): - return W_DictObject(space, [(w_key,w_value) - for hash,w_key,w_value in w_self.data - if w_value is not None]) + return W_DictObject(space, [(entry.w_key,entry.w_value) + for entry in w_self.data + if entry.w_value is not None]) def dict_items__Dict(space, w_self): - return space.newlist([ space.newtuple([w_key,w_value]) - for hash,w_key,w_value in w_self.data - if w_value is not None]) + return space.newlist([ space.newtuple([entry.w_key,entry.w_value]) + for entry in w_self.data + if entry.w_value is not None]) def dict_keys__Dict(space, w_self): - return space.newlist([ w_key - for hash,w_key,w_value in w_self.data - if w_value is not None]) + return space.newlist([ entry.w_key + for entry in w_self.data + if entry.w_value is not None]) def dict_values__Dict(space, w_self): - return space.newlist([ w_value - for hash,w_key,w_value in w_self.data - if w_value is not None]) + return space.newlist([ entry.w_value + for entry in w_self.data + if entry.w_value is not None]) def dict_clear__Dict(space, w_self): - w_self.data = [[0, None, None]] + w_self.data = [Entry()] w_self.used = 0 def dict_get__Dict_ANY_ANY(space, w_dict, w_lookup, w_default): entry = w_dict.lookdict(w_dict.hash(w_lookup), w_lookup) - if entry[2] is not None: - return entry[2] + if entry.w_value is not None: + return entry.w_value else: return w_default From mwh at codespeak.net Fri Nov 19 00:08:48 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 00:08:48 +0100 (MET) Subject: [pypy-svn] r7409 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041118230848.1F1F55B16B@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 00:08:47 2004 New Revision: 7409 Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py Log: MORE THOROUGHNESS Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Fri Nov 19 00:08:47 2004 @@ -63,8 +63,7 @@ self.insert(entry.hash, entry.w_key, entry.w_value) def non_empties(self): - return [(entry.hash, entry.w_key, entry.w_value) - for entry in self.data if entry.w_value is not None] + return [entry for entry in self.data if entry.w_value is not None] def lookdict(self, lookup_hash, w_lookup): # assert isinstance(lookup_hash, r_uint) @@ -111,8 +110,8 @@ def unwrap__Dict(space, w_dict): result = {} - for hash, w_key, w_value in w_dict.non_empties(): - result[space.unwrap(w_key)] = space.unwrap(w_value) + for entry in w_dict.non_empties(): + result[space.unwrap(entry.w_key)] = space.unwrap(entry.w_value) return result def init__Dict(space, w_dict, w_args, w_kwds): @@ -184,12 +183,12 @@ dataright = w_right.non_empties() if len(dataleft) != len(dataright): return space.w_False - for hash, w_key, w_value in dataleft: + for entry in dataleft: try: - w_rightval = space.getitem(w_right, w_key) + w_rightval = space.getitem(w_right, entry.w_key) except OperationError: return space.w_False - if not space.is_true(space.eq(w_value, w_rightval)): + if not space.is_true(space.eq(entry.w_value, w_rightval)): return space.w_False return space.w_True @@ -203,15 +202,15 @@ return space.w_False # Same size - for hash, w_key, w_value in dataleft: + for entry in dataleft: # This is incorrect, but we need to decide what comparisons on # dictionaries of equal size actually means # The Python language specification is silent on the subject try: - w_rightval = space.getitem(w_right, w_key) + w_rightval = space.getitem(w_right, entry.w_key) except OperationError: return space.w_True - if space.is_true(space.lt(w_value, w_rightval)): + if space.is_true(space.lt(entry.w_value, w_rightval)): return space.w_True # The dictionaries are equal. This is correct. return space.w_False From hpk at codespeak.net Fri Nov 19 09:45:57 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 09:45:57 +0100 (MET) Subject: [pypy-svn] r7410 - pypy/trunk/src/pypy/annotation Message-ID: <20041119084557.50CE25B178@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 09:45:56 2004 New Revision: 7410 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py Log: finally rename BUILTIN_FUNCTIONS to BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri Nov 19 09:45:56 2004 @@ -106,11 +106,11 @@ # collect all functions import __builtin__ -BUILTIN_FUNCTIONS = {} +BUILTIN_ANALYZERS = {} for name, value in globals().items(): if name.startswith('builtin_'): original = getattr(__builtin__, name[8:]) - BUILTIN_FUNCTIONS[original] = value + BUILTIN_ANALYZERS[original] = value -BUILTIN_FUNCTIONS[pypy.objspace.std.restricted_int.r_int] = builtin_int -BUILTIN_FUNCTIONS[pypy.objspace.std.restricted_int.r_uint] = restricted_uint +BUILTIN_ANALYZERS[pypy.objspace.std.restricted_int.r_int] = builtin_int +BUILTIN_ANALYZERS[pypy.objspace.std.restricted_int.r_uint] = restricted_uint Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 09:45:56 2004 @@ -282,4 +282,4 @@ for factory in self.getallfactories(): bookkeeper.annotator.reflowfromposition(factory.position_key) -from pypy.annotation.builtin import BUILTIN_FUNCTIONS +from pypy.annotation.builtin import BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 09:45:56 2004 @@ -227,8 +227,8 @@ for key, value in x.items(): items[key] = immutablevalue(value) result = SomeDict({}, items) - elif ishashable(x) and x in BUILTIN_FUNCTIONS: - result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) + elif ishashable(x) and x in BUILTIN_ANALYZERS: + result = SomeBuiltin(BUILTIN_ANALYZERS[x]) elif callable(x) or isinstance(x, staticmethod): # XXX if hasattr(x, '__self__') and x.__self__ is not None: s_self = immutablevalue(x.__self__) @@ -303,4 +303,4 @@ # this has the side-effect of registering the unary and binary operations from pypy.annotation.unaryop import UNARY_OPERATIONS from pypy.annotation.binaryop import BINARY_OPERATIONS -from pypy.annotation.builtin import BUILTIN_FUNCTIONS +from pypy.annotation.builtin import BUILTIN_ANALYZERS From arigo at codespeak.net Fri Nov 19 09:51:48 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 09:51:48 +0100 (MET) Subject: [pypy-svn] r7411 - in pypy/trunk/src/pypy: appspace appspace/test module/test module/test/impsubdir/pkg_substituted module/test/impsubdir/pkg_substituting objspace/std objspace/std/test tool tool/test translator/tool Message-ID: <20041119085148.932235AC7E@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 09:51:47 2004 New Revision: 7411 Modified: pypy/trunk/src/pypy/appspace/_float_formatting.py (props changed) pypy/trunk/src/pypy/appspace/pymd5.py (props changed) pypy/trunk/src/pypy/appspace/pysha.py (props changed) pypy/trunk/src/pypy/appspace/test/test_md5.py (props changed) pypy/trunk/src/pypy/appspace/test/test_sha.py (props changed) pypy/trunk/src/pypy/module/test/applevel_in_cpython.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg_substituted/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg_substituted/__init__.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg_substituted/mod.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg_substituting/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg_substituting/__init__.py (props changed) pypy/trunk/src/pypy/objspace/std/basestringtype.py (props changed) pypy/trunk/src/pypy/objspace/std/dictproxyobject.py (props changed) pypy/trunk/src/pypy/objspace/std/dictproxytype.py (props changed) pypy/trunk/src/pypy/objspace/std/dump_multimethod.py (props changed) pypy/trunk/src/pypy/objspace/std/fake.py (props changed) pypy/trunk/src/pypy/objspace/std/test/test_dictproxy.py (props changed) pypy/trunk/src/pypy/objspace/std/test/test_unicodestring.py (props changed) pypy/trunk/src/pypy/objspace/std/unicodeobject.py (props changed) pypy/trunk/src/pypy/objspace/std/unicodetype.py (props changed) pypy/trunk/src/pypy/tool/cache.py (props changed) pypy/trunk/src/pypy/tool/hack.py (props changed) pypy/trunk/src/pypy/tool/test/test_cache.py (props changed) pypy/trunk/src/pypy/tool/test/test_utestconvert.py (props changed) pypy/trunk/src/pypy/tool/test/test_utestconvert2.py (props changed) pypy/trunk/src/pypy/tool/uid.py (props changed) pypy/trunk/src/pypy/tool/utestconvert.py (props changed) pypy/trunk/src/pypy/translator/tool/flowtrace.py (props changed) Log: fixeol From arigo at codespeak.net Fri Nov 19 09:53:31 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 09:53:31 +0100 (MET) Subject: [pypy-svn] r7412 - in pypy/trunk/src/pypy: appspace appspace/test module Message-ID: <20041119085331.5A0335B17E@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 09:53:30 2004 New Revision: 7412 Added: pypy/trunk/src/pypy/appspace/md5.py - copied unchanged from r7411, pypy/trunk/src/pypy/appspace/pymd5.py pypy/trunk/src/pypy/appspace/sha.py - copied unchanged from r7411, pypy/trunk/src/pypy/appspace/pysha.py Removed: pypy/trunk/src/pypy/appspace/pymd5.py pypy/trunk/src/pypy/appspace/pysha.py Modified: pypy/trunk/src/pypy/appspace/test/test_md5.py pypy/trunk/src/pypy/appspace/test/test_sha.py pypy/trunk/src/pypy/module/sysinterp.py Log: Integrated md5 and sha and their tests with PyPy. Deleted: /pypy/trunk/src/pypy/appspace/pymd5.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/pymd5.py Fri Nov 19 09:53:30 2004 +++ (empty file) @@ -1,423 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 - -"""A sample implementation of MD5 in pure Python. - -This is an implementation of the MD5 hash function, as specified by -RFC 1321, in pure Python. It was implemented using Bruce Schneier's -excellent book "Applied Cryptography", 2nd ed., 1996. - -Surely this is not meant to compete with the existing implementation -of the Python standard library (written in C). Rather, it should be -seen as a Python complement that is more readable than C and can be -used more conveniently for learning and experimenting purposes in -the field of cryptography. - -This module tries very hard to follow the API of the existing Python -standard library's "md5" module, but although it seems to work fine, -it has not been extensively tested! (But note that there is a test -module, test_md5py.py, that compares this Python implementation with -the C one of the Python standard library. - -BEWARE: this comes with no guarantee whatsoever about fitness and/or -other properties! Specifically, do not use this in any production -code! License is Python License! - -Special thanks to Aurelian Coman who fixed some nasty bugs! - -Dinu C. Gherman -""" - - -__date__ = '2004-11-17' -__version__ = 0.91 # Modernised by J. Hall?n and L. Creighton for Pypy - - -import struct, copy - - -# ====================================================================== -# Bit-Manipulation helpers -# -# _long2bytes() was contributed by Barry Warsaw -# and is reused here with tiny modifications. -# ====================================================================== - -def _long2bytes(n, blocksize=0): - """Convert a long integer to a byte string. - - If optional blocksize is given and greater than zero, pad the front - of the byte string with binary zeros so that the length is a multiple - of blocksize. - """ - - # After much testing, this algorithm was deemed to be the fastest. - s = '' - pack = struct.pack - while n > 0: - ### CHANGED FROM '>I' TO '> 32 - - # Strip off leading zeros. - for i in range(len(s)): - if s[i] <> '\000': - break - else: - # Only happens when n == 0. - s = '\000' - i = 0 - - s = s[i:] - - # Add back some pad bytes. This could be done more efficiently - # w.r.t. the de-padding being done above, but sigh... - if blocksize > 0 and len(s) % blocksize: - s = (blocksize - len(s) % blocksize) * '\000' + s - - return s - - -def _bytelist2long(list): - "Transform a list of characters into a list of longs." - - imax = len(list)/4 - hl = [0L] * imax - - j = 0 - i = 0 - while i < imax: - b0 = long(ord(list[j])) - b1 = (long(ord(list[j+1]))) << 8 - b2 = (long(ord(list[j+2]))) << 16 - b3 = (long(ord(list[j+3]))) << 24 - hl[i] = b0 | b1 |b2 | b3 - i = i+1 - j = j+4 - - return hl - - -def _rotateLeft(x, n): - "Rotate x (32 bit) left n bits circularly." - - return (x << n) | (x >> (32-n)) - - -# ====================================================================== -# The real MD5 meat... -# -# Implemented after "Applied Cryptography", 2nd ed., 1996, -# pp. 436-441 by Bruce Schneier. -# ====================================================================== - -# F, G, H and I are basic MD5 functions. - -def F(x, y, z): - return (x & y) | ((~x) & z) - -def G(x, y, z): - return (x & z) | (y & (~z)) - -def H(x, y, z): - return x ^ y ^ z - -def I(x, y, z): - return y ^ (x | (~z)) - - -def XX(func, a, b, c, d, x, s, ac): - """Wrapper for call distribution to functions F, G, H and I. - - This replaces functions FF, GG, HH and II from "Appl. Crypto." - Rotation is separate from addition to prevent recomputation - (now summed-up in one function). - """ - - res = 0L - res = res + a + func(b, c, d) - res = res + x - res = res + ac - res = res & 0xffffffffL - res = _rotateLeft(res, s) - res = res & 0xffffffffL - res = res + b - - return res & 0xffffffffL - - -class MD5: - "An implementation of the MD5 hash function in pure Python." - - def __init__(self): - "Initialisation." - - # Initial message length in bits(!). - self.length = 0L - self.count = [0, 0] - - # Initial empty message as a sequence of bytes (8 bit characters). - self.input = [] - - # Call a separate init function, that can be used repeatedly - # to start from scratch on the same object. - self.init() - - - def init(self): - "Initialize the message-digest and set all fields to zero." - - self.length = 0L - self.input = [] - - # Load magic initialization constants. - self.A = 0x67452301L - self.B = 0xefcdab89L - self.C = 0x98badcfeL - self.D = 0x10325476L - - - def _transform(self, inp): - """Basic MD5 step transforming the digest based on the input. - - Note that if the Mysterious Constants are arranged backwards - in little-endian order and decrypted with the DES they produce - OCCULT MESSAGES! - """ - - a, b, c, d = A, B, C, D = self.A, self.B, self.C, self.D - - # Round 1. - - S11, S12, S13, S14 = 7, 12, 17, 22 - - a = XX(F, a, b, c, d, inp[ 0], S11, 0xD76AA478L) # 1 - d = XX(F, d, a, b, c, inp[ 1], S12, 0xE8C7B756L) # 2 - c = XX(F, c, d, a, b, inp[ 2], S13, 0x242070DBL) # 3 - b = XX(F, b, c, d, a, inp[ 3], S14, 0xC1BDCEEEL) # 4 - a = XX(F, a, b, c, d, inp[ 4], S11, 0xF57C0FAFL) # 5 - d = XX(F, d, a, b, c, inp[ 5], S12, 0x4787C62AL) # 6 - c = XX(F, c, d, a, b, inp[ 6], S13, 0xA8304613L) # 7 - b = XX(F, b, c, d, a, inp[ 7], S14, 0xFD469501L) # 8 - a = XX(F, a, b, c, d, inp[ 8], S11, 0x698098D8L) # 9 - d = XX(F, d, a, b, c, inp[ 9], S12, 0x8B44F7AFL) # 10 - c = XX(F, c, d, a, b, inp[10], S13, 0xFFFF5BB1L) # 11 - b = XX(F, b, c, d, a, inp[11], S14, 0x895CD7BEL) # 12 - a = XX(F, a, b, c, d, inp[12], S11, 0x6B901122L) # 13 - d = XX(F, d, a, b, c, inp[13], S12, 0xFD987193L) # 14 - c = XX(F, c, d, a, b, inp[14], S13, 0xA679438EL) # 15 - b = XX(F, b, c, d, a, inp[15], S14, 0x49B40821L) # 16 - - # Round 2. - - S21, S22, S23, S24 = 5, 9, 14, 20 - - a = XX(G, a, b, c, d, inp[ 1], S21, 0xF61E2562L) # 17 - d = XX(G, d, a, b, c, inp[ 6], S22, 0xC040B340L) # 18 - c = XX(G, c, d, a, b, inp[11], S23, 0x265E5A51L) # 19 - b = XX(G, b, c, d, a, inp[ 0], S24, 0xE9B6C7AAL) # 20 - a = XX(G, a, b, c, d, inp[ 5], S21, 0xD62F105DL) # 21 - d = XX(G, d, a, b, c, inp[10], S22, 0x02441453L) # 22 - c = XX(G, c, d, a, b, inp[15], S23, 0xD8A1E681L) # 23 - b = XX(G, b, c, d, a, inp[ 4], S24, 0xE7D3FBC8L) # 24 - a = XX(G, a, b, c, d, inp[ 9], S21, 0x21E1CDE6L) # 25 - d = XX(G, d, a, b, c, inp[14], S22, 0xC33707D6L) # 26 - c = XX(G, c, d, a, b, inp[ 3], S23, 0xF4D50D87L) # 27 - b = XX(G, b, c, d, a, inp[ 8], S24, 0x455A14EDL) # 28 - a = XX(G, a, b, c, d, inp[13], S21, 0xA9E3E905L) # 29 - d = XX(G, d, a, b, c, inp[ 2], S22, 0xFCEFA3F8L) # 30 - c = XX(G, c, d, a, b, inp[ 7], S23, 0x676F02D9L) # 31 - b = XX(G, b, c, d, a, inp[12], S24, 0x8D2A4C8AL) # 32 - - # Round 3. - - S31, S32, S33, S34 = 4, 11, 16, 23 - - a = XX(H, a, b, c, d, inp[ 5], S31, 0xFFFA3942L) # 33 - d = XX(H, d, a, b, c, inp[ 8], S32, 0x8771F681L) # 34 - c = XX(H, c, d, a, b, inp[11], S33, 0x6D9D6122L) # 35 - b = XX(H, b, c, d, a, inp[14], S34, 0xFDE5380CL) # 36 - a = XX(H, a, b, c, d, inp[ 1], S31, 0xA4BEEA44L) # 37 - d = XX(H, d, a, b, c, inp[ 4], S32, 0x4BDECFA9L) # 38 - c = XX(H, c, d, a, b, inp[ 7], S33, 0xF6BB4B60L) # 39 - b = XX(H, b, c, d, a, inp[10], S34, 0xBEBFBC70L) # 40 - a = XX(H, a, b, c, d, inp[13], S31, 0x289B7EC6L) # 41 - d = XX(H, d, a, b, c, inp[ 0], S32, 0xEAA127FAL) # 42 - c = XX(H, c, d, a, b, inp[ 3], S33, 0xD4EF3085L) # 43 - b = XX(H, b, c, d, a, inp[ 6], S34, 0x04881D05L) # 44 - a = XX(H, a, b, c, d, inp[ 9], S31, 0xD9D4D039L) # 45 - d = XX(H, d, a, b, c, inp[12], S32, 0xE6DB99E5L) # 46 - c = XX(H, c, d, a, b, inp[15], S33, 0x1FA27CF8L) # 47 - b = XX(H, b, c, d, a, inp[ 2], S34, 0xC4AC5665L) # 48 - - # Round 4. - - S41, S42, S43, S44 = 6, 10, 15, 21 - - a = XX(I, a, b, c, d, inp[ 0], S41, 0xF4292244L) # 49 - d = XX(I, d, a, b, c, inp[ 7], S42, 0x432AFF97L) # 50 - c = XX(I, c, d, a, b, inp[14], S43, 0xAB9423A7L) # 51 - b = XX(I, b, c, d, a, inp[ 5], S44, 0xFC93A039L) # 52 - a = XX(I, a, b, c, d, inp[12], S41, 0x655B59C3L) # 53 - d = XX(I, d, a, b, c, inp[ 3], S42, 0x8F0CCC92L) # 54 - c = XX(I, c, d, a, b, inp[10], S43, 0xFFEFF47DL) # 55 - b = XX(I, b, c, d, a, inp[ 1], S44, 0x85845DD1L) # 56 - a = XX(I, a, b, c, d, inp[ 8], S41, 0x6FA87E4FL) # 57 - d = XX(I, d, a, b, c, inp[15], S42, 0xFE2CE6E0L) # 58 - c = XX(I, c, d, a, b, inp[ 6], S43, 0xA3014314L) # 59 - b = XX(I, b, c, d, a, inp[13], S44, 0x4E0811A1L) # 60 - a = XX(I, a, b, c, d, inp[ 4], S41, 0xF7537E82L) # 61 - d = XX(I, d, a, b, c, inp[11], S42, 0xBD3AF235L) # 62 - c = XX(I, c, d, a, b, inp[ 2], S43, 0x2AD7D2BBL) # 63 - b = XX(I, b, c, d, a, inp[ 9], S44, 0xEB86D391L) # 64 - - A = (A + a) & 0xffffffffL - B = (B + b) & 0xffffffffL - C = (C + c) & 0xffffffffL - D = (D + d) & 0xffffffffL - - self.A, self.B, self.C, self.D = A, B, C, D - - - # Down from here all methods follow the Python Standard Library - # API of the md5 module. - - def update(self, inBuf): - """Add to the current message. - - Update the md5 object with the string arg. Repeated calls - are equivalent to a single call with the concatenation of all - the arguments, i.e. m.update(a); m.update(b) is equivalent - to m.update(a+b). - - The hash is immediately calculated for all full blocks. The final - calculation is made in digest(). This allows us to keep an - intermediate value for the hash, so that we only need to make - minimal recalculation if we call update() to add moredata to - the hashed string. - """ - - leninBuf = long(len(inBuf)) - - # Compute number of bytes mod 64. - index = (self.count[0] >> 3) & 0x3FL - - # Update number of bits. - self.count[0] = self.count[0] + (leninBuf << 3) - if self.count[0] < (leninBuf << 3): - self.count[1] = self.count[1] + 1 - self.count[1] = self.count[1] + (leninBuf >> 29) - - partLen = 64 - index - - if leninBuf >= partLen: - self.input[index:] = list(inBuf[:partLen]) - self._transform(_bytelist2long(self.input)) - i = partLen - while i + 63 < leninBuf: - self._transform(_bytelist2long(list(inBuf[i:i+64]))) - i = i + 64 - else: - self.input = list(inBuf[i:leninBuf]) - else: - i = 0 - self.input = self.input + list(inBuf) - - - def digest(self): - """Terminate the message-digest computation and return digest. - - Return the digest of the strings passed to the update() - method so far. This is a 16-byte string which may contain - non-ASCII characters, including null bytes. - """ - - A = self.A - B = self.B - C = self.C - D = self.D - input = [] + self.input - count = [] + self.count - - index = (self.count[0] >> 3) & 0x3fL - - if index < 56: - padLen = 56 - index - else: - padLen = 120 - index - - padding = ['\200'] + ['\000'] * 63 - self.update(padding[:padLen]) - - # Append length (before padding). - bits = _bytelist2long(self.input[:56]) + count - - self._transform(bits) - - # Store state in digest. - digest = _long2bytes(self.A << 96, 16)[:4] + \ - _long2bytes(self.B << 64, 16)[4:8] + \ - _long2bytes(self.C << 32, 16)[8:12] + \ - _long2bytes(self.D, 16)[12:] - - self.A = A - self.B = B - self.C = C - self.D = D - self.input = input - self.count = count - - return digest - - - def hexdigest(self): - """Terminate and return digest in HEX form. - - Like digest() except the digest is returned as a string of - length 32, containing only hexadecimal digits. This may be - used to exchange the value safely in email or other non- - binary environments. - """ - - return ''.join(['%02x' % ord(c) for c in self.digest()]) - - def copy(self): - """Return a clone object. - - Return a copy ('clone') of the md5 object. This can be used - to efficiently compute the digests of strings that share - a common initial substring. - """ - - return copy.deepcopy(self) - - -# ====================================================================== -# Mimic Python top-level functions from standard library API -# for consistency with the md5 module of the standard library. -# ====================================================================== - -digest_size = 16 - -def new(arg=None): - """Return a new md5 object. - - If arg is present, the method call update(arg) is made. - """ - - md5 = MD5() - if arg: - md5.update(arg) - - return md5 - - -def md5(arg=None): - """Same as new(). - - For backward compatibility reasons, this is an alternative - name for the new() function. - """ - - return new(arg) Deleted: /pypy/trunk/src/pypy/appspace/pysha.py ============================================================================== --- /pypy/trunk/src/pypy/appspace/pysha.py Fri Nov 19 09:53:30 2004 +++ (empty file) @@ -1,341 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 - -"""A sample implementation of SHA-1 in pure Python. - - Framework adapted from Dinu Gherman's MD5 implementation by - J. Hall?n and L. Creighton. SHA-1 implementation based directly on - the text of the NIST standard FIPS PUB 180-1. -""" - - -__date__ = '2004-11-17' -__version__ = 0.91 # Modernised by J. Hall?n and L. Creighton for Pypy - - -import struct, copy - - -# ====================================================================== -# Bit-Manipulation helpers -# -# _long2bytes() was contributed by Barry Warsaw -# and is reused here with tiny modifications. -# ====================================================================== - -def _long2bytesBigEndian(n, blocksize=0): - """Convert a long integer to a byte string. - - If optional blocksize is given and greater than zero, pad the front - of the byte string with binary zeros so that the length is a multiple - of blocksize. - """ - - # After much testing, this algorithm was deemed to be the fastest. - s = '' - pack = struct.pack - while n > 0: - s = pack('>I', n & 0xffffffffL) + s - n = n >> 32 - - # Strip off leading zeros. - for i in range(len(s)): - if s[i] <> '\000': - break - else: - # Only happens when n == 0. - s = '\000' - i = 0 - - s = s[i:] - - # Add back some pad bytes. This could be done more efficiently - # w.r.t. the de-padding being done above, but sigh... - if blocksize > 0 and len(s) % blocksize: - s = (blocksize - len(s) % blocksize) * '\000' + s - - return s - - -def _bytelist2longBigEndian(list): - "Transform a list of characters into a list of longs." - - imax = len(list)/4 - hl = [0L] * imax - - j = 0 - i = 0 - while i < imax: - b0 = long(ord(list[j])) << 24 - b1 = long(ord(list[j+1])) << 16 - b2 = long(ord(list[j+2])) << 8 - b3 = long(ord(list[j+3])) - hl[i] = b0 | b1 | b2 | b3 - i = i+1 - j = j+4 - - return hl - - -def _rotateLeft(x, n): - "Rotate x (32 bit) left n bits circularly." - - return (x << n) | (x >> (32-n)) - - -# ====================================================================== -# The SHA transformation functions -# -# ====================================================================== - -def f0_19(B, C, D): - return (B & C) | ((~ B) & D) - -def f20_39(B, C, D): - return B ^ C ^ D - -def f40_59(B, C, D): - return (B & C) | (B & D) | (C & D) - -def f60_79(B, C, D): - return B ^ C ^ D - - -f = [f0_19, f20_39, f40_59, f60_79] - -# Constants to be used -K = [ - 0x5A827999L, # ( 0 <= t <= 19) - 0x6ED9EBA1L, # (20 <= t <= 39) - 0x8F1BBCDCL, # (40 <= t <= 59) - 0xCA62C1D6L # (60 <= t <= 79) - ] - -class MD5: - "An implementation of the MD5 hash function in pure Python." - - def __init__(self): - "Initialisation." - - # Initial message length in bits(!). - self.length = 0L - self.count = [0, 0] - - # Initial empty message as a sequence of bytes (8 bit characters). - self.input = [] - - # Call a separate init function, that can be used repeatedly - # to start from scratch on the same object. - self.init() - - - def init(self): - "Initialize the message-digest and set all fields to zero." - - self.length = 0L - self.input = [] - - # Initial 160 bit message digest (5 times 32 bit). - self.H0 = 0x67452301L - self.H1 = 0xEFCDAB89L - self.H2 = 0x98BADCFEL - self.H3 = 0x10325476L - self.H4 = 0xC3D2E1F0L - - def _transform(self, W): - - for t in range(16, 80): - W.append(_rotateLeft( - W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1) & 0xffffffffL) - - A = self.H0 - B = self.H1 - C = self.H2 - D = self.H3 - E = self.H4 - - """ - This loop was unrolled to gain about 10% in speed - for t in range(0, 80): - TEMP = _rotateLeft(A, 5) + f[t/20] + E + W[t] + K[t/20] - E = D - D = C - C = _rotateLeft(B, 30) & 0xffffffffL - B = A - A = TEMP & 0xffffffffL - """ - - for t in range(0, 20): - TEMP = _rotateLeft(A, 5) + ((B & C) | ((~ B) & D)) + E + W[t] + K[0] - E = D - D = C - C = _rotateLeft(B, 30) & 0xffffffffL - B = A - A = TEMP & 0xffffffffL - - for t in range(20, 40): - TEMP = _rotateLeft(A, 5) + (B ^ C ^ D) + E + W[t] + K[1] - E = D - D = C - C = _rotateLeft(B, 30) & 0xffffffffL - B = A - A = TEMP & 0xffffffffL - - for t in range(40, 60): - TEMP = _rotateLeft(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2] - E = D - D = C - C = _rotateLeft(B, 30) & 0xffffffffL - B = A - A = TEMP & 0xffffffffL - - for t in range(60, 80): - TEMP = _rotateLeft(A, 5) + (B ^ C ^ D) + E + W[t] + K[3] - E = D - D = C - C = _rotateLeft(B, 30) & 0xffffffffL - B = A - A = TEMP & 0xffffffffL - - - self.H0 = (self.H0 + A) & 0xffffffffL - self.H1 = (self.H1 + B) & 0xffffffffL - self.H2 = (self.H2 + C) & 0xffffffffL - self.H3 = (self.H3 + D) & 0xffffffffL - self.H4 = (self.H4 + E) & 0xffffffffL - - - # Down from here all methods follow the Python Standard Library - # API of the sha module. - - def update(self, inBuf): - """Add to the current message. - - Update the md5 object with the string arg. Repeated calls - are equivalent to a single call with the concatenation of all - the arguments, i.e. m.update(a); m.update(b) is equivalent - to m.update(a+b). - - The hash is immediately calculated for all full blocks. The final - calculation is made in digest(). It will calculate 1-2 blocks, - depending on how much padding we have to add. This allows us to - keep an intermediate value for the hash, so that we only need to - make minimal recalculation if we call update() to add more data - to the hashed string. - """ - - leninBuf = long(len(inBuf)) - - # Compute number of bytes mod 64. - index = (self.count[1] >> 3) & 0x3FL - - # Update number of bits. - self.count[1] = self.count[1] + (leninBuf << 3) - if self.count[1] < (leninBuf << 3): - self.count[0] = self.count[0] + 1 - self.count[0] = self.count[0] + (leninBuf >> 29) - - partLen = 64 - index - - if leninBuf >= partLen: - self.input[index:] = list(inBuf[:partLen]) - self._transform(_bytelist2longBigEndian(self.input)) - i = partLen - while i + 63 < leninBuf: - self._transform(_bytelist2longBigEndian(list(inBuf[i:i+64]))) - i = i + 64 - else: - self.input = list(inBuf[i:leninBuf]) - else: - i = 0 - self.input = self.input + list(inBuf) - - - def digest(self): - """Terminate the message-digest computation and return digest. - - Return the digest of the strings passed to the update() - method so far. This is a 16-byte string which may contain - non-ASCII characters, including null bytes. - """ - - H0 = self.H0 - H1 = self.H1 - H2 = self.H2 - H3 = self.H3 - H4 = self.H4 - input = [] + self.input - count = [] + self.count - - index = (self.count[1] >> 3) & 0x3fL - - if index < 56: - padLen = 56 - index - else: - padLen = 120 - index - - padding = ['\200'] + ['\000'] * 63 - self.update(padding[:padLen]) - - # Append length (before padding). - bits = _bytelist2longBigEndian(self.input[:56]) + count - - self._transform(bits) - - # Store state in digest. - digest = _long2bytesBigEndian(self.H0, 4) + \ - _long2bytesBigEndian(self.H1, 4) + \ - _long2bytesBigEndian(self.H2, 4) + \ - _long2bytesBigEndian(self.H3, 4) + \ - _long2bytesBigEndian(self.H4, 4) - - self.H0 = H0 - self.H1 = H1 - self.H2 = H2 - self.H3 = H3 - self.H4 = H4 - self.input = input - self.count = count - - return digest - - - def hexdigest(self): - """Terminate and return digest in HEX form. - - Like digest() except the digest is returned as a string of - length 32, containing only hexadecimal digits. This may be - used to exchange the value safely in email or other non- - binary environments. - """ - return ''.join(['%02x' % ord(c) for c in self.digest()]) - - def copy(self): - """Return a clone object. - - Return a copy ('clone') of the md5 object. This can be used - to efficiently compute the digests of strings that share - a common initial substring. - """ - - return copy.deepcopy(self) - - -# ====================================================================== -# Mimic Python top-level functions from standard library API -# for consistency with the md5 module of the standard library. -# ====================================================================== - -digest_size = 16 - -def new(arg=None): - """Return a new md5 object. - - If arg is present, the method call update(arg) is made. - """ - - md5 = MD5() - if arg: - md5.update(arg) - - return md5 Modified: pypy/trunk/src/pypy/appspace/test/test_md5.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_md5.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_md5.py Fri Nov 19 09:53:30 2004 @@ -4,9 +4,10 @@ 160 sec. per MB of data on a 233 MHz Intel Pentium CPU. """ +import autopath import string, unittest -import md5 # Python's implementation in C. -import pymd5 # The pure Python implementation. +import md5 # CPython's implementation in C. +from pypy.appspace import md5 as pymd5 # The pure Python implementation. # Helpers... Modified: pypy/trunk/src/pypy/appspace/test/test_sha.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_sha.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_sha.py Fri Nov 19 09:53:30 2004 @@ -4,7 +4,8 @@ # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm -import pysha as sha +import autopath +from pypy.appspace import sha import unittest class SHATestCase(unittest.TestCase): @@ -20,7 +21,7 @@ self.check("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1") - def test_case_3(self): + def disabled_too_slow_test_case_3(self): self.check("a" * 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f") Modified: pypy/trunk/src/pypy/module/sysinterp.py ============================================================================== --- pypy/trunk/src/pypy/module/sysinterp.py (original) +++ pypy/trunk/src/pypy/module/sysinterp.py Fri Nov 19 09:53:30 2004 @@ -38,7 +38,7 @@ # The following built-in modules are not written in PyPy, so we # steal them from Python. for fn in ['posix', 'nt', 'os2', 'mac', 'ce', 'riscos', - 'itertools', 'math', '_codecs', 'md5', 'sha', + 'itertools', 'math', '_codecs', '_random', '_sre', 'time', '_socket', 'errno', 'marshal', 'struct', 'binascii', 'parser']: if fn not in builtin_modules: From arigo at codespeak.net Fri Nov 19 10:15:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 10:15:34 +0100 (MET) Subject: [pypy-svn] r7413 - in pypy/trunk/src/pypy: annotation objspace/std Message-ID: <20041119091534.218A25B182@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 10:15:33 2004 New Revision: 7413 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/objspace/std/dictobject.py Log: Treats subclasses of ints or long (e.g. r_int and r_uint, respectively) as int in builtin_isinstance(). Put an assert back in in dictobject.py. Fixed initialization of Entry.hash. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri Nov 19 10:15:33 2004 @@ -37,6 +37,8 @@ # XXX simple case only if s_type.is_constant(): typ = s_type.const + if issubclass(typ, (int, long)): + typ = int if s_obj.is_constant(): return immutablevalue(isinstance(s_obj.const, typ)) elif issubclass(s_obj.knowntype, typ): Modified: pypy/trunk/src/pypy/objspace/std/dictobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/dictobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/dictobject.py Fri Nov 19 10:15:33 2004 @@ -14,7 +14,7 @@ class Entry: def __init__(self): - self.hash = 0 + self.hash = r_uint(0) self.w_key = None self.w_value = None def __repr__(self): @@ -66,7 +66,7 @@ return [entry for entry in self.data if entry.w_value is not None] def lookdict(self, lookup_hash, w_lookup): -# assert isinstance(lookup_hash, r_uint) + assert isinstance(lookup_hash, r_uint) space = self.space i = lookup_hash % len(self.data) From arigo at codespeak.net Fri Nov 19 10:44:06 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 10:44:06 +0100 (MET) Subject: [pypy-svn] r7414 - in pypy/trunk/src: goal pypy/translator/test pypy/translator/tool Message-ID: <20041119094406.169665B180@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 10:44:05 2004 New Revision: 7414 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/translator/test/test_ctrans.py pypy/trunk/src/pypy/translator/test/test_pyrextrans.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: Hack the -O optimization flags for the compilation of generated C code by distutils (but only when running tests or translate_pypy). Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 10:44:05 2004 @@ -16,6 +16,10 @@ from pypy.annotation import model as annmodel from pypy.tool.cache import Cache +# XXX this tries to make compiling faster +from pypy.translator.tool import buildpyxmodule +buildpyxmodule.enable_fast_compilation() + #from buildcache import buildcache # __________ Entry point __________ Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Fri Nov 19 10:44:05 2004 @@ -8,6 +8,11 @@ from pypy.translator.test import snippet +# XXX this tries to make compiling faster for full-scale testing +from pypy.translator.tool import buildpyxmodule +buildpyxmodule.enable_fast_compilation() + + class NoTypeCGenTestCase(testit.IntTestCase): def setUp(self): Modified: pypy/trunk/src/pypy/translator/test/test_pyrextrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_pyrextrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_pyrextrans.py Fri Nov 19 10:44:05 2004 @@ -8,6 +8,11 @@ from pypy.translator.test import snippet +# XXX this tries to make compiling faster for full-scale testing +from pypy.translator.tool import buildpyxmodule +buildpyxmodule.enable_fast_compilation() + + class NoTypePyrexGenTestCase(testit.IntTestCase): def setUp(self): Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Fri Nov 19 10:44:05 2004 @@ -6,7 +6,7 @@ from py import path from pypy.translator.genpyrex import GenPyrex -import os, sys, inspect +import os, sys, inspect, re from pypy.translator.tool import stdoutcapture debug = 0 @@ -25,6 +25,12 @@ #print "made module", module return module +def enable_fast_compilation(): + from distutils import sysconfig + opt = sysconfig.get_config_vars()['OPT'] + opt = re.sub('-O.', '-O0', opt) + sysconfig.get_config_vars()['OPT'] = opt + def make_module_from_c(cfile): from distutils.core import setup from distutils.extension import Extension From hpk at codespeak.net Fri Nov 19 11:01:00 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 11:01:00 +0100 (MET) Subject: [pypy-svn] r7415 - pypy/trunk/src/pypy/translator Message-ID: <20041119100100.9F3AB5B18A@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 11:01:00 2004 New Revision: 7415 Modified: pypy/trunk/src/pypy/translator/transform.py Log: improve the removal of dead operations, it now checks if an operation returns a SomeImpossibleValue() which is - as Armin said - meant to indicate that an operation has side effects. IOW analysis of operations (like the one for setattr or list's method_extend) should return SomeImpossibleValue() to signal that it has side effects and thus cannot be removed even if the result is not used anywhere. In the future, we probably want to mark operations as having side effects more directly ... Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Fri Nov 19 11:01:00 2004 @@ -160,10 +160,11 @@ if op.opname in CanRemove: del block.operations[i] elif op.opname == 'simple_call': - if op.args and isinstance(op.args[0], Constant): - func = op.args[0].value - if func is isinstance: - del block.operations[i] + # XXX if the result is SomeImpossibleValue() + # we assume the operation has side effects + # and don't delete it + if op.result != annmodel.SomeImpossibleValue(): + del block.operations[i] # look for output variables never used # warning: this must be completely done *before* we attempt to From hpk at codespeak.net Fri Nov 19 11:28:04 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 11:28:04 +0100 (MET) Subject: [pypy-svn] r7416 - pypy/trunk/src/pypy/annotation Message-ID: <20041119102804.353B35B187@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 11:28:03 2004 New Revision: 7416 Modified: pypy/trunk/src/pypy/annotation/model.py Log: make SomePBC the class name and SomePrebuiltConstant just an alias (it really is too long otherwise ...) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 11:28:03 2004 @@ -176,13 +176,14 @@ # self.meths = meths # map {python_function: classdef} -class SomePrebuiltConstant(SomeObject): +class SomePBC(SomeObject): """Stands for a global user instance, built prior to the analysis, or a set of such instances.""" def __init__(self, prebuiltinstances): self.prebuiltinstances = prebuiltinstances self.knowntype = reduce(commonbase, [x.__class__ for x in prebuiltinstances]) +SomePrebuiltConstant = SomePBC class SomeImpossibleValue(SomeObject): From arigo at codespeak.net Fri Nov 19 11:33:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 11:33:45 +0100 (MET) Subject: [pypy-svn] r7417 - pypy/trunk/src/pypy/translator/test Message-ID: <20041119103345.054F65B18C@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 11:33:45 2004 New Revision: 7417 Modified: pypy/trunk/src/pypy/translator/test/test_sourcegen.py Log: This file compiles, too. Modified: pypy/trunk/src/pypy/translator/test/test_sourcegen.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_sourcegen.py (original) +++ pypy/trunk/src/pypy/translator/test/test_sourcegen.py Fri Nov 19 11:33:45 2004 @@ -9,6 +9,11 @@ from pypy.translator.tool.buildpyxmodule import make_module_from_pyxstring #from pypy.translator.test.make_dot import make_ps +# XXX this tries to make compiling faster for full-scale testing +from pypy.translator.tool import buildpyxmodule +buildpyxmodule.enable_fast_compilation() + + class SourceGenTestCase(testit.IntTestCase): def test_simple_func(self): """ From mgedmin at codespeak.net Fri Nov 19 11:39:48 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 11:39:48 +0100 (MET) Subject: [pypy-svn] r7418 - pypy/trunk/src/goal Message-ID: <20041119103948.645A65B18D@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 11:39:47 2004 New Revision: 7418 Modified: pypy/trunk/src/goal/translate_pypy.py Log: List all functions that have SomeObject in their signature. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 11:39:47 2004 @@ -15,6 +15,7 @@ from pypy.translator.translator import Translator from pypy.annotation import model as annmodel from pypy.tool.cache import Cache +from pypy.annotation.model import SomeObject # XXX this tries to make compiling faster from pypy.translator.tool import buildpyxmodule @@ -41,6 +42,43 @@ a = t.annotate([]) a.simplify() + count_someobjects(a) + +def count_someobjects(annotator): + translator = annotator.translator + + def is_someobject(var): + try: + return annotator.binding(var).__class__ == SomeObject + except KeyError: + return False + + def short_binding(var): + binding = annotator.binding(var) + if binding.is_constant(): + return 'const %s' % binding.__class__.__name__ + else: + return binding.__class__.__name__ + + header = True + for func, graph in translator.flowgraphs.items(): + unknown_input_args = len(filter(is_someobject, graph.getargs())) + unknown_return_value = is_someobject(graph.getreturnvar()) + if unknown_input_args or unknown_return_value: + if header: + header = False + print "=" * 70 + print "Functions that have SomeObject in their signature" + print "=" * 70 + print ("%(name)s(%(args)s) -> %(result)s\n" + "%(filename)s:%(lineno)s\n" + % {'name': graph.name, + 'filename': func.func_globals.get('__name__', '?'), + 'lineno': func.func_code.co_firstlineno, + 'args': ', '.join(map(short_binding, graph.getargs())), + 'result': short_binding(graph.getreturnvar())}) + + if __name__ == '__main__': options = {'-text': False, From mwh at codespeak.net Fri Nov 19 11:52:37 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 11:52:37 +0100 (MET) Subject: [pypy-svn] r7419 - pypy/trunk/src/pypy/annotation Message-ID: <20041119105237.E0ED75B18F@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 11:52:37 2004 New Revision: 7419 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: Comment tweakery. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri Nov 19 11:52:37 2004 @@ -34,9 +34,9 @@ return SomeChar() def builtin_isinstance(s_obj, s_type): - # XXX simple case only if s_type.is_constant(): typ = s_type.const + # XXX bit of a hack: if issubclass(typ, (int, long)): typ = int if s_obj.is_constant(): From mwh at codespeak.net Fri Nov 19 11:56:42 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 11:56:42 +0100 (MET) Subject: [pypy-svn] r7420 - in pypy/trunk/src/pypy: annotation objspace/std tool Message-ID: <20041119105642.B68F35B1A0@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 11:56:42 2004 New Revision: 7420 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/tool/cache.py Log: Tweaks to specialization: if present, the attribute must be one of a known set of strings, currently "location" or "argtypes". Also, the attribute is renamed to "_specialize_" -- a more special name is indicated because we're about to make it mean something on classes... Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 11:56:42 2004 @@ -163,15 +163,17 @@ func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? - x = getattr(func, 'specialize', False) - if x: + x = getattr(func, '_specialize_', False) + if x: if x == 'argtypes': key = "_".join([arg.__class__.__name__ for arg in args]) name = func.__name__+'_'+key func = self.specialize_by_key(func, key, name) - else: + elif x == "location": # fully specialize: create one version per call position func = self.specialize_by_key(func, self.position_key) + else: + raise Exception, "unsupported specialization type '%s'"%(x,) elif func.func_code.co_flags & CO_VARARGS: # calls to *arg functions: create one version per number of args Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Fri Nov 19 11:56:42 2004 @@ -262,7 +262,7 @@ return self.gettypeobject(ft.typedef) ft = self.loadfromcache(type(x), fake_type, self._faketypecache) return ft(self, x) - wrap.specialize = "argtypes" + wrap._specialize_ = "argtypes" def newint(self, intval): return W_IntObject(self, intval) Modified: pypy/trunk/src/pypy/tool/cache.py ============================================================================== --- pypy/trunk/src/pypy/tool/cache.py (original) +++ pypy/trunk/src/pypy/tool/cache.py Fri Nov 19 11:56:42 2004 @@ -30,7 +30,7 @@ return self.setdefault(key, builder(key, space)) # note to annotator: we want loadfromcache() to be # specialized for the different cache types - getorbuild.specialize = True + getorbuild._specialize_ = "location" def freeze(self): del self.frozen From hpk at codespeak.net Fri Nov 19 11:57:37 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 11:57:37 +0100 (MET) Subject: [pypy-svn] r7421 - pypy/trunk/src/goal Message-ID: <20041119105737.39F7A5B1B9@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 11:57:36 2004 New Revision: 7421 Modified: pypy/trunk/src/goal/translate_pypy.py Log: print a percentage summary for how many functions contain SomeObjects in their signature Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 11:57:36 2004 @@ -61,6 +61,7 @@ return binding.__class__.__name__ header = True + num = someobjnum = 0 for func, graph in translator.flowgraphs.items(): unknown_input_args = len(filter(is_someobject, graph.getargs())) unknown_return_value = is_someobject(graph.getreturnvar()) @@ -77,6 +78,14 @@ 'lineno': func.func_code.co_firstlineno, 'args': ', '.join(map(short_binding, graph.getargs())), 'result': short_binding(graph.getreturnvar())}) + someobjnum += 1 + num += 1 + print "=" * 70 + percent = int(num and (100.0*someobjnum / num) or 0) + print "somobjectness: %2d percent" % (percent) + print "(%d out of %d functions get or return SomeObjects" % ( + someobjnum, num) + print "=" * 70 if __name__ == '__main__': @@ -170,3 +179,4 @@ debug(True) else: debug(False) + From mgedmin at codespeak.net Fri Nov 19 12:02:17 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 12:02:17 +0100 (MET) Subject: [pypy-svn] r7422 - in pypy/trunk/src: goal pypy/translator/tool/pygame Message-ID: <20041119110217.5BA0B5B1AA@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 12:02:16 2004 New Revision: 7422 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Added --mark-some-objects option to translate_pypy.py to find, list and highlight in the flow graph all functions that receive or return SomeObject()s. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 12:02:16 2004 @@ -8,6 +8,8 @@ -no-c Don't generate the C code -c Generate the C code, but don't compile it -o Generate and compile the C code, but don't run it + --mark-some-objects + Mark all functions that have SomeObject in their signature. """ import autopath, sys, threading, pdb from pypy.objspace.std.objspace import StdObjSpace, W_Object @@ -42,10 +44,14 @@ a = t.annotate([]) a.simplify() - count_someobjects(a) + if options['--mark-some-objects']: + find_someobjects(a) -def count_someobjects(annotator): + +def find_someobjects(annotator): + """Find all functions in that have SomeObject in their signature.""" translator = annotator.translator + translator.highlight_functions = {} def is_someobject(var): try: @@ -61,8 +67,11 @@ return binding.__class__.__name__ header = True + items = [(graph.name, func, graph) + for func, graph in translator.flowgraphs.items()] + items.sort() num = someobjnum = 0 - for func, graph in translator.flowgraphs.items(): + for graphname, func, graph in items: unknown_input_args = len(filter(is_someobject, graph.getargs())) unknown_return_value = is_someobject(graph.getreturnvar()) if unknown_input_args or unknown_return_value: @@ -71,6 +80,7 @@ print "=" * 70 print "Functions that have SomeObject in their signature" print "=" * 70 + translator.highlight_functions[func] = True print ("%(name)s(%(args)s) -> %(result)s\n" "%(filename)s:%(lineno)s\n" % {'name': graph.name, @@ -94,6 +104,7 @@ '-no-c': False, '-c': False, '-o': False, + '--mark-some-objects': False, } for arg in sys.argv[1:]: if arg in ('-h', '--help'): Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Fri Nov 19 12:02:16 2004 @@ -160,11 +160,16 @@ # show the call graph functions = translator.functions + highlight_functions = getattr(translator, 'highlight_functions', {}) # XXX dotgen.emit_node('entry', fillcolor="green", shape="octagon", label="Translator\\nEntry Point") for func in functions: data = self.labelof(func, func.func_name) - dotgen.emit_node(nameof(func), label=data, shape="box") + if func in highlight_functions: + kw = {'fillcolor': '#ffcccc'} + else: + kw = {} + dotgen.emit_node(nameof(func), label=data, shape="box", **kw) dotgen.emit_edge('entry', nameof(functions[0]), color="green") for f1, f2 in translator.callgraph.itervalues(): dotgen.emit_edge(nameof(f1), nameof(f2)) From mwh at codespeak.net Fri Nov 19 12:02:38 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 12:02:38 +0100 (MET) Subject: [pypy-svn] r7423 - pypy/trunk/src/pypy/interpreter Message-ID: <20041119110238.BBC585B1DF@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 12:02:38 2004 New Revision: 7423 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py Log: One more specialize -> _specialize_ spotted by Samuele. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Fri Nov 19 12:02:38 2004 @@ -92,7 +92,7 @@ def loadfromcache(self, key, builder, cache): return cache.getorbuild(key, builder, self) - loadfromcache.specialize = True + loadfromcache._specialize_ = "location" def getexecutioncontext(self): "Return what we consider to be the active execution context." From arigo at codespeak.net Fri Nov 19 12:04:06 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 12:04:06 +0100 (MET) Subject: [pypy-svn] r7424 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041119110406.B3AC95B1DE@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 12:04:06 2004 New Revision: 7424 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Added a few key alternatives when the original ones are not available for non-US keyboards (e.g. a symbol being actually shift-something-else prevents Pygame from interpreting it correctly). Also provided alternatives when there is no obvious conflict. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Fri Nov 19 12:04:06 2004 @@ -14,7 +14,7 @@ if sys.platform == 'darwin': PMETA = 'lmeta', 'rmeta' else: - PMETA = 'lalt', 'ralt' + PMETA = 'lalt', 'ralt', 'lctrl', 'rctrl' METAKEYS['meta'] = PMETA METAKEYS['shift'] = 'lshift', 'rshift' @@ -72,10 +72,17 @@ KEYS = { 'meta -' : ('zoom', 0.5), + '-' : ('zoom', 0.5), 'meta plus' : ('zoom', 2.0), + 'plus' : ('zoom', 2.0), + 'meta .' : ('zoom', 2.0), # '+' is shift-1 on my keyboard + '.' : ('zoom', 2.0), 'meta 0' : 'zoom_actual_size', + '0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', + '1' : 'zoom_to_fit', 'meta quit' : 'quit', + 'quit' : 'quit', 'escape' : 'quit', 'meta right' : 'layout_forward', 'meta left': 'layout_back', @@ -83,6 +90,7 @@ 'backspace' : 'layout_back', 'f': 'search', '/': 'search', + 'shift 7': 'search', # '/' is shift-7 on my keyboard 'n': 'find_next', 'left' : ('pan', (-1, 0)), 'right' : ('pan', (1, 0)), @@ -100,7 +108,7 @@ Key bindings: Meta - Zoom out - Meta + Zoom in + Meta + or . Zoom in Meta 0 Actual size Meta 1 Zoom to fit From bob at codespeak.net Fri Nov 19 12:18:54 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 12:18:54 +0100 (MET) Subject: [pypy-svn] r7426 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041119111854.26DBD5B1F9@thoth.codespeak.net> Author: bob Date: Fri Nov 19 12:18:53 2004 New Revision: 7426 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: clean up the key bindings slightly use absolute imports so it works with autopath if you run one as __main__ Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Fri Nov 19 12:18:53 2004 @@ -65,7 +65,7 @@ self.links = {} def display(self): - from graphdisplay import GraphDisplay + from pypy.tool.translator.pygame.graphdisplay import GraphDisplay GraphDisplay(self).run() class Node: Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Fri Nov 19 12:18:53 2004 @@ -1,6 +1,6 @@ import autopath import inspect -from drawgraph import GraphLayout +from pypy.translator.tool.pygame.drawgraph import GraphLayout from pypy.translator.tool.make_dot import DotGen from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS from pypy.annotation import model, factory @@ -234,7 +234,7 @@ if __name__ == '__main__': from pypy.translator.translator import Translator from pypy.translator.test import snippet - from graphdisplay import GraphDisplay + from pypy.translator.tool.pygame.graphdisplay import GraphDisplay t = Translator(snippet.powerset) #t.simplify() Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Fri Nov 19 12:18:53 2004 @@ -3,7 +3,7 @@ import os, time, sys import pygame from pygame.locals import * -from drawgraph import GraphRenderer +from pypy.translator.tool.pygame.drawgraph import GraphRenderer METAKEYS = dict([ @@ -24,8 +24,8 @@ for ident in dir(pygame.locals) if ident.startswith('K_') ]) -KEYS['plus'] = ('=', '+') -KEYS['quit'] = ('q', 'f4') +KEYS['plus'] = ('=', '+', '.') +KEYS['quit'] = ('q', 'f4', 'escape') def GET_KEY(key): k = KEYS.get(key) @@ -75,15 +75,12 @@ '-' : ('zoom', 0.5), 'meta plus' : ('zoom', 2.0), 'plus' : ('zoom', 2.0), - 'meta .' : ('zoom', 2.0), # '+' is shift-1 on my keyboard - '.' : ('zoom', 2.0), 'meta 0' : 'zoom_actual_size', '0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', '1' : 'zoom_to_fit', 'meta quit' : 'quit', 'quit' : 'quit', - 'escape' : 'quit', 'meta right' : 'layout_forward', 'meta left': 'layout_back', 'p' : 'layout_back', From hpk at codespeak.net Fri Nov 19 12:23:35 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 12:23:35 +0100 (MET) Subject: [pypy-svn] r7427 - pypy/trunk/src/pypy/translator Message-ID: <20041119112335.C9BE55B207@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 12:23:35 2004 New Revision: 7427 Modified: pypy/trunk/src/pypy/translator/transform.py Log: revert the previous detection of side-effects by checking for SomeImpossibleValue() because this isn't safe at all (consider l.pop() or other operations of user defined classes ...) Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Fri Nov 19 12:23:35 2004 @@ -160,12 +160,14 @@ if op.opname in CanRemove: del block.operations[i] elif op.opname == 'simple_call': - # XXX if the result is SomeImpossibleValue() - # we assume the operation has side effects - # and don't delete it - if op.result != annmodel.SomeImpossibleValue(): - del block.operations[i] - + # XXX we want to have a more effective and safe + # way to check if this operation has side effects + # ... + if op.args and isinstance(op.args[0], Constant): + func = op.args[0].value + if func is isinstance: + del block.operations[i] + # look for output variables never used # warning: this must be completely done *before* we attempt to # remove the corresponding variables from block.inputargs! From arigo at codespeak.net Fri Nov 19 12:33:33 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 12:33:33 +0100 (MET) Subject: [pypy-svn] r7428 - pypy/trunk/src/pypy/annotation Message-ID: <20041119113333.428F65B23D@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 12:33:32 2004 New Revision: 7428 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Be just a little bit smarter about the result of dict.__getitem__. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Fri Nov 19 12:33:32 2004 @@ -210,7 +210,7 @@ if obj2.is_constant(): return dic1.items.get(obj2.const, SomeImpossibleValue()) else: - return SomeObject() + return unionof(*dic1.items.values()) def setitem((dic1, obj2), s_value): assert obj2.is_constant() From arigo at codespeak.net Fri Nov 19 12:34:52 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 12:34:52 +0100 (MET) Subject: [pypy-svn] r7429 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/std tool tool/test Message-ID: <20041119113452.A3DEF5B23E@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 12:34:52 2004 New Revision: 7429 Modified: pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/pycode.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/tool/cache.py pypy/trunk/src/pypy/tool/test/test_cache.py Log: Modified the Cache class to no longer be a subclass of dict, not exporting a dict-like interface any longer. Updated the rest of the code accordingly. Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Fri Nov 19 12:34:52 2004 @@ -202,9 +202,9 @@ cache = self.getcache(space) for value in self.staticglobals.itervalues(): if isinstance(value, Gateway): - if value in cache: + if value in cache.content: # yes, we share its w_globals - fn = cache[value] + fn = cache.content[value] w_globals = fn.w_func_globals break else: @@ -218,11 +218,11 @@ def _build_function(self, space, w_globals): cache = self.getcache(space) try: - return cache[self] + return cache.content[self] except KeyError: defs = self.getdefaults(space) # needs to be implemented by subclass fn = Function(space, self.code, w_globals, defs, forcename = self.name) - cache[self] = fn + cache.content[self] = fn return fn def get_method(self, obj): Modified: pypy/trunk/src/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pycode.py (original) +++ pypy/trunk/src/pypy/interpreter/pycode.py Fri Nov 19 12:34:52 2004 @@ -131,6 +131,9 @@ code.co_cellvars = space.unwrap(w_cellvars) return space.wrap(code) +def _really_enhanceclass(key, stuff): + return type("Mixed", key, {}) + def enhanceclass(baseclass, newclass, cache=Cache()): # this is a bit too dynamic for RPython, but it looks nice # and I assume that we can easily change it into a static @@ -138,11 +141,5 @@ if issubclass(newclass, baseclass): return newclass else: - try: - return cache[baseclass, newclass] - except KeyError: - assert not cache.frozen - class Mixed(newclass, baseclass): - pass - cache[baseclass, newclass] = Mixed - return Mixed + return cache.getorbuild((newclass, baseclass), + _really_enhanceclass, None) Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Fri Nov 19 12:34:52 2004 @@ -31,20 +31,19 @@ #self.make_sys() def loadfromcache(self, key, builder, cache): - try: - return cache[key] - except KeyError: - # this method is overloaded to allow the space to switch to - # "concrete mode" when building the object that goes into - # the cache. In concrete mode, only Constants are allowed. + # when populating the caches, the flow space switches to + # "concrete mode". In this mode, only Constants are allowed + # and no SpaceOperation is recorded. + def my_builder(key, stuff): previous_ops = self.executioncontext.crnt_ops self.executioncontext.crnt_ops = flowcontext.ConcreteNoOp() self.concrete_mode += 1 try: - return cache.setdefault(key, builder(key, self)) + return builder(key, stuff) finally: self.executioncontext.crnt_ops = previous_ops self.concrete_mode -= 1 + return super(FlowObjSpace, self).loadfromcache(key, my_builder, cache) def newdict(self, items_w): if self.concrete_mode: Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Fri Nov 19 12:34:52 2004 @@ -34,8 +34,8 @@ def fake_type(cpy_type, ignored=None): assert type(cpy_type) is type - if cpy_type in _fake_type_cache: - return _fake_type_cache[cpy_type] + if cpy_type in _fake_type_cache.content: + return _fake_type_cache.content[cpy_type] assert not _fake_type_cache.frozen print 'faking %r'%(cpy_type,) kw = {} @@ -70,7 +70,7 @@ return w_obj.val StdObjSpace.unwrap.register(fake_unwrap, W_Fake) W_Fake.typedef.fakedcpytype = cpy_type - _fake_type_cache[cpy_type] = W_Fake + _fake_type_cache.content[cpy_type] = W_Fake return W_Fake # ____________________________________________________________ @@ -105,6 +105,6 @@ def fake_builtin_callable(space, val): return Function(space, CPythonFakeCode(val)) -_fake_type_cache[type(len)] = fake_builtin_callable -_fake_type_cache[type(list.append)] = fake_builtin_callable -_fake_type_cache[type(type(None).__repr__)] = fake_builtin_callable +_fake_type_cache.content[type(len)] = fake_builtin_callable +_fake_type_cache.content[type(list.append)] = fake_builtin_callable +_fake_type_cache.content[type(type(None).__repr__)] = fake_builtin_callable Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Fri Nov 19 12:34:52 2004 @@ -74,20 +74,20 @@ self.cache_table.clear() self.compilation_cache_table.clear() self.cache_delegator_key = delegate.key + return self.cache_table.getorbuild(argclasses, + self.do_compile_calllist, + delegate) + + def do_compile_calllist(self, argclasses, delegate): + calllist = [] + self.internal_buildcalllist(argclasses, delegate, calllist) + calllist = tuple(calllist) try: - return self.cache_table[argclasses] + result = self.compilation_cache_table[calllist] except KeyError: - assert not self.cache_table.frozen - calllist = [] - self.internal_buildcalllist(argclasses, delegate, calllist) - calllist = tuple(calllist) - try: - result = self.compilation_cache_table[calllist] - except KeyError: - result = self.internal_compilecalllist(calllist) - self.compilation_cache_table[calllist] = result - self.cache_table[argclasses] = result - return result + result = self.internal_compilecalllist(calllist) + self.compilation_cache_table[calllist] = result + return result def internal_compilecalllist(self, calllist): source, glob = self.internal_sourcecalllist(calllist) Modified: pypy/trunk/src/pypy/tool/cache.py ============================================================================== --- pypy/trunk/src/pypy/tool/cache.py (original) +++ pypy/trunk/src/pypy/tool/cache.py Fri Nov 19 12:34:52 2004 @@ -1,33 +1,31 @@ -class basecache(dict): - pass - # hacks += 1 -class Cache(dict): +class Cache: frozen = True - def __init__(self, *args): + def __init__(self): + self.content = {} self.frozen = False - dict.__init__(self, *args) - for x in ('__setitem__', '__delitem__', 'setdefault', 'update', - 'pop', 'popitem', 'clear'): - l=["def %s(self, *args):", - " assert not self.frozen, 'cache already frozen'", - " return dict.%s(self, *args)"] - exec "\n".join(l) % (x,x) - def __hash__(self): if not self.frozen: raise TypeError, "cannot get hash of un-frozen cache" - return id(self) + return id(self) + + def clear(self): + if self.frozen: + raise TypeError, "cannot clear frozen cache" + self.content.clear() - def getorbuild(self, key, builder, space): + def getorbuild(self, key, builder, stuff): try: - return self[key] + return self.content[key] except KeyError: assert not self.frozen, "cannot build %r, cache already frozen" % key - return self.setdefault(key, builder(key, space)) + result = builder(key, stuff) + #assert key not in self.content, "things messed up" + self.content[key] = result + return result # note to annotator: we want loadfromcache() to be # specialized for the different cache types getorbuild._specialize_ = "location" Modified: pypy/trunk/src/pypy/tool/test/test_cache.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/test_cache.py (original) +++ pypy/trunk/src/pypy/tool/test/test_cache.py Fri Nov 19 12:34:52 2004 @@ -5,13 +5,18 @@ class TestCache(unittest.TestCase): def test_getorbuild(self): cache = Cache() - cache.getorbuild(1, lambda k,s: 42, None) - assert 1 in cache - assert cache[1] == 42 - assert cache.getorbuild(1, lambda k,s: 44, None) == 42 + assert cache.getorbuild(1, lambda k,s: 42, None) == 42 + assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 42 self.assertRaises(TypeError, hash, cache) + cache.clear() + assert cache.getorbuild(1, lambda k,s: 44, None) == 44 + assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 44 cache.freeze() - hash(cache) + hash(cache) + assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 44 + self.assertRaises(TypeError, cache.clear) + self.assertRaises(AssertionError, cache.getorbuild, + 2, lambda k,s: self.fail(), 4) if __name__ == '__main__': unittest.main() From mwh at codespeak.net Fri Nov 19 12:40:01 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 12:40:01 +0100 (MET) Subject: [pypy-svn] r7430 - pypy/trunk/src/pypy/annotation Message-ID: <20041119114001.3AA645B209@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 12:40:00 2004 New Revision: 7430 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: The start of support for specializing classes. Not finished, at all -- you'll get an assert if you try to use it :) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 12:40:00 2004 @@ -41,7 +41,7 @@ self.userclasses = {} # map classes to ClassDefs self.userclasseslist = []# userclasses.keys() in creation order self.attrs_read_from_constants = {} - self.cachespecializedfunctions = {} + self.cachespecializations = {} def enter(self, position_key): """Start of an operation. @@ -143,6 +143,14 @@ if isinstance(func, (type, ClassType)) and \ func.__module__ != '__builtin__': cls = func + x = getattr(cls, "_specialize_", False) + if x: + if x == "location": + cls = self.specialize_by_key(cls, self.position_key) + else: + raise Exception, \ + "unsupported specialization type '%s'"%(x,) + classdef = self.bookkeeper.getclassdef(cls) classdef.instancefactories[self] = True s_instance = SomeInstance(classdef) @@ -182,20 +190,26 @@ len(args))) return self.bookkeeper.annotator.recursivecall(func, self, *args) - def specialize_by_key(self, func, key, name=None): - key = func, key + def specialize_by_key(self, thing, key, name=None): + key = thing, key try: - func = self.bookkeeper.cachespecializedfunctions[key] + thing = self.bookkeeper.cachespecializations[key] except KeyError: - # XXX XXX XXX HAAAAAAAAAAAACK - self.bookkeeper.annotator.translator.getflowgraph(func) - func = new.function(func.func_code, - func.func_globals, - name or func.func_name, - func.func_defaults, - func.func_closure) - self.bookkeeper.cachespecializedfunctions[key] = func - return func + if isinstance(thing, FunctionType): + # XXX XXX XXX HAAAAAAAAAAAACK + self.bookkeeper.annotator.translator.getflowgraph(thing) + thing = new.function(thing.func_code, + thing.func_globals, + name or thing.func_name, + thing.func_defaults, + thing.func_closure) + elif isinstance(thing, (type, ClassType)): + assert not "not working yet" + thing = type(thing)(name or thing.__name__, (thing,)) + else: + raise Exception, "specializing %r?? why??"%thing + self.bookkeeper.cachespecializations[key] = thing + return thing class ClassDef: "Wraps a user class." From arigo at codespeak.net Fri Nov 19 12:47:06 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 12:47:06 +0100 (MET) Subject: [pypy-svn] r7431 - pypy/trunk/src/pypy/translator Message-ID: <20041119114706.13D715B252@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 12:47:05 2004 New Revision: 7431 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: - generating constant dictionaries with non-string keys. - fixed a typecast warning in the macros. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 12:47:05 2004 @@ -124,7 +124,7 @@ (PyObject_SetAttrString(t, attr, value) >= 0) #define SETUP_INSTANCE(i, cls) \ - (i = PyType_GenericAlloc(cls, 0)) + (i = PyType_GenericAlloc((PyTypeObject *)cls, 0)) /* we need a subclass of 'builtin_function_or_method' which can be used as methods: builtin function objects that can be bound on instances */ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 12:47:05 2004 @@ -293,9 +293,14 @@ name = self.uniquename('g%ddict' % len(dic)) def initdict(): for k in dic: - assert type(k) is str, "can only dump dicts with string keys" - yield '\tINITCHK(PyDict_SetItemString(%s, "%s", %s) >= 0)'%( - name, k, self.nameof(dic[k])) + if type(k) is str: + yield ('\tINITCHK(PyDict_SetItemString' + '(%s, "%s", %s) >= 0)'%( + name, k, self.nameof(dic[k]))) + else: + yield ('\tINITCHK(PyDict_SetItem' + '(%s, %s, %s) >= 0)'%( + name, self.nameof(k), self.nameof(dic[k]))) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) self.latercode.append(initdict()) From bob at codespeak.net Fri Nov 19 12:48:21 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 12:48:21 +0100 (MET) Subject: [pypy-svn] r7432 - in pypy/trunk/src/pypy: annotation/test appspace appspace/test interpreter interpreter/test module/test objspace/flow/test objspace/std objspace/std/test objspace/test tool tool/test translator translator/test translator/tool translator/tool/pygame Message-ID: <20041119114821.332F65B255@thoth.codespeak.net> Author: bob Date: Fri Nov 19 12:48:20 2004 New Revision: 7432 Modified: pypy/trunk/src/pypy/annotation/test/autopath.py pypy/trunk/src/pypy/appspace/autopath.py pypy/trunk/src/pypy/appspace/test/autopath.py pypy/trunk/src/pypy/interpreter/autopath.py pypy/trunk/src/pypy/interpreter/test/autopath.py pypy/trunk/src/pypy/module/test/autopath.py pypy/trunk/src/pypy/objspace/flow/test/autopath.py pypy/trunk/src/pypy/objspace/std/autopath.py pypy/trunk/src/pypy/objspace/std/test/autopath.py pypy/trunk/src/pypy/objspace/test/autopath.py pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/tool/test/autopath.py pypy/trunk/src/pypy/translator/autopath.py pypy/trunk/src/pypy/translator/test/autopath.py pypy/trunk/src/pypy/translator/tool/autopath.py pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Log: more stupid autopath tricks, make sure that a module run as a script also works as if it was imported as a module Modified: pypy/trunk/src/pypy/annotation/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/autopath.py (original) +++ pypy/trunk/src/pypy/annotation/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/appspace/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/appspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/interpreter/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/interpreter/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/module/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/module/test/autopath.py (original) +++ pypy/trunk/src/pypy/module/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/objspace/flow/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/objspace/std/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/objspace/std/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/objspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/autopath.py (original) +++ pypy/trunk/src/pypy/tool/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/tool/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/autopath.py (original) +++ pypy/trunk/src/pypy/tool/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/translator/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/autopath.py (original) +++ pypy/trunk/src/pypy/translator/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/translator/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/autopath.py (original) +++ pypy/trunk/src/pypy/translator/test/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/translator/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): Modified: pypy/trunk/src/pypy/translator/tool/pygame/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Fri Nov 19 12:48:20 2004 @@ -49,6 +49,33 @@ if os.path.join(os.path.realpath(orig), '').startswith(pypy_root): sys.path.remove(orig) sys.path.insert(0, head) + + munged = {} + for name, mod in sys.modules.items(): + fn = getattr(mod, '__file__', None) + if '.' in name or not isinstance(fn, str): + continue + newname = os.path.splitext(os.path.basename(fn))[0] + path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') + if path.startswith(pypy_root) and newname != part: + modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) + if newname != '__init__': + modpaths.append(newname) + modpath = '.'.join(modpaths) + if modpath not in sys.modules: + munged[modpath] = mod + + for name, mod in munged.iteritems(): + if name not in sys.modules: + sys.modules[name] = mod + if '.' in name: + prename = name[:name.rfind('.')] + postname = name[len(prename)+1:] + if prename not in sys.modules: + __import__(prename) + if not hasattr(sys.modules[prename], postname): + setattr(sys.modules[prename], postname, mod) + return partdir, this_dir def __clone(): From bob at codespeak.net Fri Nov 19 12:51:00 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 12:51:00 +0100 (MET) Subject: [pypy-svn] r7433 - in pypy/trunk/src/pypy: annotation/test appspace appspace/test interpreter interpreter/test module/test objspace/flow/test objspace/std objspace/std/test objspace/test tool tool/test translator translator/test translator/tool translator/tool/pygame Message-ID: <20041119115100.DBE425B25D@thoth.codespeak.net> Author: bob Date: Fri Nov 19 12:50:59 2004 New Revision: 7433 Modified: pypy/trunk/src/pypy/annotation/test/autopath.py pypy/trunk/src/pypy/appspace/autopath.py pypy/trunk/src/pypy/appspace/test/autopath.py pypy/trunk/src/pypy/interpreter/autopath.py pypy/trunk/src/pypy/interpreter/test/autopath.py pypy/trunk/src/pypy/module/test/autopath.py pypy/trunk/src/pypy/objspace/flow/test/autopath.py pypy/trunk/src/pypy/objspace/std/autopath.py pypy/trunk/src/pypy/objspace/std/test/autopath.py pypy/trunk/src/pypy/objspace/test/autopath.py pypy/trunk/src/pypy/tool/autopath.py pypy/trunk/src/pypy/tool/test/autopath.py pypy/trunk/src/pypy/translator/autopath.py pypy/trunk/src/pypy/translator/test/autopath.py pypy/trunk/src/pypy/translator/tool/autopath.py pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Log: small fix, it thought goal was a package Modified: pypy/trunk/src/pypy/annotation/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/autopath.py (original) +++ pypy/trunk/src/pypy/annotation/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/appspace/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/appspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/appspace/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/interpreter/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/interpreter/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/autopath.py (original) +++ pypy/trunk/src/pypy/interpreter/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/module/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/module/test/autopath.py (original) +++ pypy/trunk/src/pypy/module/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/objspace/flow/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/objspace/std/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/objspace/std/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/objspace/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/objspace/test/autopath.py (original) +++ pypy/trunk/src/pypy/objspace/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/autopath.py (original) +++ pypy/trunk/src/pypy/tool/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/tool/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/autopath.py (original) +++ pypy/trunk/src/pypy/tool/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/translator/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/autopath.py (original) +++ pypy/trunk/src/pypy/translator/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/translator/test/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/autopath.py (original) +++ pypy/trunk/src/pypy/translator/test/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/translator/tool/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) Modified: pypy/trunk/src/pypy/translator/tool/pygame/autopath.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/autopath.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/autopath.py Fri Nov 19 12:50:59 2004 @@ -56,6 +56,8 @@ if '.' in name or not isinstance(fn, str): continue newname = os.path.splitext(os.path.basename(fn))[0] + if not newname.startswith(part + '.'): + continue path = os.path.join(os.path.dirname(os.path.realpath(fn)), '') if path.startswith(pypy_root) and newname != part: modpaths = os.path.normpath(path[len(pypy_root):]).split(os.sep) From bob at codespeak.net Fri Nov 19 12:52:52 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 12:52:52 +0100 (MET) Subject: [pypy-svn] r7434 - pypy/trunk/src/goal Message-ID: <20041119115252.10A265B260@thoth.codespeak.net> Author: bob Date: Fri Nov 19 12:52:52 2004 New Revision: 7434 Modified: pypy/trunk/src/goal/translate_pypy.py Log: maintain hard links to the most current compiled extension and source in /tmp/usession if that dir exists Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 12:52:52 2004 @@ -185,6 +185,15 @@ c_entry_point = t.ccompile() if not options['-o']: print 'Running!' + import os + if os.path.exists('/tmp/usession'): + import glob + from pypy.tool.udir import udir + for fn in glob.glob('/tmp/usession/*'): + os.remove(fn) + d = str(udir) + for fn in glob.glob(d+'/*.c') + glob.glob(d+'/*.so'): + os.link(fn, os.path.join('/tmp/usession', os.path.basename(fn))) c_entry_point() except: debug(True) From arigo at codespeak.net Fri Nov 19 13:10:32 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 13:10:32 +0100 (MET) Subject: [pypy-svn] r7435 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041119121032.2B18E5B20A@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 13:10:31 2004 New Revision: 7435 Modified: pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: Removed a double level of caches. Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Fri Nov 19 13:10:31 2004 @@ -32,11 +32,11 @@ w_value = space.wrap(value) raise OperationError, OperationError(w_exc, w_value), tb -def fake_type(cpy_type, ignored=None): +def fake_type(cpy_type): assert type(cpy_type) is type - if cpy_type in _fake_type_cache.content: - return _fake_type_cache.content[cpy_type] - assert not _fake_type_cache.frozen + return _fake_type_cache.getorbuild(cpy_type, really_build_fake_type, None) + +def really_build_fake_type(cpy_type, ignored): print 'faking %r'%(cpy_type,) kw = {} for s, v in cpy_type.__dict__.items(): @@ -70,7 +70,6 @@ return w_obj.val StdObjSpace.unwrap.register(fake_unwrap, W_Fake) W_Fake.typedef.fakedcpytype = cpy_type - _fake_type_cache.content[cpy_type] = W_Fake return W_Fake # ____________________________________________________________ Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Fri Nov 19 13:10:31 2004 @@ -137,7 +137,6 @@ def initialize(self): self._typecache = Cache() - self._faketypecache = Cache() # The object implementations that we want to 'link' into PyPy must be # imported here. This registers them into the multimethod tables, @@ -258,9 +257,9 @@ assert isinstance(w_result, W_TypeObject) return w_result if isinstance(x, type): - ft = self.loadfromcache(x, fake_type, self._faketypecache) + ft = fake_type(x) return self.gettypeobject(ft.typedef) - ft = self.loadfromcache(type(x), fake_type, self._faketypecache) + ft = fake_type(type(x)) return ft(self, x) wrap._specialize_ = "argtypes" From mgedmin at codespeak.net Fri Nov 19 13:12:06 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 13:12:06 +0100 (MET) Subject: [pypy-svn] r7436 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041119121206.EFC9A5B208@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 13:12:06 2004 New Revision: 7436 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: Fixed import. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Fri Nov 19 13:12:06 2004 @@ -65,7 +65,7 @@ self.links = {} def display(self): - from pypy.tool.translator.pygame.graphdisplay import GraphDisplay + from pypy.translator.tool.pygame.graphdisplay import GraphDisplay GraphDisplay(self).run() class Node: From arigo at codespeak.net Fri Nov 19 13:29:14 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 13:29:14 +0100 (MET) Subject: [pypy-svn] r7437 - in pypy/trunk/src/pypy: annotation objspace/flow Message-ID: <20041119122914.360385B20B@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 13:29:13 2004 New Revision: 7437 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: Oops. This should go with the previous check-in. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 13:29:13 2004 @@ -231,6 +231,10 @@ elif ishashable(x) and x in BUILTIN_ANALYZERS: result = SomeBuiltin(BUILTIN_ANALYZERS[x]) elif callable(x) or isinstance(x, staticmethod): # XXX + # maybe 'x' is a method bound to a not-yet-frozen cache? fun fun fun. + if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) + and not x.im_self.frozen): + x.im_self.freeze() if hasattr(x, '__self__') and x.__self__ is not None: s_self = immutablevalue(x.__self__) del s_self.const # stop infinite recursion getattr<->immutablevalue Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Fri Nov 19 13:29:13 2004 @@ -193,8 +193,8 @@ def call_args(self, w_callable, args): try: fn = self.unwrap(w_callable) - sc = self.specialcases[fn] - except (UnwrapException, KeyError): + sc = self.specialcases[fn] # TypeError if 'fn' not hashable + except (UnwrapException, KeyError, TypeError): pass else: return sc(self, fn, args) From mgedmin at codespeak.net Fri Nov 19 13:30:46 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 13:30:46 +0100 (MET) Subject: [pypy-svn] r7438 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041119123046.185A85B258@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 13:30:45 2004 New Revision: 7438 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Use event.unicode for keyboard shortcuts that are characters rather than special keys. This makes the pygame interface independent from keyboard layouts. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Fri Nov 19 13:30:45 2004 @@ -24,15 +24,14 @@ for ident in dir(pygame.locals) if ident.startswith('K_') ]) -KEYS['plus'] = ('=', '+', '.') -KEYS['quit'] = ('q', 'f4', 'escape') +KEYS['plus'] = ('=', '+') +KEYS['quit'] = ('q', 'escape') +KEYS['help'] = ('h', '?', 'f1') def GET_KEY(key): - k = KEYS.get(key) - if k is None: - assert len(key) == 1 - return ord(key) - return k + if len(key) == 1: + return key + return KEYS[key] def permute_mods(base, args): if not args: @@ -44,7 +43,7 @@ yield rval class Display(object): - + def __init__(self, (w,h)=(800,680)): pygame.init() self.resize((w,h)) @@ -79,6 +78,7 @@ '0' : 'zoom_actual_size', 'meta 1' : 'zoom_to_fit', '1' : 'zoom_to_fit', + 'meta f4' : 'quit', 'meta quit' : 'quit', 'quit' : 'quit', 'meta right' : 'layout_forward', @@ -87,7 +87,6 @@ 'backspace' : 'layout_back', 'f': 'search', '/': 'search', - 'shift 7': 'search', # '/' is shift-7 on my keyboard 'n': 'find_next', 'left' : ('pan', (-1, 0)), 'right' : ('pan', (1, 0)), @@ -97,17 +96,16 @@ 'shift right' : ('fast_pan', (1, 0)), 'shift up' : ('fast_pan', (0, -1)), 'shift down' : ('fast_pan', (0, 1)), - 'h': 'help', - 'f1': 'help', + 'help': 'help', } HELP_MSG = """ Key bindings: - Meta - Zoom out - Meta + or . Zoom in - Meta 0 Actual size - Meta 1 Zoom to fit + + or = Zoom in + - Zoom out + 1 Zoom to fit + 0 Actual size Arrows Scroll Shift+Arrows Scroll faster @@ -119,10 +117,9 @@ F or / Search for text N Find next occurrence - H This help message + F1, H or ? This help message - Esc Quit - Meta Q Quit + Q or Esc Quit Mouse bindings: @@ -142,6 +139,7 @@ self.viewer = None self.method_cache = {} self.key_cache = {} + self.ascii_key_cache = {} self.status_bar_height = 0 self.searchstr = None self.searchpos = None @@ -175,14 +173,20 @@ else: val = GET_KEY(name) assert len(keys) == 0 - if not isinstance(val, int): + if not isinstance(val, (int, basestring)): keys.extend([GET_KEY(k) for k in val]) else: keys.append(val) assert keys for key in keys: - for mod in permute_mods(basemod, mods): - self.key_cache[(key, mod)] = (method, args) + if isinstance(key, int): + for mod in permute_mods(basemod, mods): + self.key_cache[(key, mod)] = (method, args) + else: + for mod in permute_mods(basemod, mods): + char = key.lower() + mod = mod & ~KMOD_SHIFT + self.ascii_key_cache[(char, mod)] = (method, args) def help(self): """Show a help window and wait for a key or a mouse press.""" @@ -544,6 +548,10 @@ def process_KeyDown(self, event): method, args = self.key_cache.get((event.key, event.mod), (None, None)) + if method is None and event.unicode: + char = event.unicode.lower() + mod = event.mod & ~ KMOD_SHIFT + method, args = self.ascii_key_cache.get((char, mod), (None, None)) if method is not None: method(*args) From mgedmin at codespeak.net Fri Nov 19 14:54:20 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 14:54:20 +0100 (MET) Subject: [pypy-svn] r7439 - pypy/trunk/src/pypy/annotation Message-ID: <20041119135420.C119C5B272@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 14:54:20 2004 New Revision: 7439 Modified: pypy/trunk/src/pypy/annotation/model.py Log: Added SomeNone. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 14:54:20 2004 @@ -74,6 +74,10 @@ caused_by_merge = property(caused_by_merge, set_caused_by_merge) del set_caused_by_merge +class SomeNone(SomeObject): + "Stands for None." + knowntype = type(None) + const = None class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." @@ -246,6 +250,8 @@ if isinstance(x, Cache) and not x.frozen: x.freeze() result = SomePrebuiltConstant({x: True}) # pre-built inst: + elif x is None: + result = SomeNone() else: result = SomeObject() result.const = x From arigo at codespeak.net Fri Nov 19 15:01:37 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 15:01:37 +0100 (MET) Subject: [pypy-svn] r7440 - pypy/trunk/src/pypy/interpreter Message-ID: <20041119140137.02F855B273@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 15:01:37 2004 New Revision: 7440 Modified: pypy/trunk/src/pypy/interpreter/typedef.py Log: This hack was copying too much stuff from the dictionary of the User_InsertNameHere class. Modified: pypy/trunk/src/pypy/interpreter/typedef.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/typedef.py (original) +++ pypy/trunk/src/pypy/interpreter/typedef.py Fri Nov 19 15:01:37 2004 @@ -53,7 +53,9 @@ self.w__class__ = w_subtype self.w__dict__ = space.newdict([]) - body = dict(User_InsertNameHere.__dict__.items()) + body = dict([(key, value) + for key, value in User_InsertNameHere.__dict__.items() + if not key.startswith('_')]) subcls = type(name, (cls,), body) unique_interplevel_subclass_cache[cls] = subcls return subcls From arigo at codespeak.net Fri Nov 19 15:07:00 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 15:07:00 +0100 (MET) Subject: [pypy-svn] r7441 - pypy/trunk/src/pypy/translator Message-ID: <20041119140700.F336D5B28F@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 15:07:00 2004 New Revision: 7441 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Compiles again. Segfaults when importing, though. - extended the typename_mapping with some dark internal types of CPython. - replaced list.extend with a 'for' loop doing list.append, because list.extend eats and so hides TypeErrors in CPython < 2.4 :-( Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 15:07:00 2004 @@ -24,6 +24,11 @@ SEEN[result] = True return result +def go_figure_out_this_name(source): + # ahem + return 'PyRun_String("%s", Py_eval_input, PyEval_GetGlobals(), NULL)' % ( + source, ) + class GenC: MODNAMES = {} @@ -243,24 +248,43 @@ nameof_class = nameof_classobj # for Python 2.2 typename_mapping = { - object: 'PyBaseObject_Type', - int: 'PyInt_Type', - long: 'PyLong_Type', - bool: 'PyBool_Type', - list: 'PyList_Type', - tuple: 'PyTuple_Type', - dict: 'PyDict_Type', - str: 'PyString_Type', - float: 'PyFloat_Type', - type: 'PyType_Type', - complex:'PyComplex_Type', - r_int: 'PyInt_Type', - r_uint: 'PyInt_Type', + object: '&PyBaseObject_Type', + int: '&PyInt_Type', + long: '&PyLong_Type', + bool: '&PyBool_Type', + list: '&PyList_Type', + tuple: '&PyTuple_Type', + dict: '&PyDict_Type', + str: '&PyString_Type', + float: '&PyFloat_Type', + type: '&PyType_Type', + complex:'&PyComplex_Type', + unicode:'&PyUnicode_Type', + file: '&PyFile_Type', + + r_int: '&PyInt_Type', + r_uint: '&PyInt_Type', + + # XXX we leak 5 references here, but that's the least of the + # problems with this section of code + # type 'builtin_function_or_method': + type(len): go_figure_out_this_name('type(len)'), + # type 'method_descriptor': + type(list.append): go_figure_out_this_name('type(list.append)'), + # type 'wrapper_descriptor': + type(type(None).__repr__): go_figure_out_this_name( + 'type(type(None).__repr__)'), + # type 'getset_descriptor': + type(type.__dict__['__dict__']): go_figure_out_this_name( + "type(type.__dict__['__dict__'])"), + # type 'member_descriptor': + type(type.__dict__['__basicsize__']): go_figure_out_this_name( + "type(type.__dict__['__basicsize__'])"), } def nameof_type(self, cls): if cls in self.typename_mapping: - return '(PyObject*) &%s' % self.typename_mapping[cls] + return '(PyObject*) %s' % self.typename_mapping[cls] assert cls.__module__ != '__builtin__', \ "built-in class %r not found in typename_mapping" % (cls,) return self.nameof_classobj(cls) @@ -324,7 +348,9 @@ # collect more of the latercode after each function while self.latercode: gen = self.latercode.pop(0) - self.initcode.extend(gen) + #self.initcode.extend(gen) -- eats TypeError! bad CPython! + for line in gen: + self.initcode.append(line) self.gen_global_declarations() # footer From tismer at codespeak.net Fri Nov 19 15:17:55 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Fri, 19 Nov 2004 15:17:55 +0100 (MET) Subject: [pypy-svn] r7442 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041119141755.A159E5B29C@thoth.codespeak.net> Author: tismer Date: Fri Nov 19 15:17:55 2004 New Revision: 7442 Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: fixed enable_fast_compilation: 'OPT' does not have to exist Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Fri Nov 19 15:17:55 2004 @@ -27,9 +27,13 @@ def enable_fast_compilation(): from distutils import sysconfig - opt = sysconfig.get_config_vars()['OPT'] - opt = re.sub('-O.', '-O0', opt) - sysconfig.get_config_vars()['OPT'] = opt + gcv = sysconfig.get_config_vars() + opt = gcv.get('OPT') # not always existent + if opt: + opt = re.sub('-O.', '-O0', opt) + else: + opt = '-O0' + gcv['OPT'] = opt def make_module_from_c(cfile): from distutils.core import setup From hpk at codespeak.net Fri Nov 19 15:18:34 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 15:18:34 +0100 (MET) Subject: [pypy-svn] r7443 - pypy/trunk/src/pypy/tool Message-ID: <20041119141834.92FD75B29B@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 15:18:34 2004 New Revision: 7443 Modified: pypy/trunk/src/pypy/tool/hack.py Log: for returning a new function with a new name also copy function attributes Modified: pypy/trunk/src/pypy/tool/hack.py ============================================================================== --- pypy/trunk/src/pypy/tool/hack.py (original) +++ pypy/trunk/src/pypy/tool/hack.py Fri Nov 19 15:18:34 2004 @@ -5,9 +5,13 @@ if sys.version_info > (2, 2): def func_with_new_name(func, newname): - return new.function(func.func_code, func.func_globals, + f = new.function(func.func_code, func.func_globals, newname, func.func_defaults, func.func_closure) + if func.func_dict: + f.func_dict = {} + f.func_dict.update(func.func_dict) + return f else: From arigo at codespeak.net Fri Nov 19 15:23:14 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 15:23:14 +0100 (MET) Subject: [pypy-svn] r7444 - pypy/trunk/src/pypy/translator Message-ID: <20041119142314.51EB95B2A1@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 15:23:13 2004 New Revision: 7444 Modified: pypy/trunk/src/pypy/translator/genc.py Log: We shouldn't build tuples lazily, because they can be used e.g. as keys in dictionaries before they are ready. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 15:23:13 2004 @@ -291,14 +291,11 @@ def nameof_tuple(self, tup): name = self.uniquename('g%dtuple' % len(tup)) - def inittuple(): - for i in range(len(tup)): - item = self.nameof(tup[i]) - yield '\tPy_INCREF(%s);' % item - yield '\tPyTuple_SET_ITEM(%s, %d, %s);' % (name, i, item) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('INITCHK(%s = PyTuple_New(%d))' % (name, len(tup))) - self.latercode.append(inittuple()) + args = [self.nameof(x) for x in tup] + args.insert(0, '%d' % len(tup)) + args = ', '.join(args) + self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) return name def nameof_list(self, lis): From arigo at codespeak.net Fri Nov 19 15:48:55 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 15:48:55 +0100 (MET) Subject: [pypy-svn] r7445 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041119144855.DA5615B2A2@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 15:48:55 2004 New Revision: 7445 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Support def(*args) in the generated C functions. Added a test for it. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 15:48:55 2004 @@ -8,6 +8,7 @@ from pypy.objspace.flow.model import FunctionGraph, Block, Link, last_exception from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph from pypy.translator.simplify import remove_direct_loops +from pypy.interpreter.pycode import CO_VARARGS from types import FunctionType from pypy.objspace.std.restricted_int import r_int, r_uint @@ -395,14 +396,45 @@ print >> f # argument unpacking - lst = ['args', - '"%s"' % func.__name__, - '%d' % len(graph.getargs()), - '%d' % len(graph.getargs()), - ] - lst += ['&' + a.name for a in graph.getargs()] - print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst) - print >> f, '\t\treturn NULL;' + if func.func_code.co_flags & CO_VARARGS: + vararg = graph.getargs()[-1] + positional_args = graph.getargs()[:-1] + print >> f, '\t%s = PyTuple_GetSlice(args, %d, INT_MAX);' % ( + vararg, len(positional_args)) + print >> f, '\tif (%s == NULL)' % vararg + print >> f, '\t\treturn NULL;' + print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % ( + len(positional_args),) + print >> f, '\tif (args == NULL) {' + print >> f, '\t\tPy_DECREF(%s);' % vararg + print >> f, '\t\treturn NULL;' + print >> f, '\t}' + lst = ['args', + '"%s"' % func.__name__, + '%d' % len(positional_args), + '%d' % len(positional_args), + ] + lst += ['&' + a.name for a in positional_args] + print >> f, '\tif (!PyArg_UnpackTuple(%s)) {' % ', '.join(lst) + print >> f, '\t\tPy_DECREF(args);' + print >> f, '\t\tPy_DECREF(%s);' % vararg + print >> f, '\t\treturn NULL;' + print >> f, '\t}' + print >> f, '\tPy_DECREF(args);' + else: + positional_args = graph.getargs() + lst = ['args', + '"%s"' % func.__name__, + '%d' % len(positional_args), + '%d' % len(positional_args), + ] + lst += ['&' + a.name for a in positional_args] + print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst) + print >> f, '\t\treturn NULL;' + + # generate an incref for each input argument + for v in positional_args: + print >> f, '\tPy_INCREF(%s);' % v.name # print the body for line in body: @@ -463,10 +495,6 @@ blocknum[block] = len(blocknum) traverse(visit, graph) - # generate an incref for each input argument - for v in graph.getargs(): - yield 'Py_INCREF(%s);' % v.name - # generate the body of each block for block in allblocks: yield '' Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Fri Nov 19 15:48:55 2004 @@ -474,6 +474,12 @@ else: return (None, None) +def star_args(x, y, *args): + return x + args[0] + +def call_star_args(z): + return star_args(z, 5, 10, 15, 20) + def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Fri Nov 19 15:48:55 2004 @@ -126,6 +126,10 @@ multiple_inheritance = self.build_cfunc(snippet.multiple_inheritance) self.assertEquals(multiple_inheritance(), 1+2+3+4) + def test_call_star_args(self): + call_star_args = self.build_cfunc(snippet.call_star_args) + self.assertEquals(call_star_args(42), 52) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From bob at codespeak.net Fri Nov 19 15:50:53 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 15:50:53 +0100 (MET) Subject: [pypy-svn] r7446 - pypy/trunk/src/pypy/translator Message-ID: <20041119145053.84BC85B2B5@thoth.codespeak.net> Author: bob Date: Fri Nov 19 15:50:53 2004 New Revision: 7446 Modified: pypy/trunk/src/pypy/translator/genc.h Log: super debug action Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 15:50:53 2004 @@ -2,9 +2,14 @@ /************************************************************/ /*** Generic C header section ***/ -#include -#include - +#include "Python.h" +#include "compile.h" +#include "frameobject.h" +#include "structmember.h" + +/* Turn this off if you don't want the call trace frames to be built */ +#define USE_CALL_TRACE +#define OBNOXIOUS_PRINT_STATEMENTS #define op_richcmp(x,y,r,err,dir) \ if (!(r=PyObject_RichCompare(x,y,dir))) goto err; @@ -184,9 +189,55 @@ #define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) goto err; #define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) goto err; #define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) goto err; + +#if defined(USE_CALL_TRACE) + +#define OP_SIMPLE_CALL(args, r, err) do { \ + PyCodeObject *c = getcode("OP_SIMPLE_CALL" #args, __LINE__); \ + PyThreadState *tstate = PyThreadState_GET(); \ + PyFrameObject *f; \ + if (c == NULL) { \ + r = NULL; \ + goto err; \ + } \ + f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); \ + if (f == NULL) { \ + r = NULL; \ + goto err; \ + } \ + Py_DECREF(c); \ + tstate->frame = f; \ + if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { \ + r = NULL; \ + goto err; \ + } \ + r = PyObject_CallFunctionObjArgs args; \ + if (r == NULL) { \ + if (tstate->curexc_traceback == NULL) { \ + PyTraceBack_Here(f); \ + } \ + if (trace_frame_exc(tstate, f) < 0) { \ + goto err; \ + } \ + } \ + else { \ + if (trace_frame(tstate, f, PyTrace_RETURN, r) < 0) { \ + Py_XDECREF(r); \ + r = NULL; \ + } \ + } \ + tstate->frame = f->f_back; \ + Py_DECREF(f); \ + if (r == NULL) goto err; \ +} while (0); + +#else + #define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ goto err; +#endif + static PyObject* PyList_Pack(int n, ...) { int i; @@ -196,8 +247,9 @@ va_start(vargs, n); result = PyList_New(n); - if (result == NULL) + if (result == NULL) { return NULL; + } for (i = 0; i < n; i++) { o = va_arg(vargs, PyObject *); Py_INCREF(o); @@ -218,8 +270,9 @@ va_start(vargs, n); result = PyTuple_New(n); - if (result == NULL) + if (result == NULL) { return NULL; + } items = ((PyTupleObject *)result)->ob_item; for (i = 0; i < n; i++) { o = va_arg(vargs, PyObject *); @@ -239,23 +292,30 @@ static PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index) { int start, stop, step; - if (!PySlice_Check(index)) + if (!PySlice_Check(index)) { return PyObject_GetItem(obj, index); - if (((PySliceObject*) index)->start == Py_None) + } + if (((PySliceObject*) index)->start == Py_None) { start = -INT_MAX-1; - else { + } else { start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) return NULL; + if (start == -1 && PyErr_Occurred()) { + return NULL; + } } - if (((PySliceObject*) index)->stop == Py_None) + if (((PySliceObject*) index)->stop == Py_None) { stop = INT_MAX; - else { + } else { stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) return NULL; + if (stop == -1 && PyErr_Occurred()) { + return NULL; + } } if (((PySliceObject*) index)->step != Py_None) { step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) return NULL; + if (step == -1 && PyErr_Occurred()) { + return NULL; + } if (step != 1) { PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); @@ -267,23 +327,30 @@ static PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v) { int start, stop, step; - if (!PySlice_Check(index)) + if (!PySlice_Check(index)) { return PyObject_SetItem(obj, index, v); - if (((PySliceObject*) index)->start == Py_None) + } + if (((PySliceObject*) index)->start == Py_None) { start = -INT_MAX-1; - else { + } else { start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) return NULL; + if (start == -1 && PyErr_Occurred()) { + return NULL; + } } - if (((PySliceObject*) index)->stop == Py_None) + if (((PySliceObject*) index)->stop == Py_None) { stop = INT_MAX; - else { + } else { stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) return NULL; + if (stop == -1 && PyErr_Occurred()) { + return NULL; + } } if (((PySliceObject*) index)->step != Py_None) { step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) return NULL; + if (step == -1 && PyErr_Occurred()) { + return NULL; + } if (step != 1) { PyErr_SetString(PyExc_ValueError, "obj[slice]: no step allowed"); @@ -296,5 +363,118 @@ static PyObject* PyExc_OperationError; +#ifdef USE_CALL_TRACE +static int +trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) +{ + int result = 0; + if (!tstate->use_tracing || tstate->tracing) { + return 0; + } + if (tstate->c_profilefunc != NULL) { + tstate->tracing++; + result = tstate->c_profilefunc(tstate->c_profileobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + if (result) { + return result; + } + } + if (tstate->c_tracefunc != NULL) { + tstate->tracing++; + result = tstate->c_tracefunc(tstate->c_traceobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + } + return result; +} + +static int +trace_frame_exc(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *type, *value, *traceback, *arg; + int err; + + if (tstate->c_tracefunc == NULL) { + return 0; + } + + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = PyTuple_Pack(3, type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return 0; + } + err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg); + Py_DECREF(arg); + if (err == 0) { + PyErr_Restore(type, value, traceback); + } else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } + return err; +} + +static PyCodeObject* +getcode(char* func_name, int lineno) +{ + PyObject *code = NULL; + PyObject *name = NULL; + PyObject *nulltuple = NULL; + PyObject *filename = NULL; + PyCodeObject *tb_code = NULL; + +#if defined(OBNOXIOUS_PRINT_STATEMENTS) + printf("%d: %s\n", lineno, func_name); +#endif + code = PyString_FromString(""); + if (code == NULL) + goto failed; + name = PyString_FromString(func_name); + if (name == NULL) + goto failed; + nulltuple = PyTuple_New(0); + if (nulltuple == NULL) + goto failed; + filename = PyString_FromString(__FILE__); + tb_code = PyCode_New(0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + code, /* code */ + nulltuple, /* consts */ + nulltuple, /* names */ + nulltuple, /* varnames */ + nulltuple, /* freevars */ + nulltuple, /* cellvars */ + filename, /* filename */ + name, /* name */ + lineno, /* firstlineno */ + code /* lnotab */ + ); + if (tb_code == NULL) + goto failed; + Py_DECREF(code); + Py_DECREF(nulltuple); + Py_DECREF(filename); + Py_DECREF(name); + return tb_code; + failed: + Py_XDECREF(code); + Py_XDECREF(name); + return NULL; +} +#endif + /************************************************************/ /*** The rest is produced by genc.py ***/ From mgedmin at codespeak.net Fri Nov 19 16:06:35 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Fri, 19 Nov 2004 16:06:35 +0100 (MET) Subject: [pypy-svn] r7447 - in pypy/trunk/src/pypy: annotation objspace/flow translator/tool translator/tool/pygame Message-ID: <20041119150635.762AA5B2A7@thoth.codespeak.net> Author: mgedmin Date: Fri Nov 19 16:06:34 2004 New Revision: 7447 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/translator/tool/make_dot.py pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Annotator now remembers which functions are really methods by putting the class into func_dict. Flow graphs now show class names for methods. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 16:06:34 2004 @@ -14,6 +14,7 @@ from pypy.annotation.model import unionof, immutablevalue from pypy.interpreter.miscutils import getthreadlocals from pypy.interpreter.pycode import CO_VARARGS +from pypy.tool.hack import func_with_new_name class BlockedInference(Exception): @@ -168,6 +169,7 @@ if func.im_self is not None: s_self = immutablevalue(func.im_self) args = [s_self] + list(args) + func.im_func.class_ = func.im_class func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? @@ -198,11 +200,7 @@ if isinstance(thing, FunctionType): # XXX XXX XXX HAAAAAAAAAAAACK self.bookkeeper.annotator.translator.getflowgraph(thing) - thing = new.function(thing.func_code, - thing.func_globals, - name or thing.func_name, - thing.func_defaults, - thing.func_closure) + thing = func_with_new_name(thing, name or thing.func_name) elif isinstance(thing, (type, ClassType)): assert not "not working yet" thing = type(thing)(name or thing.__name__, (thing,)) @@ -237,6 +235,8 @@ # ignore some special attributes if name.startswith('_') and not isinstance(value, FunctionType): continue + if isinstance(value, FunctionType): + value.class_ = cls # remember that this is really a method # although self.getallfactories() is currently empty, # the following might still invalidate some blocks if it # generalizes existing values in parent classes Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Fri Nov 19 16:06:34 2004 @@ -75,7 +75,8 @@ class FlowExecutionContext(ExecutionContext): - def __init__(self, space, code, globals, constargs={}, closure=None): + def __init__(self, space, code, globals, constargs={}, closure=None, + name=None): ExecutionContext.__init__(self, space) self.code = code self.w_globals = w_globals = space.wrap(globals) @@ -95,7 +96,7 @@ self.joinpoints[joinpoint] = [] # list of blocks initialblock = SpamBlock(FrameState(frame).copy()) self.pendingblocks = [initialblock] - self.graph = FunctionGraph(code.co_name, initialblock) + self.graph = FunctionGraph(name or code.co_name, initialblock) def create_frame(self): # create an empty frame suitable for the code object Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Fri Nov 19 16:06:34 2004 @@ -115,14 +115,17 @@ closure = None else: closure = [extract_cell_content(c) for c in func.func_closure] - ec = flowcontext.FlowExecutionContext(self, code, func.func_globals, - constargs, closure) - self.setup_executioncontext(ec) - ec.build_flow() + # CallableFactory.pycall may add class_ to functions that are methods name = func.func_name + class_ = getattr(func, 'class_', None) + if class_ is not None: + name = '%s.%s' % (class_.__name__, name) for c in "<>&!": name = name.replace(c, '_') - ec.graph.name = name + ec = flowcontext.FlowExecutionContext(self, code, func.func_globals, + constargs, closure, name) + self.setup_executioncontext(ec) + ec.build_flow() checkgraph(ec.graph) return ec.graph Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Fri Nov 19 16:06:34 2004 @@ -10,7 +10,7 @@ from py.process import cmdexec class DotGen: - + def __init__(self, graphname, rankdir=None): self.graphname = graphname self.lines = [] @@ -72,7 +72,11 @@ class FlowGraphDotGen(DotGen): + def __init__(self, graphname, rankdir=None): + DotGen.__init__(self, graphname.replace('.', '_'), rankdir) + def emit_subgraph(self, name, node): + name = name.replace('.', '_') self.blocks = {} self.prefix = name self.enter_subgraph(name) @@ -93,7 +97,7 @@ def visit_FunctionGraph(self, funcgraph): name = self.prefix # +'_'+funcgraph.name - data = name + data = funcgraph.name if hasattr(funcgraph, 'source'): source = funcgraph.source.replace('"', '\\"') data += "\\n" + "\\l".join(source.split('\n')) Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Fri Nov 19 16:06:34 2004 @@ -17,7 +17,7 @@ 'red': (255,0,0), 'green': (0,255,0), } -re_nonword=re.compile(r'(\W+)') +re_nonword=re.compile(r'([^0-9a-zA-Z_.]+)') def highlight_color(color): intensity = sum(color) Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Fri Nov 19 16:06:34 2004 @@ -164,7 +164,11 @@ dotgen.emit_node('entry', fillcolor="green", shape="octagon", label="Translator\\nEntry Point") for func in functions: - data = self.labelof(func, func.func_name) + name = func.func_name + class_ = getattr(func, 'class_', None) + if class_ is not None: + name = '%s.%s' % (class_.__name__, name) + data = self.labelof(func, name) if func in highlight_functions: kw = {'fillcolor': '#ffcccc'} else: From bob at codespeak.net Fri Nov 19 16:11:07 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 16:11:07 +0100 (MET) Subject: [pypy-svn] r7448 - pypy/trunk/src/pypy/translator Message-ID: <20041119151107.3FBD05B2BB@thoth.codespeak.net> Author: bob Date: Fri Nov 19 16:11:06 2004 New Revision: 7448 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: record the function name that OP_SIMPLE_CALL was used from Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 16:11:06 2004 @@ -10,6 +10,7 @@ /* Turn this off if you don't want the call trace frames to be built */ #define USE_CALL_TRACE #define OBNOXIOUS_PRINT_STATEMENTS +#define INSIDE_FUNCTION "" #define op_richcmp(x,y,r,err,dir) \ if (!(r=PyObject_RichCompare(x,y,dir))) goto err; @@ -193,7 +194,7 @@ #if defined(USE_CALL_TRACE) #define OP_SIMPLE_CALL(args, r, err) do { \ - PyCodeObject *c = getcode("OP_SIMPLE_CALL" #args, __LINE__); \ + PyCodeObject *c = getcode(INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __LINE__); \ PyThreadState *tstate = PyThreadState_GET(); \ PyFrameObject *f; \ if (c == NULL) { \ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 16:11:06 2004 @@ -383,6 +383,8 @@ print >> f, 'static PyObject* %s(PyObject* self, PyObject* args)' % ( f_name,) print >> f, '{' + print >> f, '#undef INSIDE_FUNCTION' + print >> f, '#define INSIDE_FUNCTION "%s"' % (f_name,) # collect and print all the local variables graph = self.translator.getflowgraph(func) @@ -448,6 +450,8 @@ else: fmt = '%s\n' f.write(fmt % line) + print >> f, '#undef INSIDE_FUNCTION' + print >> f, '#define INSIDE_FUNCTION "unknown"' print >> f, '}' # print the PyMethodDef From arigo at codespeak.net Fri Nov 19 16:18:28 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 16:18:28 +0100 (MET) Subject: [pypy-svn] r7449 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041119151828.2EAD25B2D3@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 16:18:27 2004 New Revision: 7449 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Support for default arguments in generated C. Wrote tests. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 16:18:27 2004 @@ -374,6 +374,7 @@ ## func.__name__) f = self.f body = list(self.cfunction_body(func)) + name_of_defaults = [self.nameof(x) for x in (func.func_defaults or ())] self.gen_global_declarations() # print header @@ -411,28 +412,28 @@ print >> f, '\t\tPy_DECREF(%s);' % vararg print >> f, '\t\treturn NULL;' print >> f, '\t}' - lst = ['args', - '"%s"' % func.__name__, - '%d' % len(positional_args), - '%d' % len(positional_args), - ] - lst += ['&' + a.name for a in positional_args] - print >> f, '\tif (!PyArg_UnpackTuple(%s)) {' % ', '.join(lst) - print >> f, '\t\tPy_DECREF(args);' - print >> f, '\t\tPy_DECREF(%s);' % vararg - print >> f, '\t\treturn NULL;' - print >> f, '\t}' - print >> f, '\tPy_DECREF(args);' + tail = """{ +\t\tPy_DECREF(args); +\t\tPy_DECREF(%s); +\t\treturn NULL; +\t} +\tPy_DECREF(args);""" % vararg else: positional_args = graph.getargs() - lst = ['args', - '"%s"' % func.__name__, - '%d' % len(positional_args), - '%d' % len(positional_args), - ] - lst += ['&' + a.name for a in positional_args] - print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst) - print >> f, '\t\treturn NULL;' + tail = '\n\t\treturn NULL;' + min_number_of_args = len(positional_args) - len(name_of_defaults) + for i in range(len(name_of_defaults)): + print >> f, '\t%s = %s;' % ( + positional_args[min_number_of_args+i], + name_of_defaults[i]) + lst = ['args', + '"%s"' % func.__name__, + '%d' % min_number_of_args, + '%d' % len(positional_args), + ] + lst += ['&' + a.name for a in positional_args] + print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst), + print >> f, tail # generate an incref for each input argument for v in positional_args: Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Fri Nov 19 16:18:27 2004 @@ -480,6 +480,19 @@ def call_star_args(z): return star_args(z, 5, 10, 15, 20) +def default_args(x, y=2, z=3): + return x+y+z + +def call_default_args(u): + return default_args(111, u) + +def default_and_star_args(x, y=2, z=3, *more): + return x+y+z+len(more) + +def call_default_and_star_args(u): + return (default_and_star_args(111, u), + default_and_star_args(-1000, -2000, -3000, -4000, -5000)) + def powerset(setsize=int): """Powerset Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Fri Nov 19 16:18:27 2004 @@ -130,6 +130,16 @@ call_star_args = self.build_cfunc(snippet.call_star_args) self.assertEquals(call_star_args(42), 52) + def test_call_default_args(self): + call_default_args = self.build_cfunc(snippet.call_default_args) + self.assertEquals(call_default_args(42), 111+42+3) + + def test_call_default_and_star_args(self): + call_default_and_star_args = self.build_cfunc( + snippet.call_default_and_star_args) + self.assertEquals(call_default_and_star_args(42), + (111+42+3+0, -1000-2000-3000+2)) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): From arigo at codespeak.net Fri Nov 19 16:24:56 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 16:24:56 +0100 (MET) Subject: [pypy-svn] r7450 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041119152456.A78A85B2D7@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 16:24:56 2004 New Revision: 7450 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py Log: nameof_long(). Wrote the shortest test ever! One character. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 16:24:56 2004 @@ -110,6 +110,17 @@ 'PyInt_FromLong(%d))' % (name, value)) return name + def nameof_long(self, value): + assert type(int(value)) is int, "your literal long is too long" + if value >= 0: + name = 'glong%d' % value + else: + name = 'glong_minus%d' % abs(value) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = ' + 'PyLong_FromLong(%d))' % (name, value)) + return name + def nameof_str(self, value): chrs = [c for c in value if ('a' <= c <='z' or 'A' <= c <='Z' or Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Fri Nov 19 16:24:56 2004 @@ -480,7 +480,7 @@ def call_star_args(z): return star_args(z, 5, 10, 15, 20) -def default_args(x, y=2, z=3): +def default_args(x, y=2, z=3L): return x+y+z def call_default_args(u): From bob at codespeak.net Fri Nov 19 16:31:28 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 16:31:28 +0100 (MET) Subject: [pypy-svn] r7451 - pypy/trunk/src/pypy/translator Message-ID: <20041119153128.BAB0C5B2DF@thoth.codespeak.net> Author: bob Date: Fri Nov 19 16:31:28 2004 New Revision: 7451 Modified: pypy/trunk/src/pypy/translator/genc.h Log: evil callstack depth hack for obnoxious print statements Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 16:31:28 2004 @@ -193,26 +193,32 @@ #if defined(USE_CALL_TRACE) +static int callstack_depth = -1; #define OP_SIMPLE_CALL(args, r, err) do { \ + callstack_depth++; \ PyCodeObject *c = getcode(INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __LINE__); \ PyThreadState *tstate = PyThreadState_GET(); \ PyFrameObject *f; \ if (c == NULL) { \ r = NULL; \ + callstack_depth--; \ goto err; \ } \ f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); \ if (f == NULL) { \ r = NULL; \ + callstack_depth--; \ goto err; \ } \ Py_DECREF(c); \ tstate->frame = f; \ if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { \ r = NULL; \ + callstack_depth--; \ goto err; \ } \ r = PyObject_CallFunctionObjArgs args; \ + callstack_depth--; \ if (r == NULL) { \ if (tstate->curexc_traceback == NULL) { \ PyTraceBack_Here(f); \ @@ -229,7 +235,9 @@ } \ tstate->frame = f->f_back; \ Py_DECREF(f); \ - if (r == NULL) goto err; \ + if (r == NULL) { \ + goto err; \ + } \ } while (0); #else @@ -434,9 +442,17 @@ PyObject *nulltuple = NULL; PyObject *filename = NULL; PyCodeObject *tb_code = NULL; + int i; #if defined(OBNOXIOUS_PRINT_STATEMENTS) - printf("%d: %s\n", lineno, func_name); + printf("%5d: ", lineno); + assert(callstack_depth >= 0); + if (callstack_depth) { + for (i=0; i Author: arigo Date: Fri Nov 19 16:43:44 2004 New Revision: 7452 Modified: pypy/trunk/src/pypy/objspace/descroperation.py Log: better for annotations. Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Fri Nov 19 16:43:44 2004 @@ -63,7 +63,7 @@ def get_and_call_args(space, w_descr, w_obj, args): descr = space.unwrap_builtin(w_descr) # some special cases to avoid infinite recursion - if type(descr) is Function: + if isinstance(descr, Function): if isinstance(descr.code, BuiltinCode): # this sub-special case is ONLY for performance reasons w_result = descr.code.performance_shortcut_call_meth( From bob at codespeak.net Fri Nov 19 16:53:00 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 16:53:00 +0100 (MET) Subject: [pypy-svn] r7453 - in pypy/trunk/src/pypy/translator: . tool Message-ID: <20041119155300.2D72F5B2FB@thoth.codespeak.net> Author: bob Date: Fri Nov 19 16:52:59 2004 New Revision: 7453 Modified: pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py pypy/trunk/src/pypy/translator/translator.py Log: include the header with an #include statement, not an open(fn).read() Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 16:52:59 2004 @@ -594,7 +594,7 @@ # ____________________________________________________________ - C_HEADER = open(os.path.join(autopath.this_dir, 'genc.h')).read() + C_HEADER = '#include "genc.h"' C_SEP = "/************************************************************/" Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Fri Nov 19 16:52:59 2004 @@ -35,7 +35,7 @@ opt = '-O0' gcv['OPT'] = opt -def make_module_from_c(cfile): +def make_module_from_c(cfile, include_dirs=None): from distutils.core import setup from distutils.extension import Extension @@ -45,6 +45,8 @@ #except ImportError: # print "ERROR IMPORTING" # pass + if include_dirs is None: + include_dirs = [] dirpath = cfile.dirpath() lastdir = path.local() @@ -57,8 +59,9 @@ try: setup( name = "testmodules", - ext_modules=[ - Extension(modname, [str(cfile)]) + ext_modules=[ + Extension(modname, [str(cfile)], + include_dirs=include_dirs) ], script_name = 'setup.py', script_args = ['-q', 'build_ext', '--inplace'] Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Fri Nov 19 16:52:59 2004 @@ -232,7 +232,8 @@ f.close() if not really_compile: return cfile - mod = make_module_from_c(cfile) + mod = make_module_from_c(cfile, + include_dirs=[autopath.this_dir]) return getattr(mod, self.entrypoint.func_name) def call(self, *args): From arigo at codespeak.net Fri Nov 19 17:01:29 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 17:01:29 +0100 (MET) Subject: [pypy-svn] r7454 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20041119160129.BA8AF5B303@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 17:01:29 2004 New Revision: 7454 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/translator/genc.py Log: translate a bit more of the needed attributes of prebuilt constants Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 17:01:29 2004 @@ -298,4 +298,10 @@ for factory in self.getallfactories(): bookkeeper.annotator.reflowfromposition(factory.position_key) + def about_attribute(self, name): + for cdef in self.getmro(): + if name in cdef.attrs: + return cdef.attrs[name] + return SomeImpossibleValue() + from pypy.annotation.builtin import BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 17:01:29 2004 @@ -9,6 +9,7 @@ from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph from pypy.translator.simplify import remove_direct_loops from pypy.interpreter.pycode import CO_VARARGS +from pypy.annotation import model as annmodel from types import FunctionType from pypy.objspace.std.restricted_int import r_int, r_uint @@ -186,7 +187,13 @@ ann = self.translator.annotator if ann is None: return "good luck" # True - return attr in ann.getpbcattrs(pbc) + if attr in ann.getpbcattrs(pbc): + return True + classdef = ann.getuserclasses().get(pbc.__class__) + if (classdef and + classdef.about_attribute(attr) != annmodel.SomeImpossibleValue()): + return True + return False def nameof_instance(self, instance): name = self.uniquename('ginst_' + instance.__class__.__name__) From arigo at codespeak.net Fri Nov 19 17:39:12 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 17:39:12 +0100 (MET) Subject: [pypy-svn] r7455 - pypy/trunk/src/pypy/translator Message-ID: <20041119163912.AC8965B314@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 17:39:12 2004 New Revision: 7455 Modified: pypy/trunk/src/pypy/translator/genc.py Log: nameof_bizarre_internal_stuff(). Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Fri Nov 19 17:39:12 2004 @@ -345,7 +345,23 @@ self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) self.latercode.append(initdict()) return name - + + # strange prebuilt instances below, don't look too closely + # XXX oh well. + def nameof_member_descriptor(self, md): + name = self.uniquename('gdescriptor_%s_%s' % ( + md.__objclass__.__name__, md.__name__)) + self.globaldecl.append('static PyObject* %s;' % name) + cls = self.nameof(md.__objclass__) + self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % + cls) + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + '((PyTypeObject*) %s)->tp_dict, "%s"))' % + (name, cls, md.__name__)) + return name + nameof_getset_descriptor = nameof_member_descriptor + nameof_method_descriptor = nameof_member_descriptor + nameof_wrapper_descriptor = nameof_member_descriptor def gen_source(self): f = self.f From hpk at codespeak.net Fri Nov 19 17:58:48 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 17:58:48 +0100 (MET) Subject: [pypy-svn] r7456 - pypy/trunk/src/pypy/translator Message-ID: <20041119165848.07D075B32C@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 17:58:48 2004 New Revision: 7456 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: an (commented out!) hack by which you can ignore stupid *args processing related errors while annotating Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Nov 19 17:58:48 2004 @@ -187,6 +187,11 @@ missingargs = expectedargs - len(inputcells) nbdefaults = len(func.func_defaults or ()) if not (0 <= missingargs <= nbdefaults): + # XXX hack to avoid "*args" related processing + # to bail out + #v = graph.getreturnvar() + #return self.bindings.get(v, annmodel.SomeImpossibleValue()) + # XXX end hack if nbdefaults: msg = "%d to %d" % (expectedargs-nbdefaults, expectedargs) From hpk at codespeak.net Fri Nov 19 18:02:13 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Fri, 19 Nov 2004 18:02:13 +0100 (MET) Subject: [pypy-svn] r7457 - pypy/trunk/src/pypy/annotation Message-ID: <20041119170213.1C4C15B352@thoth.codespeak.net> Author: hpk Date: Fri Nov 19 18:02:12 2004 New Revision: 7457 Modified: pypy/trunk/src/pypy/annotation/unaryop.py Log: a SomeTuple returns a sensible SomeIterator setattr(PBC, ...) does not raise but merely warns about the unwanted modifications of the prebuilt constant Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Fri Nov 19 18:02:12 2004 @@ -69,6 +69,8 @@ def len(tup): return immutablevalue(len(tup.items)) + def iter(tup): + return SomeIterator(unionof(*tup.items)) class __extend__(SomeDict): @@ -205,4 +207,6 @@ return unionof(*actuals) def setattr(pbc, s_attr, s_value): - raise Exception, "oops!" + #raise Exception, "oops!" + print "*** WARNING: setattr not wanted on %r" % pbc + pass From arigo at codespeak.net Fri Nov 19 18:13:14 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 18:13:14 +0100 (MET) Subject: [pypy-svn] r7458 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20041119171314.085D05B354@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 18:13:14 2004 New Revision: 7458 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Better handling of isinstance(x, type): try hard not to lose any information (added a test for that) and, maybe, to work better somewhere in translate_pypy.py. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Nov 19 18:13:14 2004 @@ -329,7 +329,7 @@ cells = [] for a in link.args: if link.exitcase is True and a is knownvar \ - and self.binding(a).contains(knownvarvalue): + and not knownvarvalue.contains(self.binding(a)): cell = knownvarvalue else: cell = self.binding(a) Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Fri Nov 19 18:13:14 2004 @@ -283,6 +283,14 @@ #a.translator.view() self.assertEquals(s.knowntype, int) + def test_flow_type_info_2(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_type_info, + [annmodel.SomeInteger(nonneg=True)]) + # this checks that isinstance(i, int) didn't loose the + # actually more precise information that i is non-negative + self.assertEquals(s, annmodel.SomeInteger(nonneg=True)) + def test_flow_identity_info(self): a = RPythonAnnotator() s = a.build_types(snippet.flow_identity_info, [object, object]) From bob at codespeak.net Fri Nov 19 18:21:52 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 18:21:52 +0100 (MET) Subject: [pypy-svn] r7459 - pypy/trunk/src/goal Message-ID: <20041119172152.942D25B35A@thoth.codespeak.net> Author: bob Date: Fri Nov 19 18:21:52 2004 New Revision: 7459 Modified: pypy/trunk/src/goal/translate_pypy.py Log: fiddle with the /tmp/usession/ hack Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Fri Nov 19 18:21:52 2004 @@ -185,15 +185,26 @@ c_entry_point = t.ccompile() if not options['-o']: print 'Running!' - import os - if os.path.exists('/tmp/usession'): - import glob - from pypy.tool.udir import udir - for fn in glob.glob('/tmp/usession/*'): + import os, shutil + from pypy.tool.udir import udir + d = str(udir) + linkdir = os.path.join(os.path.dirname(d), 'usession') + if os.path.exists(linkdir): + def globexps(dirname, *exps): + import glob + rval = [] + for exp in exps: + rval.extend(glob.glob(os.path.join(dirname, exp))) + return rval + exts = ('*.c', '*.so') + for fn in globexps(linkdir, *exts): os.remove(fn) - d = str(udir) - for fn in glob.glob(d+'/*.c') + glob.glob(d+'/*.so'): - os.link(fn, os.path.join('/tmp/usession', os.path.basename(fn))) + for fn in globexps(d, *exts): + args = fn, os.path.join(linkdir, os.path.basename(fn)) + try: + os.link(*args) + except OSError: + shutil.copy2(*args) c_entry_point() except: debug(True) From bob at codespeak.net Fri Nov 19 18:22:11 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 18:22:11 +0100 (MET) Subject: [pypy-svn] r7460 - pypy/trunk/src/pypy/translator Message-ID: <20041119172211.340095B363@thoth.codespeak.net> Author: bob Date: Fri Nov 19 18:22:10 2004 New Revision: 7460 Modified: pypy/trunk/src/pypy/translator/genc.h Log: stuff the traceback object with c_args, c_signature and c_lineno(!!) Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 18:22:10 2004 @@ -13,7 +13,7 @@ #define INSIDE_FUNCTION "" #define op_richcmp(x,y,r,err,dir) \ - if (!(r=PyObject_RichCompare(x,y,dir))) goto err; + if (!(r=PyObject_RichCompare(x,y,dir))) goto err; #define OP_LT(x,y,r,err) op_richcmp(x,y,r,err, Py_LT) #define OP_LE(x,y,r,err) op_richcmp(x,y,r,err, Py_LE) #define OP_EQ(x,y,r,err) op_richcmp(x,y,r,err, Py_EQ) @@ -195,30 +195,49 @@ static int callstack_depth = -1; #define OP_SIMPLE_CALL(args, r, err) do { \ - callstack_depth++; \ - PyCodeObject *c = getcode(INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __LINE__); \ + char *c_signature = INSIDE_FUNCTION " OP_SIMPLE_CALL" #args; \ + PyCodeObject *c; \ + PyObject *locals = PyDict_New(); \ + PyObject *locals_list = PyList_CrazyPack args; \ + PyObject *locals_signature = PyString_FromString(c_signature); \ + PyObject *locals_lineno = PyInt_FromLong(__LINE__); \ + callstack_depth++; \ + c = getcode(c_signature, __LINE__); \ + if (locals_list != NULL && locals_signature != NULL && locals_lineno != NULL && locals != NULL) { \ + PyDict_SetItemString(locals, "c_args", locals_list); \ + PyDict_SetItemString(locals, "c_signature", locals_signature); \ + PyDict_SetItemString(locals, "c_lineno", locals_lineno); \ + Py_DECREF(locals_list); \ + } else { \ + Py_XDECREF(locals); \ + Py_XDECREF(locals_list); \ + Py_XDECREF(locals_signature); \ + Py_XDECREF(locals_lineno); \ + locals = NULL; \ + } \ PyThreadState *tstate = PyThreadState_GET(); \ PyFrameObject *f; \ - if (c == NULL) { \ + if (c == NULL || locals == NULL) { \ r = NULL; \ - callstack_depth--; \ + callstack_depth--; \ goto err; \ } \ - f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); \ + f = PyFrame_New(tstate, c, PyEval_GetGlobals(), locals); \ if (f == NULL) { \ r = NULL; \ - callstack_depth--; \ + callstack_depth--; \ goto err; \ } \ Py_DECREF(c); \ + Py_DECREF(locals); \ tstate->frame = f; \ if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { \ r = NULL; \ - callstack_depth--; \ + callstack_depth--; \ goto err; \ } \ r = PyObject_CallFunctionObjArgs args; \ - callstack_depth--; \ + callstack_depth--; \ if (r == NULL) { \ if (tstate->curexc_traceback == NULL) { \ PyTraceBack_Here(f); \ @@ -236,8 +255,8 @@ tstate->frame = f->f_back; \ Py_DECREF(f); \ if (r == NULL) { \ - goto err; \ - } \ + goto err; \ + } \ } while (0); #else @@ -247,6 +266,33 @@ #endif +static PyObject* PyList_CrazyPack(PyObject *begin, ...) +{ + int i; + PyObject *o; + PyObject *result; + va_list vargs; + + result = PyList_New(0); + if (result == NULL || begin == NULL) { + return result; + } + va_start(vargs, begin); + if (PyList_Append(result, begin) == -1) { + Py_XDECREF(result); + return result; + } + while ((o = va_arg(vargs, PyObject *)) != NULL) { + if (PyList_Append(result, o) == -1) { + Py_XDECREF(result); + return NULL; + } + } + va_end(vargs); + return result; +} + + static PyObject* PyList_Pack(int n, ...) { int i; @@ -442,16 +488,16 @@ PyObject *nulltuple = NULL; PyObject *filename = NULL; PyCodeObject *tb_code = NULL; - int i; + int i; #if defined(OBNOXIOUS_PRINT_STATEMENTS) - printf("%5d: ", lineno); - assert(callstack_depth >= 0); - if (callstack_depth) { - for (i=0; i= 0); + if (callstack_depth) { + for (i=0; i Author: mwh Date: Fri Nov 19 18:49:19 2004 New Revision: 7461 Modified: pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Smarten up valueoftype -- add optional bookkeeper argument, use it if available when passed a user defined class. Attach knowntype to return value in any case. Tests for this. Fixes to the isinstance annotation. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri Nov 19 18:49:19 2004 @@ -33,6 +33,10 @@ def builtin_chr(s_int): return SomeChar() +def our_issubclass(cls1, cls2): + """ we're going to try to be less silly in the face of old-style classes""" + return cls2 is object or issubclass(cls1, cls2) + def builtin_isinstance(s_obj, s_type): if s_type.is_constant(): typ = s_type.const @@ -41,25 +45,26 @@ typ = int if s_obj.is_constant(): return immutablevalue(isinstance(s_obj.const, typ)) - elif issubclass(s_obj.knowntype, typ): + elif our_issubclass(s_obj.knowntype, typ): return immutablevalue(True) - elif not issubclass(typ, s_obj.knowntype): - return immutablevalue(False) + elif not our_issubclass(typ, s_obj.knowntype): + return immutablevalue(False) else: # XXX HACK HACK HACK # XXX HACK HACK HACK # XXX HACK HACK HACK # XXX HACK HACK HACK # XXX HACK HACK HACK - fn, block, i = getbookkeeper().position_key - annotator = getbookkeeper().annotator + bk = getbookkeeper() + fn, block, i = bk.position_key + annotator = bk.annotator op = block.operations[i] assert op.opname == "simple_call" assert len(op.args) == 3 assert op.args[0] == Constant(isinstance) assert annotator.binding(op.args[1]) is s_obj r = SomeBool() - r.knowntypedata = (op.args[1], valueoftype(typ)) + r.knowntypedata = (op.args[1], valueoftype(typ, bk)) return r return SomeBool() Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 18:49:19 2004 @@ -257,7 +257,7 @@ result.const = x return result -def valueoftype(t): +def valueoftype(t, bookkeeper=None): "The most precise SomeValue instance that contains all objects of type t." if t is bool: return SomeBool() @@ -267,8 +267,14 @@ return SomeString() elif t is list: return SomeList(factories={}) + # can't do dict, tuple + elif isinstance(t, (type, ClassType)) and \ + t.__module__ != '__builtin__' and bookkeeper is not None: + return SomeInstance(bookkeeper.getclassdef(t)) else: - return SomeObject() + o = SomeObject() + o.knowntype = t + return o ##def decode_simple_call(s_args, s_kwds): ## s_nbargs = s_args.len() Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri Nov 19 18:49:19 2004 @@ -58,7 +58,7 @@ inputcells = [] for t in input_arg_types: if not isinstance(t, annmodel.SomeObject): - t = annmodel.valueoftype(t) + t = annmodel.valueoftype(t, self.bookkeeper) inputcells.append(t) # register the entry point Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Fri Nov 19 18:49:19 2004 @@ -462,6 +462,12 @@ a = len(str(i)) return a +def flow_usertype_info(ob): + if isinstance(ob, WithInit): + return ob + else: + return WithMoreInit(1, 2) + def flow_identity_info(x=object, y=object): if x is None: if None is y: Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Fri Nov 19 18:49:19 2004 @@ -291,6 +291,18 @@ # actually more precise information that i is non-negative self.assertEquals(s, annmodel.SomeInteger(nonneg=True)) + def test_flow_usertype_info(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_usertype_info, [object]) + #a.translator.view() + self.assertEquals(s.knowntype, snippet.WithInit) + + def test_flow_usertype_info2(self): + a = RPythonAnnotator() + s = a.build_types(snippet.flow_usertype_info, [snippet.WithMoreInit]) + #a.translator.view() + self.assertEquals(s.knowntype, snippet.WithMoreInit) + def test_flow_identity_info(self): a = RPythonAnnotator() s = a.build_types(snippet.flow_identity_info, [object, object]) From arigo at codespeak.net Fri Nov 19 18:57:21 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 18:57:21 +0100 (MET) Subject: [pypy-svn] r7463 - pypy/trunk/src/pypy/translator Message-ID: <20041119175721.469E05B396@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 18:57:20 2004 New Revision: 7463 Modified: pypy/trunk/src/pypy/translator/genc.h Log: Made the C code compatible with old compilers. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 18:57:20 2004 @@ -215,7 +215,7 @@ Py_XDECREF(locals_lineno); \ locals = NULL; \ } \ - PyThreadState *tstate = PyThreadState_GET(); \ + { PyThreadState *tstate = PyThreadState_GET(); \ PyFrameObject *f; \ if (c == NULL || locals == NULL) { \ r = NULL; \ @@ -256,7 +256,7 @@ Py_DECREF(f); \ if (r == NULL) { \ goto err; \ - } \ + } } \ } while (0); #else From bob at codespeak.net Fri Nov 19 18:59:10 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 18:59:10 +0100 (MET) Subject: [pypy-svn] r7464 - pypy/trunk/src/pypy/translator Message-ID: <20041119175910.943C25B3A3@thoth.codespeak.net> Author: bob Date: Fri Nov 19 18:59:10 2004 New Revision: 7464 Modified: pypy/trunk/src/pypy/translator/genc.h Log: possibly working nicer genc.h Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 18:59:10 2004 @@ -194,70 +194,101 @@ #if defined(USE_CALL_TRACE) static int callstack_depth = -1; -#define OP_SIMPLE_CALL(args, r, err) do { \ - char *c_signature = INSIDE_FUNCTION " OP_SIMPLE_CALL" #args; \ - PyCodeObject *c; \ - PyObject *locals = PyDict_New(); \ - PyObject *locals_list = PyList_CrazyPack args; \ - PyObject *locals_signature = PyString_FromString(c_signature); \ - PyObject *locals_lineno = PyInt_FromLong(__LINE__); \ - callstack_depth++; \ - c = getcode(c_signature, __LINE__); \ - if (locals_list != NULL && locals_signature != NULL && locals_lineno != NULL && locals != NULL) { \ - PyDict_SetItemString(locals, "c_args", locals_list); \ - PyDict_SetItemString(locals, "c_signature", locals_signature); \ - PyDict_SetItemString(locals, "c_lineno", locals_lineno); \ - Py_DECREF(locals_list); \ - } else { \ - Py_XDECREF(locals); \ - Py_XDECREF(locals_list); \ - Py_XDECREF(locals_signature); \ - Py_XDECREF(locals_lineno); \ - locals = NULL; \ - } \ - { PyThreadState *tstate = PyThreadState_GET(); \ - PyFrameObject *f; \ - if (c == NULL || locals == NULL) { \ - r = NULL; \ - callstack_depth--; \ - goto err; \ - } \ - f = PyFrame_New(tstate, c, PyEval_GetGlobals(), locals); \ - if (f == NULL) { \ - r = NULL; \ - callstack_depth--; \ - goto err; \ - } \ - Py_DECREF(c); \ - Py_DECREF(locals); \ - tstate->frame = f; \ - if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { \ - r = NULL; \ - callstack_depth--; \ - goto err; \ - } \ - r = PyObject_CallFunctionObjArgs args; \ - callstack_depth--; \ - if (r == NULL) { \ - if (tstate->curexc_traceback == NULL) { \ - PyTraceBack_Here(f); \ - } \ - if (trace_frame_exc(tstate, f) < 0) { \ - goto err; \ - } \ - } \ - else { \ - if (trace_frame(tstate, f, PyTrace_RETURN, r) < 0) { \ - Py_XDECREF(r); \ - r = NULL; \ - } \ - } \ - tstate->frame = f->f_back; \ - Py_DECREF(f); \ - if (r == NULL) { \ - goto err; \ - } } \ -} while (0); + +static PyObject *traced_function_call(PyObject *allargs, char *c_signature, char *filename, int c_lineno) { + /* + STEALS a reference to allargs + */ + PyCodeObject *c; + PyFrameObject *f; + PyObject *rval; + PyThreadState *tstate; + PyObject *locals; + PyObject *function; + PyObject *args; + PyObject *locals_signature; + PyObject *locals_lineno; + PyObject *locals_filename; + + if (allargs == NULL) { + return NULL; + } + tstate = PyThreadState_GET(); + locals = PyDict_New(); + args = PyTuple_GetSlice(allargs, 1, PyTuple_Size(allargs)); + function = PyTuple_GetItem(allargs, 0); + Py_INCREF(function) + Py_DECREF(allargs); + locals_signature = PyString_FromString(c_signature); + locals_lineno = PyInt_FromLong(c_lineno); + locals_filename = PyString_FromString(filename); + if (locals == NULL || function == NULL || args == NULL || + locals_signature == NULL || locals_lineno == NULL || + locals_filename == NULL) { + Py_XDECREF(locals); + Py_XDECREF(args); + Py_XDECREF(locals_signature); + Py_XDECREF(locals_lineno); + Py_XDECREF(locals_filename); + return NULL; + } + PyDict_SetItemString(locals, "function", function); + PyDict_SetItemString(locals, "args", args); + PyDict_SetItemString(locals, "signature", locals_signature); + PyDict_SetItemString(locals, "lineno", locals_lineno); + PyDict_SetItemString(locals, "filename", locals_filename); + Py_DECREF(locals); + Py_DECREF(locals_signature); + Py_DECREF(locals_lineno); + Py_DECREF(locals_filename); + callstack_depth++; + c = getcode(c_signature, c_lineno); + if (c == NULL) { + callstack_depth--; + Py_DECREF(args); + Py_DECREF(locals); + return NULL; + } + f = PyFrame_New(tstate, c, PyEval_GetGlobals(), locals); + if (f == NULL) { + callstack_depth--; + Py_DECREF(c); + Py_DECREF(locals); + Py_DECREF(args); + return NULL; + } + Py_DECREF(c); + Py_DECREF(locals); + tstate->frame = f; + + if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { + callstack_depth--; + Py_DECREF(args); + return NULL; + } + rval = PyObject_Call(function, args, NULL); + PyObject_DECREF(args); + callstack_depth--; + if (rval == NULL) { + if (tstate->curexc_traceback == NULL) { + PyTraceBack_Here(f); + } + if (trace_frame_exc(tstate, f) < 0) { + return NULL; + } + } else { + if (trace_frame(tstate, f, PyTrace_RETURN, rval) < 0) { + Py_DECREF(rval); + rval = NULL; + } + } + tstate->frame = f->f_back; + Py_DECREF(f); + return rval; +} + +#define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #arg, __FILE__, __LINE__)) == NULL) \ + goto err; #else @@ -266,6 +297,38 @@ #endif +static PyObject* PyTuple_CrazyPack(PyObject *begin, ...) +{ + int i; + PyObject *o; + PyObject *result; + PyObject *tuple; + va_list vargs; + + result = PyList_New(0); + if (result == NULL || begin == NULL) { + return result; + } + va_start(vargs, begin); + if (PyList_Append(result, begin) == -1) { + Py_XDECREF(result); + return result; + } + while ((o = va_arg(vargs, PyObject *)) != NULL) { + if (PyList_Append(result, o) == -1) { + Py_XDECREF(result); + return NULL; + } + } + va_end(vargs); + if ((tuple = PySequence_Tuple(result)) == NULL) { + Py_DECREF(result); + return NULL; + } + Py_DECREF(result); + return tuple; +} + static PyObject* PyList_CrazyPack(PyObject *begin, ...) { int i; From bob at codespeak.net Fri Nov 19 19:07:17 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 19:07:17 +0100 (MET) Subject: [pypy-svn] r7465 - pypy/trunk/src/pypy/translator Message-ID: <20041119180717.960B75B3A9@thoth.codespeak.net> Author: bob Date: Fri Nov 19 19:07:12 2004 New Revision: 7465 Modified: pypy/trunk/src/pypy/translator/genc.h Log: ok now it should work Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 19:07:12 2004 @@ -1,6 +1,6 @@ /************************************************************/ - /*** Generic C header section ***/ +/*** Generic C header section ***/ #include "Python.h" #include "compile.h" @@ -194,6 +194,9 @@ #if defined(USE_CALL_TRACE) static int callstack_depth = -1; +static PyCodeObject* getcode(char* func_name, int lineno); +static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val); +static int trace_frame_exc(PyThreadState *tstate, PyFrameObject *f); static PyObject *traced_function_call(PyObject *allargs, char *c_signature, char *filename, int c_lineno) { /* @@ -217,7 +220,7 @@ locals = PyDict_New(); args = PyTuple_GetSlice(allargs, 1, PyTuple_Size(allargs)); function = PyTuple_GetItem(allargs, 0); - Py_INCREF(function) + Py_INCREF(function); Py_DECREF(allargs); locals_signature = PyString_FromString(c_signature); locals_lineno = PyInt_FromLong(c_lineno); @@ -287,7 +290,7 @@ return rval; } -#define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #arg, __FILE__, __LINE__)) == NULL) \ +#define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __FILE__, __LINE__)) == NULL) \ goto err; #else @@ -603,4 +606,4 @@ #endif /************************************************************/ - /*** The rest is produced by genc.py ***/ +/*** The rest is produced by genc.py ***/ From bob at codespeak.net Fri Nov 19 19:08:13 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 19:08:13 +0100 (MET) Subject: [pypy-svn] r7466 - pypy/trunk/src/pypy/translator Message-ID: <20041119180813.E7EC35B40B@thoth.codespeak.net> Author: bob Date: Fri Nov 19 19:08:12 2004 New Revision: 7466 Modified: pypy/trunk/src/pypy/translator/genc.h Log: another typo fixed Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 19:08:12 2004 @@ -270,7 +270,7 @@ return NULL; } rval = PyObject_Call(function, args, NULL); - PyObject_DECREF(args); + Py_DECREF(args); callstack_depth--; if (rval == NULL) { if (tstate->curexc_traceback == NULL) { From arigo at codespeak.net Fri Nov 19 19:11:28 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 19:11:28 +0100 (MET) Subject: [pypy-svn] r7467 - pypy/trunk/src/pypy/annotation Message-ID: <20041119181128.BFB405B414@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 19:11:26 2004 New Revision: 7467 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py Log: Bug: a missing factory. See the comment. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri Nov 19 19:11:26 2004 @@ -55,6 +55,9 @@ del getthreadlocals().bookkeeper del self.position_key + def is_in_an_operation(self): + return hasattr(self, 'position_key') + def getfactory(self, factorycls): """Get the Factory associated with the current position, or build it if it doesn't exist yet.""" Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 19:11:26 2004 @@ -270,7 +270,16 @@ # can't do dict, tuple elif isinstance(t, (type, ClassType)) and \ t.__module__ != '__builtin__' and bookkeeper is not None: - return SomeInstance(bookkeeper.getclassdef(t)) + classdef = bookkeeper.getclassdef(t) + if bookkeeper.is_in_an_operation(): + # woha! instantiating a "mutable" SomeXxx like SomeInstance + # is always dangerous, because we need to record this fact + # in a factory, to allow reflowing from the current operation + # if/when the classdef later changes. + from pypy.annotation.factory import CallableFactory + factory = bookkeeper.getfactory(CallableFactory) + classdef.instancefactories[factory] = True + return SomeInstance(classdef) else: o = SomeObject() o.knowntype = t From arigo at codespeak.net Fri Nov 19 19:14:52 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 19 Nov 2004 19:14:52 +0100 (MET) Subject: [pypy-svn] r7468 - pypy/trunk/src/pypy/annotation Message-ID: <20041119181452.B2BFB5B3BE@thoth.codespeak.net> Author: arigo Date: Fri Nov 19 19:14:51 2004 New Revision: 7468 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: builtin_apply(). Well, almost. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri Nov 19 19:14:51 2004 @@ -111,6 +111,10 @@ factory.generalize(s_iter.next()) return factory.create() +def builtin_apply(*stuff): + print "XXX ignoring apply%r" % (stuff,) + return SomeObject() + # collect all functions import __builtin__ BUILTIN_ANALYZERS = {} From bob at codespeak.net Fri Nov 19 19:15:05 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 19:15:05 +0100 (MET) Subject: [pypy-svn] r7469 - pypy/trunk/src/pypy/translator Message-ID: <20041119181505.DB56B5B41D@thoth.codespeak.net> Author: bob Date: Fri Nov 19 19:15:03 2004 New Revision: 7469 Modified: pypy/trunk/src/pypy/translator/genc.h Log: should actually be fixed now... Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 19:15:03 2004 @@ -240,7 +240,6 @@ PyDict_SetItemString(locals, "signature", locals_signature); PyDict_SetItemString(locals, "lineno", locals_lineno); PyDict_SetItemString(locals, "filename", locals_filename); - Py_DECREF(locals); Py_DECREF(locals_signature); Py_DECREF(locals_lineno); Py_DECREF(locals_filename); @@ -248,6 +247,7 @@ c = getcode(c_signature, c_lineno); if (c == NULL) { callstack_depth--; + Py_DECREF(function); Py_DECREF(args); Py_DECREF(locals); return NULL; @@ -257,6 +257,7 @@ callstack_depth--; Py_DECREF(c); Py_DECREF(locals); + Py_DECREF(function); Py_DECREF(args); return NULL; } @@ -270,6 +271,7 @@ return NULL; } rval = PyObject_Call(function, args, NULL); + Py_DECREF(function); Py_DECREF(args); callstack_depth--; if (rval == NULL) { From bob at codespeak.net Fri Nov 19 19:40:07 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Fri, 19 Nov 2004 19:40:07 +0100 (MET) Subject: [pypy-svn] r7470 - pypy/trunk/src/pypy/translator Message-ID: <20041119184007.3EDF05B41A@thoth.codespeak.net> Author: bob Date: Fri Nov 19 19:40:00 2004 New Revision: 7470 Modified: pypy/trunk/src/pypy/translator/genc.h Log: refactoring Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Fri Nov 19 19:40:00 2004 @@ -198,30 +198,15 @@ static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val); static int trace_frame_exc(PyThreadState *tstate, PyFrameObject *f); -static PyObject *traced_function_call(PyObject *allargs, char *c_signature, char *filename, int c_lineno) { - /* - STEALS a reference to allargs - */ +static PyFrameObject *traced_function_head(PyObject *function, PyObject *args, char *c_signature, char *filename, int c_lineno, PyThreadState *tstate) { PyCodeObject *c; PyFrameObject *f; - PyObject *rval; - PyThreadState *tstate; PyObject *locals; - PyObject *function; - PyObject *args; PyObject *locals_signature; PyObject *locals_lineno; PyObject *locals_filename; - if (allargs == NULL) { - return NULL; - } - tstate = PyThreadState_GET(); locals = PyDict_New(); - args = PyTuple_GetSlice(allargs, 1, PyTuple_Size(allargs)); - function = PyTuple_GetItem(allargs, 0); - Py_INCREF(function); - Py_DECREF(allargs); locals_signature = PyString_FromString(c_signature); locals_lineno = PyInt_FromLong(c_lineno); locals_filename = PyString_FromString(filename); @@ -229,7 +214,6 @@ locals_signature == NULL || locals_lineno == NULL || locals_filename == NULL) { Py_XDECREF(locals); - Py_XDECREF(args); Py_XDECREF(locals_signature); Py_XDECREF(locals_lineno); Py_XDECREF(locals_filename); @@ -243,43 +227,33 @@ Py_DECREF(locals_signature); Py_DECREF(locals_lineno); Py_DECREF(locals_filename); - callstack_depth++; c = getcode(c_signature, c_lineno); if (c == NULL) { - callstack_depth--; - Py_DECREF(function); - Py_DECREF(args); Py_DECREF(locals); return NULL; } f = PyFrame_New(tstate, c, PyEval_GetGlobals(), locals); if (f == NULL) { - callstack_depth--; - Py_DECREF(c); - Py_DECREF(locals); - Py_DECREF(function); - Py_DECREF(args); return NULL; } Py_DECREF(c); Py_DECREF(locals); tstate->frame = f; - if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { - callstack_depth--; Py_DECREF(args); return NULL; } - rval = PyObject_Call(function, args, NULL); - Py_DECREF(function); - Py_DECREF(args); - callstack_depth--; + + return f; +} + +static PyObject *traced_function_tail(PyObject *rval, PyFrameObject *f, PyThreadState *tstate) { if (rval == NULL) { if (tstate->curexc_traceback == NULL) { PyTraceBack_Here(f); } if (trace_frame_exc(tstate, f) < 0) { - return NULL; + goto end; } } else { if (trace_frame(tstate, f, PyTrace_RETURN, rval) < 0) { @@ -287,8 +261,47 @@ rval = NULL; } } +end: tstate->frame = f->f_back; - Py_DECREF(f); + return rval; +} + +static PyObject *traced_function_call(PyObject *allargs, char *c_signature, char *filename, int c_lineno) { + /* + STEALS a reference to allargs + */ + PyFrameObject *f; + PyObject *rval; + PyThreadState *tstate; + PyObject *function; + PyObject *args; + + if (allargs == NULL) { + return NULL; + } + args = PyTuple_GetSlice(allargs, 1, PyTuple_Size(allargs)); + function = PyTuple_GetItem(allargs, 0); + if (args == NULL || function == NULL) { + return NULL; + } + Py_INCREF(function); + Py_DECREF(allargs); + + tstate = PyThreadState_GET(); + callstack_depth++; + f = traced_function_head(function, args, c_signature, filename, c_lineno, tstate); + if (f == NULL) { + callstack_depth--; + Py_DECREF(function); + Py_DECREF(args); + return NULL; + } + + rval = PyObject_Call(function, args, NULL); + Py_DECREF(function); + Py_DECREF(args); + rval = traced_function_tail(rval, f, tstate); + callstack_depth--; return rval; } From mwh at codespeak.net Fri Nov 19 19:46:05 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Fri, 19 Nov 2004 19:46:05 +0100 (MET) Subject: [pypy-svn] r7471 - pypy/trunk/src/pypy/annotation Message-ID: <20041119184605.E1D9D5B41F@thoth.codespeak.net> Author: mwh Date: Fri Nov 19 19:46:04 2004 New Revision: 7471 Modified: pypy/trunk/src/pypy/annotation/model.py Log: Given the potential of commonbase to cause subtle problems, perhaps someone should actually think about it's implementation. This protects against an infinite loop. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri Nov 19 19:46:04 2004 @@ -315,6 +315,7 @@ return d def commonbase(cls1, cls2): # XXX single inheritance only XXX hum + assert issubclass(cls1, object) while not issubclass(cls1, cls2): cls2, = [x for x in cls2.__bases__ if x is not object] or [object] return cls2 From bob at codespeak.net Sat Nov 20 00:12:25 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 00:12:25 +0100 (MET) Subject: [pypy-svn] r7472 - pypy/trunk/src/pypy/translator Message-ID: <20041119231225.B4B4E5B2B3@thoth.codespeak.net> Author: bob Date: Sat Nov 20 00:12:25 2004 New Revision: 7472 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: more crazy debugging hacks Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 00:12:25 2004 @@ -7,9 +7,13 @@ #include "frameobject.h" #include "structmember.h" +static PyObject *this_module_globals; + /* Turn this off if you don't want the call trace frames to be built */ #define USE_CALL_TRACE +#if 0 #define OBNOXIOUS_PRINT_STATEMENTS +#endif #define INSIDE_FUNCTION "" #define op_richcmp(x,y,r,err,dir) \ @@ -179,10 +183,16 @@ 0, /* tp_descr_set */ }; -#define SETUP_MODULE \ +#define MODULE_INITFUNC(modname) \ + static PyMethodDef no_methods[] = { NULL, NULL }; \ + void init##modname(void) + +#define SETUP_MODULE(modname) \ + PyObject *m = Py_InitModule(#modname, no_methods); \ + this_module_globals = PyModule_GetDict(m); \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ PyType_Ready(&PyGenCFunction_Type); \ - PyExc_OperationError = PyErr_NewException("bah.OperationError", NULL, NULL); + PyExc_OperationError = PyErr_NewException(#modname ".OperationError", NULL, NULL); /*** operations with a variable number of arguments ***/ @@ -194,7 +204,7 @@ #if defined(USE_CALL_TRACE) static int callstack_depth = -1; -static PyCodeObject* getcode(char* func_name, int lineno); +static PyCodeObject* getcode(char *func_name, char *func_filename, int lineno); static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val); static int trace_frame_exc(PyThreadState *tstate, PyFrameObject *f); @@ -206,6 +216,11 @@ PyObject *locals_lineno; PyObject *locals_filename; + if (function == NULL || args == NULL || tstate == NULL) { + printf("BAD ARGUMENTS!\n"); + printf("function = 0x%08X args = %08X tstate = %08X\n", function, args, tstate); + return NULL; + } locals = PyDict_New(); locals_signature = PyString_FromString(c_signature); locals_lineno = PyInt_FromLong(c_lineno); @@ -227,13 +242,16 @@ Py_DECREF(locals_signature); Py_DECREF(locals_lineno); Py_DECREF(locals_filename); - c = getcode(c_signature, c_lineno); + callstack_depth++; + c = getcode(c_signature, filename, c_lineno); if (c == NULL) { Py_DECREF(locals); + callstack_depth--; return NULL; } - f = PyFrame_New(tstate, c, PyEval_GetGlobals(), locals); + f = PyFrame_New(tstate, c, this_module_globals, locals); if (f == NULL) { + callstack_depth--; return NULL; } Py_DECREF(c); @@ -241,6 +259,7 @@ tstate->frame = f; if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { Py_DECREF(args); + callstack_depth--; return NULL; } @@ -248,6 +267,12 @@ } static PyObject *traced_function_tail(PyObject *rval, PyFrameObject *f, PyThreadState *tstate) { + /* + STEALS a reference to f + */ + if (f == NULL) { + goto bad_args; + } if (rval == NULL) { if (tstate->curexc_traceback == NULL) { PyTraceBack_Here(f); @@ -263,6 +288,9 @@ } end: tstate->frame = f->f_back; + Py_DECREF(f); +bad_args: + callstack_depth--; return rval; } @@ -288,10 +316,8 @@ Py_DECREF(allargs); tstate = PyThreadState_GET(); - callstack_depth++; f = traced_function_head(function, args, c_signature, filename, c_lineno, tstate); if (f == NULL) { - callstack_depth--; Py_DECREF(function); Py_DECREF(args); return NULL; @@ -300,19 +326,31 @@ rval = PyObject_Call(function, args, NULL); Py_DECREF(function); Py_DECREF(args); - rval = traced_function_tail(rval, f, tstate); - callstack_depth--; - return rval; + return traced_function_tail(rval, f, tstate); } #define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __FILE__, __LINE__)) == NULL) \ goto err; +#define FUNCTION_HEAD(signature, self, args) \ + PyThreadState *__tstate = PyThreadState_GET(); \ + PyFrameObject *__f = traced_function_head(self, args, signature, __FILE__, __LINE__, __tstate); \ + if (__f == NULL) { \ + printf("frame is null, wtf?!\n"); \ + return NULL; \ + } + +#define FUNCTION_RETURN(rval) return traced_function_tail(rval, __f, __tstate); + + #else #define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ goto err; +#define FUNCTION_HEAD(signature, self, args) +#define FUNCTION_RETURN(rval) return rval; + #endif static PyObject* PyTuple_CrazyPack(PyObject *begin, ...) @@ -562,7 +600,7 @@ } static PyCodeObject* -getcode(char* func_name, int lineno) +getcode(char *func_name, char *func_filename, int lineno) { PyObject *code = NULL; PyObject *name = NULL; @@ -590,7 +628,7 @@ nulltuple = PyTuple_New(0); if (nulltuple == NULL) goto failed; - filename = PyString_FromString(__FILE__); + filename = PyString_FromString(func_filename); tb_code = PyCode_New(0, /* argcount */ 0, /* nlocals */ 0, /* stacksize */ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 00:12:25 2004 @@ -16,6 +16,9 @@ # ____________________________________________________________ +def c_string(s): + return '"%s"' % (s.replace('\\', '\\\\').replace('"', '\"'),) + def uniquemodulename(name, SEEN={}): # never reuse the same module name within a Python session! i = 0 @@ -418,8 +421,11 @@ print >> f, 'static PyObject* %s(PyObject* self, PyObject* args)' % ( f_name,) print >> f, '{' - print >> f, '#undef INSIDE_FUNCTION' - print >> f, '#define INSIDE_FUNCTION "%s"' % (f_name,) + print >> f, '\t#undef INSIDE_FUNCTION' + print >> f, '\t#define INSIDE_FUNCTION "%s"' % (f_name,) + print >> f, '\tFUNCTION_HEAD(%s, %s, args)' % ( + c_string('%s(%s)' % (name, ', '.join(name_of_defaults))), + name) # collect and print all the local variables graph = self.translator.getflowgraph(func) @@ -439,22 +445,22 @@ print >> f, '\t%s = PyTuple_GetSlice(args, %d, INT_MAX);' % ( vararg, len(positional_args)) print >> f, '\tif (%s == NULL)' % vararg - print >> f, '\t\treturn NULL;' + print >> f, '\t\tFUNCTION_RETURN(NULL)' print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % ( len(positional_args),) print >> f, '\tif (args == NULL) {' print >> f, '\t\tPy_DECREF(%s);' % vararg - print >> f, '\t\treturn NULL;' + print >> f, '\t\tFUNCTION_RETURN(NULL)' print >> f, '\t}' tail = """{ \t\tPy_DECREF(args); \t\tPy_DECREF(%s); -\t\treturn NULL; +\t\tFUNCTION_RETURN(NULL); \t} \tPy_DECREF(args);""" % vararg else: positional_args = graph.getargs() - tail = '\n\t\treturn NULL;' + tail = '\n\t\tFUNCTION_RETURN(NULL)' min_number_of_args = len(positional_args) - len(name_of_defaults) for i in range(len(name_of_defaults)): print >> f, '\t%s = %s;' % ( @@ -558,10 +564,10 @@ # exceptional return block yield 'PyErr_SetObject(PyExc_%s, %s);' % ( block.exc_type.__name__, retval) - yield 'return NULL;' + yield 'FUNCTION_RETURN(NULL)' else: # regular return block - yield 'return %s;' % retval + yield 'FUNCTION_RETURN(%s)' % retval continue elif block.exitswitch is None: # single-exit block @@ -613,7 +619,7 @@ yield 'err%d_%d:' % (blocknum[block], len(to_release)) err_reachable = True if err_reachable: - yield 'return NULL;' + yield 'FUNCTION_RETURN(NULL)' # ____________________________________________________________ @@ -623,11 +629,9 @@ C_INIT_HEADER = C_SEP + ''' -static PyMethodDef no_methods[] = { NULL, NULL }; -void init%(modname)s(void) +MODULE_INITFUNC(%(modname)s) { -\tPyObject* m = Py_InitModule("%(modname)s", no_methods); -\tSETUP_MODULE +\tSETUP_MODULE(%(modname)s) ''' C_INIT_FOOTER = ''' From bob at codespeak.net Sat Nov 20 00:51:17 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 00:51:17 +0100 (MET) Subject: [pypy-svn] r7473 - pypy/trunk/src/pypy/translator Message-ID: <20041119235117.E1D755B2C7@thoth.codespeak.net> Author: bob Date: Sat Nov 20 00:51:17 2004 New Revision: 7473 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: register module globals Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 00:51:17 2004 @@ -117,6 +117,7 @@ #define MOVE(x, y) y = x; #define INITCHK(expr) if (!(expr)) return; +#define REGISTER_GLOBAL(name) Py_INCREF(name); PyModule_AddObject(m, #name, name); /*** classes ***/ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 00:51:17 2004 @@ -54,6 +54,7 @@ # objects self.globaldecl = [] self.pendingfunctions = [] + self.initglobals = [] self.gen_source() def nameof(self, obj): @@ -92,6 +93,7 @@ name = self.uniquename('g_object') self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_module(self, value): @@ -101,6 +103,7 @@ name = self.uniquename('mod%s'%value.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name @@ -112,6 +115,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = ' 'PyInt_FromLong(%d))' % (name, value)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_long(self, value): @@ -123,6 +127,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = ' 'PyLong_FromLong(%d))' % (name, value)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_str(self, value): @@ -142,6 +147,7 @@ s = '"%s"' % value self.initcode.append('INITCHK(%s = PyString_FromStringAndSize(' '%s, %d))' % (name, s, len(value))) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_function(self, func): @@ -154,6 +160,7 @@ self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.pendingfunctions.append(func) return name @@ -167,6 +174,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.pendingfunctions.append(func) return name @@ -179,12 +187,13 @@ ob = self.nameof(meth.im_self) func = self.nameof(meth.im_func) typ = self.nameof(meth.im_class) - us = self.uniquename('gmeth_'+meth.im_func.__name__) - self.globaldecl.append('static PyObject* %s;'%(us,)) + name = self.uniquename('gmeth_'+meth.im_func.__name__) + self.globaldecl.append('static PyObject* %s;'%(name,)) self.initcode.append( 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( - us, func, ob, typ)) - return us + name, func, ob, typ)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) + return name def should_translate_attr(self, pbc, attr): ann = self.translator.annotator @@ -211,6 +220,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.latercode.append(initinstance()) return name @@ -223,6 +233,7 @@ self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' 'PyEval_GetBuiltins(), "%s"))' % ( name, func.__name__)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_classobj(self, cls): @@ -264,6 +275,7 @@ self.initcode.append('\t\t"s(%s){}", "%s"%s))' %("O"*len(basenames), cls.__name__, baseargs)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.latercode.append(initclassobj()) return name @@ -318,6 +330,7 @@ args.insert(0, '%d' % len(tup)) args = ', '.join(args) self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_list(self, lis): @@ -329,6 +342,7 @@ yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.latercode.append(initlist()) return name @@ -346,6 +360,7 @@ name, self.nameof(k), self.nameof(dic[k]))) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.latercode.append(initdict()) return name @@ -361,6 +376,7 @@ self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' '((PyTypeObject*) %s)->tp_dict, "%s"))' % (name, cls, md.__name__)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name nameof_getset_descriptor = nameof_member_descriptor nameof_method_descriptor = nameof_member_descriptor @@ -392,6 +408,8 @@ print >> f, self.C_INIT_HEADER % info for codeline in self.initcode: print >> f, '\t' + codeline + for codeline in self.initglobals: + print >> f, '\t' + codeline print >> f, self.C_INIT_FOOTER % info def gen_global_declarations(self): From bob at codespeak.net Sat Nov 20 01:35:04 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 01:35:04 +0100 (MET) Subject: [pypy-svn] r7474 - pypy/trunk/src/pypy/translator Message-ID: <20041120003504.5447B5B2D4@thoth.codespeak.net> Author: bob Date: Sat Nov 20 01:35:03 2004 New Revision: 7474 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: do some stupid hacks to set the locals to "correct" names Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 01:35:03 2004 @@ -7,6 +7,10 @@ #include "frameobject.h" #include "structmember.h" +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif /* MIN */ + static PyObject *this_module_globals; /* Turn this off if you don't want the call trace frames to be built */ @@ -209,13 +213,19 @@ static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val); static int trace_frame_exc(PyThreadState *tstate, PyFrameObject *f); -static PyFrameObject *traced_function_head(PyObject *function, PyObject *args, char *c_signature, char *filename, int c_lineno, PyThreadState *tstate) { +static PyFrameObject *traced_function_head(PyObject *function, PyObject *args, char *c_signature, char *filename, int c_lineno, PyThreadState *tstate, PyObject *extra_local_names) { + /* + STEALS a reference to extra_local_names if not NULL + */ + PyCodeObject *c; PyFrameObject *f; PyObject *locals; PyObject *locals_signature; PyObject *locals_lineno; PyObject *locals_filename; + int i; + int max_locals; if (function == NULL || args == NULL || tstate == NULL) { printf("BAD ARGUMENTS!\n"); @@ -243,6 +253,13 @@ Py_DECREF(locals_signature); Py_DECREF(locals_lineno); Py_DECREF(locals_filename); + if (extra_local_names != NULL) { + int max_locals = MIN(PyList_Size(extra_local_names), PyTuple_Size(args)); + for (i = 0; i < max_locals; ++i) { + PyDict_SetItem(locals, PyList_GET_ITEM(extra_local_names, i), PyTuple_GET_ITEM(args, i)); + } + } + callstack_depth++; c = getcode(c_signature, filename, c_lineno); if (c == NULL) { @@ -317,7 +334,7 @@ Py_DECREF(allargs); tstate = PyThreadState_GET(); - f = traced_function_head(function, args, c_signature, filename, c_lineno, tstate); + f = traced_function_head(function, args, c_signature, filename, c_lineno, tstate, NULL); if (f == NULL) { Py_DECREF(function); Py_DECREF(args); @@ -333,9 +350,10 @@ #define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __FILE__, __LINE__)) == NULL) \ goto err; -#define FUNCTION_HEAD(signature, self, args) \ +#define FUNCTION_HEAD(signature, self, args, names) \ PyThreadState *__tstate = PyThreadState_GET(); \ - PyFrameObject *__f = traced_function_head(self, args, signature, __FILE__, __LINE__, __tstate); \ + PyObject *__localnames = PyList_CrazyStringPack names; \ + PyFrameObject *__f = traced_function_head(self, args, signature, __FILE__, __LINE__, __tstate, __localnames); \ if (__f == NULL) { \ printf("frame is null, wtf?!\n"); \ return NULL; \ @@ -411,6 +429,46 @@ va_end(vargs); return result; } +static PyObject* PyList_CrazyStringPack(char *begin, ...) +{ + int i; + PyObject *o; + PyObject *result; + va_list vargs; + + result = PyList_New(0); + if (result == NULL || begin == NULL) { + return result; + } + va_start(vargs, begin); + o = PyString_FromString(begin); + if (o == NULL) { + Py_XDECREF(result); + return NULL; + } + if (PyList_Append(result, o) == -1) { + Py_DECREF(o); + Py_XDECREF(result); + return result; + } + Py_DECREF(o); + while ((begin = va_arg(vargs, char *)) != NULL) { + o = PyString_FromString(begin); + if (o == NULL) { + Py_XDECREF(result); + return NULL; + } + if (PyList_Append(result, o) == -1) { + Py_DECREF(o); + Py_XDECREF(result); + return NULL; + } + Py_DECREF(o); + } + va_end(vargs); + return result; +} + static PyObject* PyList_Pack(int n, ...) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 01:35:03 2004 @@ -441,9 +441,11 @@ print >> f, '{' print >> f, '\t#undef INSIDE_FUNCTION' print >> f, '\t#define INSIDE_FUNCTION "%s"' % (f_name,) - print >> f, '\tFUNCTION_HEAD(%s, %s, args)' % ( + print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s)' % ( c_string('%s(%s)' % (name, ', '.join(name_of_defaults))), - name) + name, + '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), + ) # collect and print all the local variables graph = self.translator.getflowgraph(func) From bob at codespeak.net Sat Nov 20 01:35:37 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 01:35:37 +0100 (MET) Subject: [pypy-svn] r7475 - pypy/trunk/src/pypy/translator Message-ID: <20041120003537.9ABF55B2DA@thoth.codespeak.net> Author: bob Date: Sat Nov 20 01:35:37 2004 New Revision: 7475 Modified: pypy/trunk/src/pypy/translator/genc.h Log: steal the reference as advertised Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 01:35:37 2004 @@ -258,6 +258,7 @@ for (i = 0; i < max_locals; ++i) { PyDict_SetItem(locals, PyList_GET_ITEM(extra_local_names, i), PyTuple_GET_ITEM(args, i)); } + Py_DECREF(extra_local_names); } callstack_depth++; From bob at codespeak.net Sat Nov 20 01:42:30 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 01:42:30 +0100 (MET) Subject: [pypy-svn] r7476 - pypy/trunk/src/pypy/translator Message-ID: <20041120004230.1C6825B2E3@thoth.codespeak.net> Author: bob Date: Sat Nov 20 01:42:29 2004 New Revision: 7476 Modified: pypy/trunk/src/pypy/translator/genc.h Log: add a __sourcefile__ constant Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 01:42:29 2004 @@ -194,6 +194,7 @@ #define SETUP_MODULE(modname) \ PyObject *m = Py_InitModule(#modname, no_methods); \ + PyModule_AddStringConstant(m, "__sourcefile__", __FILE__); \ this_module_globals = PyModule_GetDict(m); \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ PyType_Ready(&PyGenCFunction_Type); \ From hpk at codespeak.net Sat Nov 20 09:20:25 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 09:20:25 +0100 (MET) Subject: [pypy-svn] r7477 - in pypy/trunk/src/pypy: annotation interpreter objspace/std translator Message-ID: <20041120082025.4E7665AB7D@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 09:20:22 2004 New Revision: 7477 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/interpreter/argument.py pypy/trunk/src/pypy/interpreter/eval.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/translator/annrpython.py Log: use newstyleclasses (the annotator is happier in its "commonbase" hack then) Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat Nov 20 09:20:22 2004 @@ -7,7 +7,7 @@ from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeCallable -from pypy.annotation.model import SomeBuiltin, SomeIterator +from pypy.annotation.model import SomeBuiltin, SomeIterator, SomeNone from pypy.annotation.model import SomePrebuiltConstant, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize, isclassdef, getbookkeeper @@ -288,6 +288,24 @@ d[cal] = classdef return SomeCallable(d) +# XXX experimental hack: union of more complex objects with +# SomeNone (aka "NULL"-pointer) doesn't destroy +# type inference (keeps the type of the more complex object) + +#for _X in SomeCallable, SomeInstance, SomePrebuiltConstant: +# class __extend__(pairtype(_X, SomeNone)): +# def union((obj1, obj2)): +# return obj1 +# class __extend__(pairtype(SomeNone, _X)): +# def union((obj1, obj2)): +# return obj2 + +#class __extend__(pairtype(SomePrebuiltConstant, SomeNone)): +# def union((pbc, non)): +# if + +# XXX experimental hack finish ... kind of + class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): return obj2 Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat Nov 20 09:20:22 2004 @@ -177,11 +177,27 @@ assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? x = getattr(func, '_specialize_', False) + #if not x: + # x = 'argtypesdeep' if x: if x == 'argtypes': key = "_".join([arg.__class__.__name__ for arg in args]) name = func.__name__+'_'+key func = self.specialize_by_key(func, key, name) + elif x == 'argtypesdeep': + l = [] + for arg in args: + if isinstance(arg, SomeInstance): + if hasattr(arg, 'knowntype'): + x = arg.knowntype.__name__ + else: + x = 'unknown' + l.append('SI_%s' % x) + else: + l.append(arg.__class__.__name__) + key = "_".join(l) + name = func.__name__ + '_' + key + func = self.specialize_by_key(func, key, name) elif x == "location": # fully specialize: create one version per call position func = self.specialize_by_key(func, self.position_key) Modified: pypy/trunk/src/pypy/interpreter/argument.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/argument.py (original) +++ pypy/trunk/src/pypy/interpreter/argument.py Sat Nov 20 09:20:22 2004 @@ -84,7 +84,9 @@ space = self.space args_w = self.args_w kwds_w = self.kwds_w - argnames, varargname, kwargname = signature + argnames = signature[0] + varargname = signature[1] + kwargname = signature[2] # # args_w = list of the normal actual parameters, wrapped # kwds_w = real dictionary {'keyword': wrapped parameter} Modified: pypy/trunk/src/pypy/interpreter/eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/eval.py (original) +++ pypy/trunk/src/pypy/interpreter/eval.py Sat Nov 20 09:20:22 2004 @@ -49,7 +49,7 @@ def getdocstring(self): return None -class UndefinedClass: +class UndefinedClass: pass UNDEFINED = UndefinedClass() # marker for undefined local variables Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Sat Nov 20 09:20:22 2004 @@ -303,6 +303,7 @@ def lookup(self, w_obj, name): w_type = w_obj.getclass(self) return w_type.lookup(name) + lookup._specialize_ = "argtypesdeep" def allocate_instance(self, cls, w_subtype): """Allocate the memory needed for an instance of an internal or @@ -349,6 +350,7 @@ if w_one is w_two: return self.w_True return self.w_False + is_._specialize_ = "argtypesdeep" def is_true(self, w_obj): # XXX don't look! @@ -356,6 +358,7 @@ return not not w_obj.used else: return DescrOperation.is_true(self, w_obj) + is_true._specialize_ = "argtypesdeep" def hash(space, w_obj): w = space.wrap Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Nov 20 09:20:22 2004 @@ -187,16 +187,17 @@ missingargs = expectedargs - len(inputcells) nbdefaults = len(func.func_defaults or ()) if not (0 <= missingargs <= nbdefaults): - # XXX hack to avoid "*args" related processing - # to bail out - #v = graph.getreturnvar() - #return self.bindings.get(v, annmodel.SomeImpossibleValue()) - # XXX end hack if nbdefaults: msg = "%d to %d" % (expectedargs-nbdefaults, expectedargs) else: msg = "%d" % expectedargs + # XXX hack to avoid "*args" related processing + # to bail out + print "ANNOTATION WARNING: got %d inputcells in call to %r; expected %s" % (len(inputcells), func, msg) + v = graph.getreturnvar() + return self.bindings.get(v, annmodel.SomeImpossibleValue()) + # XXX end hack raise AnnotatorError, ( "got %d inputcells in call to %r; expected %s" % ( len(inputcells), func, msg)) From hpk at codespeak.net Sat Nov 20 09:22:14 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 09:22:14 +0100 (MET) Subject: [pypy-svn] r7478 - in pypy/trunk/src/pypy: annotation interpreter objspace/std translator Message-ID: <20041120082214.B2FAD5AF1C@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 09:22:14 2004 New Revision: 7478 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/interpreter/argument.py pypy/trunk/src/pypy/interpreter/eval.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genc.h Log: revert the previous commit ... sorry mixed up my cmdline ... Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat Nov 20 09:22:14 2004 @@ -7,7 +7,7 @@ from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeCallable -from pypy.annotation.model import SomeBuiltin, SomeIterator, SomeNone +from pypy.annotation.model import SomeBuiltin, SomeIterator from pypy.annotation.model import SomePrebuiltConstant, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize, isclassdef, getbookkeeper @@ -288,24 +288,6 @@ d[cal] = classdef return SomeCallable(d) -# XXX experimental hack: union of more complex objects with -# SomeNone (aka "NULL"-pointer) doesn't destroy -# type inference (keeps the type of the more complex object) - -#for _X in SomeCallable, SomeInstance, SomePrebuiltConstant: -# class __extend__(pairtype(_X, SomeNone)): -# def union((obj1, obj2)): -# return obj1 -# class __extend__(pairtype(SomeNone, _X)): -# def union((obj1, obj2)): -# return obj2 - -#class __extend__(pairtype(SomePrebuiltConstant, SomeNone)): -# def union((pbc, non)): -# if - -# XXX experimental hack finish ... kind of - class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): return obj2 Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat Nov 20 09:22:14 2004 @@ -177,27 +177,11 @@ assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? x = getattr(func, '_specialize_', False) - #if not x: - # x = 'argtypesdeep' if x: if x == 'argtypes': key = "_".join([arg.__class__.__name__ for arg in args]) name = func.__name__+'_'+key func = self.specialize_by_key(func, key, name) - elif x == 'argtypesdeep': - l = [] - for arg in args: - if isinstance(arg, SomeInstance): - if hasattr(arg, 'knowntype'): - x = arg.knowntype.__name__ - else: - x = 'unknown' - l.append('SI_%s' % x) - else: - l.append(arg.__class__.__name__) - key = "_".join(l) - name = func.__name__ + '_' + key - func = self.specialize_by_key(func, key, name) elif x == "location": # fully specialize: create one version per call position func = self.specialize_by_key(func, self.position_key) Modified: pypy/trunk/src/pypy/interpreter/argument.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/argument.py (original) +++ pypy/trunk/src/pypy/interpreter/argument.py Sat Nov 20 09:22:14 2004 @@ -84,9 +84,7 @@ space = self.space args_w = self.args_w kwds_w = self.kwds_w - argnames = signature[0] - varargname = signature[1] - kwargname = signature[2] + argnames, varargname, kwargname = signature # # args_w = list of the normal actual parameters, wrapped # kwds_w = real dictionary {'keyword': wrapped parameter} Modified: pypy/trunk/src/pypy/interpreter/eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/eval.py (original) +++ pypy/trunk/src/pypy/interpreter/eval.py Sat Nov 20 09:22:14 2004 @@ -49,7 +49,7 @@ def getdocstring(self): return None -class UndefinedClass: +class UndefinedClass: pass UNDEFINED = UndefinedClass() # marker for undefined local variables Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Sat Nov 20 09:22:14 2004 @@ -303,7 +303,6 @@ def lookup(self, w_obj, name): w_type = w_obj.getclass(self) return w_type.lookup(name) - lookup._specialize_ = "argtypesdeep" def allocate_instance(self, cls, w_subtype): """Allocate the memory needed for an instance of an internal or @@ -350,7 +349,6 @@ if w_one is w_two: return self.w_True return self.w_False - is_._specialize_ = "argtypesdeep" def is_true(self, w_obj): # XXX don't look! @@ -358,7 +356,6 @@ return not not w_obj.used else: return DescrOperation.is_true(self, w_obj) - is_true._specialize_ = "argtypesdeep" def hash(space, w_obj): w = space.wrap Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Nov 20 09:22:14 2004 @@ -187,17 +187,16 @@ missingargs = expectedargs - len(inputcells) nbdefaults = len(func.func_defaults or ()) if not (0 <= missingargs <= nbdefaults): + # XXX hack to avoid "*args" related processing + # to bail out + #v = graph.getreturnvar() + #return self.bindings.get(v, annmodel.SomeImpossibleValue()) + # XXX end hack if nbdefaults: msg = "%d to %d" % (expectedargs-nbdefaults, expectedargs) else: msg = "%d" % expectedargs - # XXX hack to avoid "*args" related processing - # to bail out - print "ANNOTATION WARNING: got %d inputcells in call to %r; expected %s" % (len(inputcells), func, msg) - v = graph.getreturnvar() - return self.bindings.get(v, annmodel.SomeImpossibleValue()) - # XXX end hack raise AnnotatorError, ( "got %d inputcells in call to %r; expected %s" % ( len(inputcells), func, msg)) Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 09:22:14 2004 @@ -194,7 +194,6 @@ #define SETUP_MODULE(modname) \ PyObject *m = Py_InitModule(#modname, no_methods); \ - PyModule_AddStringConstant(m, "__sourcefile__", __FILE__); \ this_module_globals = PyModule_GetDict(m); \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ PyType_Ready(&PyGenCFunction_Type); \ From hpk at codespeak.net Sat Nov 20 09:24:01 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 09:24:01 +0100 (MET) Subject: [pypy-svn] r7479 - pypy/trunk/src/pypy/interpreter Message-ID: <20041120082401.841C85B344@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 09:24:01 2004 New Revision: 7479 Modified: pypy/trunk/src/pypy/interpreter/eval.py Log: (now really) make UndefinedClass a newstyle class Modified: pypy/trunk/src/pypy/interpreter/eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/eval.py (original) +++ pypy/trunk/src/pypy/interpreter/eval.py Sat Nov 20 09:24:01 2004 @@ -49,7 +49,7 @@ def getdocstring(self): return None -class UndefinedClass: +class UndefinedClass(object): pass UNDEFINED = UndefinedClass() # marker for undefined local variables From arigo at codespeak.net Sat Nov 20 09:24:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 09:24:45 +0100 (MET) Subject: [pypy-svn] r7480 - in pypy/trunk/src: goal pypy/interpreter pypy/translator Message-ID: <20041120082445.6A0725B35B@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 09:24:44 2004 New Revision: 7480 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/translator/genc.py Log: Trying 'translate_pypy.py -no-a' to generate the C code from *all* functions without doing the annotation phase at all. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Sat Nov 20 09:24:44 2004 @@ -5,6 +5,7 @@ Command-line options for translate_pypy: -text Don't start the Pygame viewer + -no-a Don't infer annotations, just translate everything -no-c Don't generate the C code -c Generate the C code, but don't compile it -o Generate and compile the C code, but don't run it @@ -41,8 +42,10 @@ # caches (as far as analyzing the entry_point is concerned) entry_point() t = Translator(entry_point, verbose=True, simplifying=True) - a = t.annotate([]) - a.simplify() + if not options['-no-a']: + a = t.annotate([]) + a.simplify() + t.frozen = True # cannot freeze if we don't have annotations if options['--mark-some-objects']: find_someobjects(a) @@ -105,6 +108,7 @@ '-c': False, '-o': False, '--mark-some-objects': False, + '-no-a': False, } for arg in sys.argv[1:]: if arg in ('-h', '--help'): @@ -172,7 +176,6 @@ try: analyse() - t.frozen = True print '-'*60 if options['-no-c']: print 'Not generating C code.' Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Sat Nov 20 09:24:44 2004 @@ -92,6 +92,13 @@ space.delitem(w_builtins, w_name) del self.__saved_hooks + # Don't keep a reference to __builtins__ in self.__dict__ + # (it might have been put there by exec/eval/execfile) + try: + del self.__dict__['__builtins__'] + except KeyError: + pass + def interplevelexec(self, w_codestring): "'exec' a string at interp-level." codestring = self.space.unwrap(w_codestring) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 09:24:44 2004 @@ -347,6 +347,8 @@ return name def nameof_dict(self, dic): + assert dic is not __builtins__ + assert '__builtins__' not in dic, 'It seems to be a globals dict' name = self.uniquename('g%ddict' % len(dic)) def initdict(): for k in dic: From arigo at codespeak.net Sat Nov 20 09:39:57 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 09:39:57 +0100 (MET) Subject: [pypy-svn] r7481 - pypy/trunk/src/pypy/interpreter Message-ID: <20041120083957.439ED5B359@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 09:39:56 2004 New Revision: 7481 Modified: pypy/trunk/src/pypy/interpreter/gateway.py Log: Oups. This doesn't work (tests failing). Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Sat Nov 20 09:39:56 2004 @@ -173,8 +173,8 @@ # after initialization the following attributes should be set # name # code - # staticglobals - # staticdefs + # _staticglobals + # _staticdefs def __spacebind__(self, space): # to wrap a Gateway, we first make a real Function object out of it @@ -191,16 +191,16 @@ # but must be done lazily when needed only, because # 1) it depends on the object space # 2) the w_globals must not be built before the underlying - # staticglobals is completely initialized, because + # _staticglobals is completely initialized, because # w_globals must be built only once for all the Gateway - # instances of staticglobals - if self.staticglobals is None: + # instances of _staticglobals + if self._staticglobals is None: w_globals = None else: - # is there another Gateway in staticglobals for which we + # is there another Gateway in _staticglobals for which we # already have a w_globals for this space ? cache = self.getcache(space) - for value in self.staticglobals.itervalues(): + for value in self._staticglobals.itervalues(): if isinstance(value, Gateway): if value in cache.content: # yes, we share its w_globals @@ -208,8 +208,8 @@ w_globals = fn.w_func_globals break else: - # no, we build all Gateways in the staticglobals now. - w_globals = build_dict(self.staticglobals, space) + # no, we build all Gateways in the _staticglobals now. + w_globals = build_dict(self._staticglobals, space) return self._build_function(space, w_globals) def getcache(self, space): @@ -237,7 +237,7 @@ fn = self.get_function(space) w_obj = space.wrap(obj) return Method(space, space.wrap(fn), - w_obj, space.type(w_obj)) + w_obj, space.type(w_obj)) class app2interp(Gateway): @@ -255,11 +255,11 @@ self.name = app_name self.code = pycode.PyCode(None) self.code._from_code(app.func_code) - self.staticglobals = app.func_globals - self.staticdefs = list(app.func_defaults or ()) + self._staticglobals = app.func_globals + self._staticdefs = list(app.func_defaults or ()) def getdefaults(self, space): - return [space.wrap(val) for val in self.staticdefs] + return [space.wrap(val) for val in self._staticdefs] def __call__(self, space, *args_w): # to call the Gateway as a non-method, 'space' must be explicitly @@ -291,11 +291,11 @@ app_name = f.func_name self.code = BuiltinCode(f) self.name = app_name - self.staticdefs = list(f.func_defaults or ()) - self.staticglobals = None + self._staticdefs = list(f.func_defaults or ()) + self._staticglobals = None def getdefaults(self, space): - return self.staticdefs + return self._staticdefs def exportall(d, temporary=False): """Publish every function from a dict.""" From hpk at codespeak.net Sat Nov 20 09:47:37 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 09:47:37 +0100 (MET) Subject: [pypy-svn] r7482 - pypy/trunk/src/pypy/translator Message-ID: <20041120084737.4D8F85B353@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 09:47:36 2004 New Revision: 7482 Modified: pypy/trunk/src/pypy/translator/genc.h Log: reverted a line in genc.h that got reverted earlier on in error Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 09:47:36 2004 @@ -194,6 +194,7 @@ #define SETUP_MODULE(modname) \ PyObject *m = Py_InitModule(#modname, no_methods); \ + PyModule_AddStringConstant(m, "__sourcefile__", __FILE__); \ this_module_globals = PyModule_GetDict(m); \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ PyType_Ready(&PyGenCFunction_Type); \ From arigo at codespeak.net Sat Nov 20 09:51:11 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 09:51:11 +0100 (MET) Subject: [pypy-svn] r7483 - pypy/trunk/src/pypy/interpreter Message-ID: <20041120085111.9B0165B36C@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 09:51:11 2004 New Revision: 7483 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py Log: Argh. This is what I meant with the previous check-in. Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Sat Nov 20 09:51:11 2004 @@ -92,13 +92,6 @@ space.delitem(w_builtins, w_name) del self.__saved_hooks - # Don't keep a reference to __builtins__ in self.__dict__ - # (it might have been put there by exec/eval/execfile) - try: - del self.__dict__['__builtins__'] - except KeyError: - pass - def interplevelexec(self, w_codestring): "'exec' a string at interp-level." codestring = self.space.unwrap(w_codestring) From hpk at codespeak.net Sat Nov 20 10:13:56 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 10:13:56 +0100 (MET) Subject: [pypy-svn] r7484 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20041120091356.C96CA5B391@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 10:13:56 2004 New Revision: 7484 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/test/test_model.py Log: improve the commonbase() helper for annotation, it now uses MRO and tries a bit harder to find the commonbase, assuming 'object' to be the common base if it can't otherwise find one added a few tests for this Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat Nov 20 10:13:56 2004 @@ -34,6 +34,7 @@ from pypy.annotation.pairtype import pair, extendabletype from pypy.objspace.flow.model import Constant from pypy.tool.cache import Cache +import inspect class SomeObject: """The set of all objects. Each instance stands @@ -315,10 +316,16 @@ return d def commonbase(cls1, cls2): # XXX single inheritance only XXX hum - assert issubclass(cls1, object) - while not issubclass(cls1, cls2): - cls2, = [x for x in cls2.__bases__ if x is not object] or [object] - return cls2 + l1 = inspect.getmro(cls1) + l2 = inspect.getmro(cls2) + if l1[-1] != object: + l1 = l1 + (object,) + if l2[-1] != object: + l2 = l2 + (object,) + for x in l1: + if x in l2: + return x + assert 0, "couldn't get to commonbase of %r and %r" % (cls1, cls2)) def missing_operation(cls, name): def default_op(*args): Modified: pypy/trunk/src/pypy/annotation/test/test_model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/test/test_model.py (original) +++ pypy/trunk/src/pypy/annotation/test/test_model.py Sat Nov 20 10:13:56 2004 @@ -38,6 +38,24 @@ s1, s1, s1, s5, s5, s5, s1, s2, s3, s4, s5, s6]) +def test_commonbase_simple(): + class A0: + pass + class A1(A0): + pass + class A2(A0): + pass + class B1(object): + pass + class B2(object): + pass + class B3(object, A0): + pass + assert commonbase(A1,A2) is A0 + assert commonbase(A1,A0) is A0 + assert commonbase(A1,A1) is A1 + assert commonbase(A2,B2) is object + assert commonbase(A2,B3) is A0 if __name__ == '__main__': for name, value in globals().items(): From hpk at codespeak.net Sat Nov 20 10:15:00 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 10:15:00 +0100 (MET) Subject: [pypy-svn] r7485 - pypy/trunk/src/pypy/annotation Message-ID: <20041120091500.8A4375B39A@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 10:15:00 2004 New Revision: 7485 Modified: pypy/trunk/src/pypy/annotation/model.py Log: argl: fixed a syntax error ... Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat Nov 20 10:15:00 2004 @@ -325,7 +325,7 @@ for x in l1: if x in l2: return x - assert 0, "couldn't get to commonbase of %r and %r" % (cls1, cls2)) + assert 0, "couldn't get to commonbase of %r and %r" % (cls1, cls2) def missing_operation(cls, name): def default_op(*args): From mgedmin at codespeak.net Sat Nov 20 10:29:30 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 10:29:30 +0100 (MET) Subject: [pypy-svn] r7486 - in pypy/trunk/src/pypy/translator: . tool/pygame Message-ID: <20041120092930.B322D5B3A6@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 10:29:30 2004 New Revision: 7486 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Highlight blocked functions in red. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Nov 20 10:29:30 2004 @@ -27,6 +27,7 @@ self.why_not_annotated = {} # {block: (exc_type, exc_value, traceback)} # records the location of BlockedInference # exceptions that blocked some blocks. + self.blocked_functions = {} # set of functions that have blocked blocks self.notify = {} # {block: {factory-to-invalidate-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues self.binding_caused_by = {} # map Variables to Factories @@ -121,6 +122,8 @@ if False in self.annotated.values(): for block in self.annotated: if self.annotated[block] is False: + fn = self.why_not_annotated[block][1].break_at[0] + self.blocked_functions[fn] = True import traceback print '-+' * 30 print 'BLOCKED block at:', Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sat Nov 20 10:29:30 2004 @@ -157,9 +157,13 @@ self.name_by_object = {} dotgen = DotGen('translator') dotgen.emit('mclimit=15.0') - + # show the call graph functions = translator.functions + if translator.annotator: + blocked_functions = translator.annotator.blocked_functions + else: + blocked_functions = {} highlight_functions = getattr(translator, 'highlight_functions', {}) # XXX dotgen.emit_node('entry', fillcolor="green", shape="octagon", label="Translator\\nEntry Point") @@ -169,7 +173,9 @@ if class_ is not None: name = '%s.%s' % (class_.__name__, name) data = self.labelof(func, name) - if func in highlight_functions: + if func in blocked_functions: + kw = {'fillcolor': 'red'} + elif func in highlight_functions: kw = {'fillcolor': '#ffcccc'} else: kw = {} From arigo at codespeak.net Sat Nov 20 10:30:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 10:30:44 +0100 (MET) Subject: [pypy-svn] r7487 - in pypy/trunk/src/pypy: interpreter objspace/flow translator Message-ID: <20041120093044.05D645B3BD@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 10:30:44 2004 New Revision: 7487 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: - functions whose docstring start with NOT_RPYTHON are never flowgraphified and translated. Tagging functions more systematically as NOT_RPYTHON is a good idea anyway. - genc writes placeholders for skipped functions; the placeholder (should) raise an informative message if it gets called at run-time. - nameof_float, nameof_file (only for sys.std{in,out,err}). - some name magic to skip some instances attributes if we don't have the annotator to tell us. - uniquename() complexity was wrong, slowing everything down. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Sat Nov 20 10:30:44 2004 @@ -206,7 +206,7 @@ return self.issubtype(w_objtype, w_type) def eval(self, expression, w_globals, w_locals): - "For internal debugging." + "NOT_RPYTHON: For internal debugging." import types from pypy.interpreter.pycode import PyCode if isinstance(expression, str): @@ -218,7 +218,7 @@ return expression.exec_code(self, w_globals, w_locals) def exec_(self, statement, w_globals, w_locals): - "For internal debugging." + "NOT_RPYTHON: For internal debugging." import types from pypy.interpreter.pycode import PyCode if isinstance(statement, str): Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 10:30:44 2004 @@ -109,6 +109,8 @@ def build_flow(self, func, constargs={}): """ """ + if func.func_doc and func.func_doc.startswith('NOT_RPYTHON'): + raise Exception, "%r is tagged as NOT_RPYTHON" % (func,) code = func.func_code code = PyCode()._from_code(code) if func.func_closure is None: Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 10:30:44 2004 @@ -719,5 +719,10 @@ } #endif -/************************************************************/ -/*** The rest is produced by genc.py ***/ +static PyObject* skipped(PyObject* self, PyObject* args) +{ + PyErr_Format(PyExc_AssertionError, + "calling the skipped function '%s'", + (((PyCFunctionObject *)self) -> m_ml -> ml_name)); + return NULL; +} Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 10:30:44 2004 @@ -79,13 +79,12 @@ return name def uniquename(self, basename): - name = basename - i = 0 - while name in self.seennames: - i += 1 - name = '%s_%d' % (basename, i) - self.seennames[name] = True - return name + n = self.seennames.get(basename, 0) + self.seennames[basename] = n+1 + if n == 0: + return basename + else: + return self.uniquename('%s_%d' % (basename, n)) def nameof_object(self, value): if type(value) is not object: @@ -130,6 +129,22 @@ self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name + def nameof_float(self, value): + name = 'gfloat_%s' % value + name = (name.replace('-', 'minus') + .replace('.', 'dot')) + chrs = [c for c in name if ('a' <= c <='z' or + 'A' <= c <='Z' or + '0' <= c <='9' or + '_' == c )] + name = ''.join(chrs) + name = self.uniquename(name) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = ' + 'PyFloat_FromFloat(%r))' % (name, value)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) + return name + def nameof_str(self, value): chrs = [c for c in value if ('a' <= c <='z' or 'A' <= c <='Z' or @@ -150,11 +165,29 @@ self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name + def skipped_function(self, func): + # debugging only! Generates a placeholder for missing functions + # that raises an exception when called. + name = self.uniquename('gskippedfunc_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\tPy_INCREF(%s);' % name) + self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) + return name + def nameof_function(self, func): if self.translator.frozen: if func not in self.translator.flowgraphs: print "NOT GENERATING", func - return self.nameof(None) + return self.skipped_function(func) + else: + if func.func_doc and func.func_doc.startswith('NOT_RPYTHON'): + print "skipped", func + return self.skipped_function(func) + print "nameof", func name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' @@ -198,7 +231,10 @@ def should_translate_attr(self, pbc, attr): ann = self.translator.annotator if ann is None: - return "good luck" # True + if attr.startswith('_'): + return False # ignore _xyz and __xyz__ attributes + else: + return "probably" # True if attr in ann.getpbcattrs(pbc): return True classdef = ann.getuserclasses().get(pbc.__class__) @@ -348,7 +384,8 @@ def nameof_dict(self, dic): assert dic is not __builtins__ - assert '__builtins__' not in dic, 'It seems to be a globals dict' + assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( + dic.get('__name__', '?'),) name = self.uniquename('g%ddict' % len(dic)) def initdict(): for k in dic: @@ -384,6 +421,16 @@ nameof_method_descriptor = nameof_member_descriptor nameof_wrapper_descriptor = nameof_member_descriptor + def nameof_file(self, fil): + import sys + if fil is sys.stdin: + return 'PySys_GetObject("stdin")' + if fil is sys.stdout: + return 'PySys_GetObject("stdout")' + if fil is sys.stderr: + return 'PySys_GetObject("stderr")' + raise Exception, 'Cannot translate an already-open file: %r' % (fil,) + def gen_source(self): f = self.f info = { From tismer at codespeak.net Sat Nov 20 10:35:10 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 20 Nov 2004 10:35:10 +0100 (MET) Subject: [pypy-svn] r7488 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041120093510.1CBE95B3EC@thoth.codespeak.net> Author: tismer Date: Sat Nov 20 10:35:09 2004 New Revision: 7488 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: added bytecode offset information to the operations. Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sat Nov 20 10:35:09 2004 @@ -109,6 +109,7 @@ if not isinstance(self.crnt_ops, list): return next_instr = frame.next_instr + self.crnt_offset = next_instr # save offset for opcode if next_instr in self.joinpoints: currentstate = FrameState(frame) # can 'currentstate' be merged with one of the blocks that Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Sat Nov 20 10:35:09 2004 @@ -138,10 +138,11 @@ Constant.__init__(UNDEFINED, None) class SpaceOperation: - def __init__(self, opname, args, result): + def __init__(self, opname, args, result): self.opname = opname # operation name self.args = list(args) # mixed list of var/const self.result = result # either Variable or Constant instance + self.offset = -1 # offset in code string, to be added later def __eq__(self, other): return (self.__class__ is other.__class__ and Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 10:35:09 2004 @@ -172,6 +172,7 @@ def do_operation(self, name, *args_w): spaceop = SpaceOperation(name, args_w, Variable()) if hasattr(self, 'executioncontext'): # not here during bootstrapping + spaceop.offset = self.executioncontext.crnt_offset self.executioncontext.crnt_ops.append(spaceop) return spaceop.result From arigo at codespeak.net Sat Nov 20 10:35:26 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 10:35:26 +0100 (MET) Subject: [pypy-svn] r7489 - pypy/trunk/src/pypy/translator Message-ID: <20041120093526.B0CAC5B41B@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 10:35:26 2004 New Revision: 7489 Modified: pypy/trunk/src/pypy/translator/genc.py Log: print the modules where the functions come from. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 10:35:26 2004 @@ -179,15 +179,19 @@ return name def nameof_function(self, func): + printable_name = '(%s:%d) %s' % ( + func.func_globals.get('__name__', '?'), + func.func_code.co_firstlineno, + func.__name__) if self.translator.frozen: if func not in self.translator.flowgraphs: - print "NOT GENERATING", func + print "NOT GENERATING", printable_name return self.skipped_function(func) else: if func.func_doc and func.func_doc.startswith('NOT_RPYTHON'): - print "skipped", func + print "skipped", printable_name return self.skipped_function(func) - print "nameof", func + print "nameof", printable_name name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' From mgedmin at codespeak.net Sat Nov 20 10:43:41 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 10:43:41 +0100 (MET) Subject: [pypy-svn] r7490 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041120094341.7BA3C5B41C@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 10:43:40 2004 New Revision: 7490 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Mark in red all blocks that are blocked in function flow graphs. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sat Nov 20 10:43:40 2004 @@ -79,6 +79,10 @@ functions = functions or translator.functions graphs = [translator.getflowgraph(func) for func in functions] gs = [(graph.name, graph) for graph in graphs] + if self.annotator and self.annotator.blocked_functions: + for block, was_annotated in self.annotator.annotated.items(): + if not was_annotated: + block.fillcolor = "red" fn = make_dot_graphs(graphs[0].name + "_graph", gs, target='plain') GraphLayout.__init__(self, fn) # make the dictionary of links -- one per annotated variable From mgedmin at codespeak.net Sat Nov 20 10:55:18 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 10:55:18 +0100 (MET) Subject: [pypy-svn] r7491 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041120095518.74B255B416@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 10:55:17 2004 New Revision: 7491 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: Fiddled with highlight color selection. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sat Nov 20 10:55:17 2004 @@ -19,14 +19,25 @@ } re_nonword=re.compile(r'([^0-9a-zA-Z_.]+)') +def combine(color1, color2, alpha): + r1, g1, b1 = color1 + r2, g2, b2 = color2 + beta = 1.0 - alpha + return (int(r1 * alpha + r2 * beta), + int(g1 * alpha + g2 * beta), + int(b1 * alpha + b2 * beta)) + + def highlight_color(color): - intensity = sum(color) - components = [] - if color == (0,0,0): + if color == (0, 0, 0): # black becomes magenta return (255, 0, 255) - elif color == (255,255,255): + elif color == (255, 255, 255): # white becomes yellow return (255, 255, 0) - return color[1:] + color[:1] + intensity = sum(color) + if intensity > 191 * 3: + return combine(color, (128, 192, 0), 0.2) + else: + return combine(color, (255, 255, 0), 0.2) def getcolor(name, default): if name in COLOR: From arigo at codespeak.net Sat Nov 20 11:01:31 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 11:01:31 +0100 (MET) Subject: [pypy-svn] r7492 - pypy/trunk/src/pypy/translator Message-ID: <20041120100131.096D15B421@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 11:01:30 2004 New Revision: 7492 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Debugging helper: the 'debugstack' of the C code generator recording the stack of objects that eventually triggered an unexpected nameof(). Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 11:01:30 2004 @@ -55,13 +55,19 @@ self.globaldecl = [] self.pendingfunctions = [] self.initglobals = [] + self.debugstack = () # linked list of nested nameof() self.gen_source() - def nameof(self, obj): + def nameof(self, obj, debug=None): key = Constant(obj).key try: return self.cnames[key] except KeyError: + if debug: + stackentry = debug, obj + else: + stackentry = obj + self.debugstack = (self.debugstack, stackentry) if type(obj).__module__ != '__builtin__': # assume it's a user defined thingy name = self.nameof_instance(obj) @@ -75,6 +81,8 @@ else: raise Exception, "nameof(%r)" % (obj,) name = meth(obj) + self.debugstack, x = self.debugstack + assert x is stackentry self.cnames[key] = name return name @@ -247,6 +255,9 @@ return True return False + def later(self, gen): + self.latercode.append((gen, self.debugstack)) + def nameof_instance(self, instance): name = self.uniquename('ginst_' + instance.__class__.__name__) cls = self.nameof(instance.__class__) @@ -261,7 +272,7 @@ self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) - self.latercode.append(initinstance()) + self.later(initinstance()) return name def nameof_builtin_function_or_method(self, func): @@ -277,6 +288,9 @@ return name def nameof_classobj(self, cls): + if cls.__doc__ and cls.__doc__.startswith('NOT_RPYTHON'): + raise Exception, "%r should never be reached" % (cls,) + if issubclass(cls, Exception): if cls.__module__ == 'exceptions': return 'PyExc_%s'%cls.__name__ @@ -316,7 +330,7 @@ %("O"*len(basenames), cls.__name__, baseargs)) self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) - self.latercode.append(initclassobj()) + self.later(initclassobj()) return name nameof_class = nameof_classobj # for Python 2.2 @@ -383,7 +397,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) - self.latercode.append(initlist()) + self.later(initlist()) return name def nameof_dict(self, dic): @@ -404,7 +418,7 @@ self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) - self.latercode.append(initdict()) + self.later(initdict()) return name # strange prebuilt instances below, don't look too closely @@ -451,10 +465,11 @@ self.gen_cfunction(func) # collect more of the latercode after each function while self.latercode: - gen = self.latercode.pop(0) + gen, self.debugstack = self.latercode.pop(0) #self.initcode.extend(gen) -- eats TypeError! bad CPython! for line in gen: self.initcode.append(line) + self.debugstack = () self.gen_global_declarations() # footer @@ -482,7 +497,8 @@ ## func.__name__) f = self.f body = list(self.cfunction_body(func)) - name_of_defaults = [self.nameof(x) for x in (func.func_defaults or ())] + name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) + for x in (func.func_defaults or ())] self.gen_global_declarations() # print header @@ -585,7 +601,8 @@ if isinstance(v, Variable): return v.name elif isinstance(v, Constant): - return self.nameof(v.value) + return self.nameof(v.value, + debug=('Constant in the graph of',func)) else: raise TypeError, "expr(%r)" % (v,) From arigo at codespeak.net Sat Nov 20 11:06:03 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 11:06:03 +0100 (MET) Subject: [pypy-svn] r7493 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/std Message-ID: <20041120100603.447455B422@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 11:06:02 2004 New Revision: 7493 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/objspace.py Log: Some more NOT_RPYTHON annotations. Now classes can have this tag in their docstring, too, to mean that it's bad if we see the class at all during translation. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Sat Nov 20 11:06:02 2004 @@ -32,12 +32,13 @@ full_exceptions = True # full support for exceptions (normalization & more) def __init__(self): - "Basic initialization of objects." + "NOT_RPYTHON: Basic initialization of objects." self._gatewaycache = Cache() # sets all the internal descriptors self.initialize() def make_builtins(self, for_builtins): + "NOT_RPYTHON: only for initializing the space." # initializing builtins may require creating a frame which in # turn already accesses space.w_builtins, provide a dummy one ... self.w_builtins = self.newdict([]) @@ -68,6 +69,7 @@ self.sys.setbuiltinmodule(self.w_builtin, '__builtin__') def make_sys(self): + "NOT_RPYTHON: only for initializing the space." from pypy.interpreter.extmodule import BuiltinModule assert not hasattr(self, 'sys') self.sys = BuiltinModule(self, 'sys') @@ -87,8 +89,8 @@ return w_module def initialize(self): - """Abstract method that should put some minimal content into the - w_builtins.""" + """NOT_RPYTHON: Abstract method that should put some minimal + content into the w_builtins.""" def loadfromcache(self, key, builder, cache): return cache.getorbuild(key, builder, self) Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 11:06:02 2004 @@ -13,6 +13,12 @@ # ______________________________________________________________________ class FlowObjSpace(ObjSpace): + """NOT_RPYTHON. + The flow objspace space is used to produce a flow graph by recording + the space operations that the interpreter generates when it interprets + (the bytecode of) some function. + """ + full_exceptions = False def initialize(self): Modified: pypy/trunk/src/pypy/objspace/std/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/std/objspace.py Sat Nov 20 11:06:02 2004 @@ -48,6 +48,7 @@ PACKAGE_PATH = 'objspace.std' def standard_types(self): + "NOT_RPYTHON: only for initializing the space." class result: "Import here the types you want to have appear in __builtin__." @@ -68,6 +69,7 @@ if not key.startswith('_')] # don't look def clone_exception_hierarchy(self): + "NOT_RPYTHON: only for initializing the space." from pypy.objspace.std.typeobject import W_TypeObject from pypy.interpreter import gateway w = self.wrap @@ -136,6 +138,7 @@ return done def initialize(self): + "NOT_RPYTHON: only for initializing the space." self._typecache = Cache() # The object implementations that we want to 'link' into PyPy must be From arigo at codespeak.net Sat Nov 20 11:38:17 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 11:38:17 +0100 (MET) Subject: [pypy-svn] r7494 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/std translator Message-ID: <20041120103817.0BFDC5B424@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 11:38:17 2004 New Revision: 7494 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/interpreter/gateway.py pypy/trunk/src/pypy/interpreter/pycode.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/stdtypedef.py pypy/trunk/src/pypy/translator/genc.py Log: - next bunch of NOT_RPYTHON annotations. - support for built-in methods in genc.py. Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Sat Nov 20 11:38:17 2004 @@ -17,6 +17,10 @@ class BuiltinModule(Module): """A Module subclass specifically for built-in modules.""" + # '__builtins__' is stored in self.__dict__ by + # self.interplevel{exec,eval,execfile}() + NOT_RPYTHON_ATTRIBUTES = ['__builtins__'] + def __init__(self, space, modulename, w_dict=None, sourcefile=None): """Load the named built-in module, by default from the source file 'pypy/module/module.py', which is app-level Python code Modified: pypy/trunk/src/pypy/interpreter/gateway.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/gateway.py (original) +++ pypy/trunk/src/pypy/interpreter/gateway.py Sat Nov 20 11:38:17 2004 @@ -24,6 +24,7 @@ # you get the functionality of CPython's built-in function type. def __init__(self, func, ismethod=None, spacearg=None): + "NOT_RPYTHON" # 'implfunc' is the interpreter-level function. # Note that this uses a lot of (construction-time) introspection. eval.Code.__init__(self, func.__name__) @@ -176,6 +177,8 @@ # _staticglobals # _staticdefs + NOT_RPYTHON_ATTRIBUTES = ['_staticglobals', '_staticdefs'] + def __spacebind__(self, space): # to wrap a Gateway, we first make a real Function object out of it # and the result is a wrapped version of this Function. @@ -187,6 +190,7 @@ self.getcache(space)) def build_all_functions(self, space): + "NOT_RPYTHON" # the construction is supposed to be done only once in advance, # but must be done lazily when needed only, because # 1) it depends on the object space @@ -216,6 +220,7 @@ return space._gatewaycache def _build_function(self, space, w_globals): + "NOT_RPYTHON" cache = self.getcache(space) try: return cache.content[self] @@ -243,6 +248,7 @@ class app2interp(Gateway): """Build a Gateway that calls 'app' at app-level.""" def __init__(self, app, app_name=None): + "NOT_RPYTHON" Gateway.__init__(self) # app must be a function whose name starts with 'app_'. if not isinstance(app, types.FunctionType): @@ -259,6 +265,7 @@ self._staticdefs = list(app.func_defaults or ()) def getdefaults(self, space): + "NOT_RPYTHON" return [space.wrap(val) for val in self._staticdefs] def __call__(self, space, *args_w): @@ -268,6 +275,7 @@ return space.call_function(space.wrap(fn), *args_w) def __get__(self, obj, cls=None): + "NOT_RPYTHON" if obj is None: return self else: @@ -280,6 +288,7 @@ class interp2app(Gateway): """Build a Gateway that calls 'f' at interp-level.""" def __init__(self, f, app_name=None): + "NOT_RPYTHON" Gateway.__init__(self) # f must be a function whose name does NOT starts with 'app_' if not isinstance(f, types.FunctionType): @@ -295,10 +304,11 @@ self._staticglobals = None def getdefaults(self, space): + "NOT_RPYTHON" return self._staticdefs def exportall(d, temporary=False): - """Publish every function from a dict.""" + """NOT_RPYTHON: Publish every function from a dict.""" if temporary: i2a = interp2app_temp else: @@ -318,6 +328,7 @@ d['app_'+name] = i2a(obj, name) def export_values(space, dic, w_namespace): + "NOT_RPYTHON" for name, w_value in dic.items(): if name.startswith('w_'): if name == 'w_dict': @@ -329,7 +340,7 @@ space.setitem(w_namespace, w_name, w_value) def importall(d, temporary=False): - """Import all app_-level functions as Gateways into a dict.""" + """NOT_RPYTHON: Import all app_-level functions as Gateways into a dict.""" if temporary: a2i = app2interp_temp else: @@ -340,7 +351,8 @@ d[name[4:]] = a2i(obj, name[4:]) def build_dict(d, space): - """Search all Gateways and put them into a wrapped dictionary.""" + """NOT_RPYTHON: + Search all Gateways and put them into a wrapped dictionary.""" w_globals = space.newdict([]) for value in d.itervalues(): if isinstance(value, Gateway): @@ -356,12 +368,14 @@ # # the next gateways are to be used only for # temporary/initialization purposes -class app2interp_temp(app2interp): +class app2interp_temp(app2interp): + "NOT_RPYTHON" def getcache(self, space): return self.__dict__.setdefault(space, Cache()) # ^^^^^ # armin suggested this class interp2app_temp(interp2app): + "NOT_RPYTHON" def getcache(self, space): return self.__dict__.setdefault(space, Cache()) Modified: pypy/trunk/src/pypy/interpreter/pycode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pycode.py (original) +++ pypy/trunk/src/pypy/interpreter/pycode.py Sat Nov 20 11:38:17 2004 @@ -38,7 +38,8 @@ self.co_lnotab = "" # string: encoding addr<->lineno mapping def _from_code(self, code): - """ Initialize the code object from a real (CPython) one. + """ NOT_RPYTHON + Initialize the code object from a real (CPython) one. This is just a hack, until we have our own compile. At the moment, we just fake this. This method is called by our compile builtin function. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 11:38:17 2004 @@ -115,7 +115,7 @@ def build_flow(self, func, constargs={}): """ """ - if func.func_doc and func.func_doc.startswith('NOT_RPYTHON'): + if func.func_doc and func.func_doc.lstrip().startswith('NOT_RPYTHON'): raise Exception, "%r is tagged as NOT_RPYTHON" % (func,) code = func.func_code code = PyCode()._from_code(code) Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Sat Nov 20 11:38:17 2004 @@ -37,6 +37,7 @@ return _fake_type_cache.getorbuild(cpy_type, really_build_fake_type, None) def really_build_fake_type(cpy_type, ignored): + "NOT_RPYTHON (not remotely so!)." print 'faking %r'%(cpy_type,) kw = {} for s, v in cpy_type.__dict__.items(): Modified: pypy/trunk/src/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stdtypedef.py (original) +++ pypy/trunk/src/pypy/objspace/std/stdtypedef.py Sat Nov 20 11:38:17 2004 @@ -12,10 +12,12 @@ class StdTypeDef(TypeDef): def __init__(self, __name, __base=None, **rawdict): + "NOT_RPYTHON: initialization-time only." TypeDef.__init__(self, __name, __base, **rawdict) self.local_multimethods = [] def registermethods(self, namespace): + "NOT_RPYTHON: initialization-time only." self.local_multimethods += hack_out_multimethods(namespace) def issubtypedef(a, b): @@ -30,6 +32,7 @@ def newmethod(descr_new): + "NOT_RPYTHON: initialization-time only." # this is turned into a static method by the constructor of W_TypeObject. return gateway.interp2app(descr_new) @@ -40,6 +43,7 @@ # def buildtypeobject(typedef, space): + "NOT_RPYTHON: initialization-time only." # build a W_TypeObject from this StdTypeDef from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.objecttype import object_typedef @@ -76,6 +80,7 @@ overridetypedef=typedef, forcedict=False) def hack_out_multimethods(ns): + "NOT_RPYTHON: initialization-time only." result = [] for value in ns.itervalues(): if isinstance(value, MultiMethod): @@ -115,6 +120,7 @@ """A code object that invokes a multimethod.""" def __init__(self, multimethod, framecls, typeclass, bound_position=0): + "NOT_RPYTHON: initialization-time only." eval.Code.__init__(self, multimethod.operatorsymbol) self.basemultimethod = multimethod self.typeclass = typeclass @@ -131,6 +137,7 @@ self.sig = argnames, varargname, kwargname def computeslice(self, space): + "NOT_RPYTHON: initialization-time only." if self.typeclass is None: slice = self.basemultimethod else: Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 11:38:17 2004 @@ -196,7 +196,8 @@ print "NOT GENERATING", printable_name return self.skipped_function(func) else: - if func.func_doc and func.func_doc.startswith('NOT_RPYTHON'): + if (func.func_doc and + func.func_doc.lstrip().startswith('NOT_RPYTHON')): print "skipped", printable_name return self.skipped_function(func) print "nameof", printable_name @@ -243,8 +244,9 @@ def should_translate_attr(self, pbc, attr): ann = self.translator.annotator if ann is None: - if attr.startswith('_'): - return False # ignore _xyz and __xyz__ attributes + ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', []) + if attr in ignore: + return False else: return "probably" # True if attr in ann.getpbcattrs(pbc): @@ -277,18 +279,28 @@ def nameof_builtin_function_or_method(self, func): import __builtin__ - assert func is getattr(__builtin__, func.__name__, None), ( - '%r is not from __builtin__' % (func,)) - name = self.uniquename('gbltin_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' - 'PyEval_GetBuiltins(), "%s"))' % ( - name, func.__name__)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) + if func.__self__ is None: + # builtin function + assert func is getattr(__builtin__, func.__name__, None), ( + '%r is not from __builtin__' % (func,)) + name = self.uniquename('gbltin_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s"))' % ( + name, func.__name__)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) + else: + # builtin (bound) method + name = self.uniquename('gbltinmethod_' + func.__name__) + self.globaldecl.append('static PyObject* %s;' % name) + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(func.__self__), func.__name__)) + self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_classobj(self, cls): - if cls.__doc__ and cls.__doc__.startswith('NOT_RPYTHON'): + if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): raise Exception, "%r should never be reached" % (cls,) if issubclass(cls, Exception): @@ -465,7 +477,7 @@ self.gen_cfunction(func) # collect more of the latercode after each function while self.latercode: - gen, self.debugstack = self.latercode.pop(0) + gen, self.debugstack = self.latercode.pop() #self.initcode.extend(gen) -- eats TypeError! bad CPython! for line in gen: self.initcode.append(line) From arigo at codespeak.net Sat Nov 20 11:45:28 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 11:45:28 +0100 (MET) Subject: [pypy-svn] r7495 - pypy/trunk/src/pypy/interpreter Message-ID: <20041120104528.2068A5B029@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 11:45:27 2004 New Revision: 7495 Modified: pypy/trunk/src/pypy/interpreter/miscutils.py pypy/trunk/src/pypy/interpreter/pyopcode.py Log: unclean hacking to make the translator ignore __initclass__ Modified: pypy/trunk/src/pypy/interpreter/miscutils.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/miscutils.py (original) +++ pypy/trunk/src/pypy/interpreter/miscutils.py Sat Nov 20 11:45:27 2004 @@ -44,11 +44,10 @@ subclasses) by calling __initclass__() as a class method.""" def __init__(self, name, bases, dict): super(InitializedClass, self).__init__(name, bases, dict) - if hasattr(self, '__initclass__'): - raw = dict.get('__initclass__') + for basecls in self.__mro__: + raw = basecls.__dict__.get('__initclass__') if isinstance(raw, types.FunctionType): - self.__initclass__ = classmethod(raw) - self.__initclass__() + raw(self) # call it as a class method class RwDictProxy(object): Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Sat Nov 20 11:45:27 2004 @@ -769,6 +769,7 @@ __metaclass__ = InitializedClass def __initclass__(cls): + "NOT_RPYTHON" # create the 'cls.dispatch_table' attribute import dis dispatch_table = [] From arigo at codespeak.net Sat Nov 20 12:03:35 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:03:35 +0100 (MET) Subject: [pypy-svn] r7496 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041120110335.696715B051@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:03:34 2004 New Revision: 7496 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py Log: Initialize crnt_offset to -1, in case operations are generated before we enter the first bytecode. Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sat Nov 20 12:03:34 2004 @@ -80,6 +80,7 @@ ExecutionContext.__init__(self, space) self.code = code self.w_globals = w_globals = space.wrap(globals) + self.crnt_offset = -1 if closure is None: self.closure = None else: From arigo at codespeak.net Sat Nov 20 12:04:19 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:04:19 +0100 (MET) Subject: [pypy-svn] r7497 - in pypy/trunk/src/pypy: objspace/std translator Message-ID: <20041120110419.8F78F5B425@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:04:19 2004 New Revision: 7497 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/translator/genc.py Log: More NOT_RPYTHON tags. Support for type(None). Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Sat Nov 20 12:04:19 2004 @@ -38,6 +38,7 @@ i.e. the classes that are not bound to a specific space instance.""" def __init__(self, operatorsymbol, arity): + "NOT_RPYTHON: cannot create new multimethods dynamically" self.arity = arity self.operatorsymbol = operatorsymbol self.dispatch_table = {} @@ -50,6 +51,8 @@ return '<%s %s>' % (self.__class__.__name__, self.operatorsymbol) def register(self, function, *types): + """NOT_RPYTHON: cannot register new multimethod + implementations dynamically""" assert len(types) == self.arity functions = self.dispatch_table.setdefault(types, []) if function in functions: @@ -61,6 +64,7 @@ return True def adjust_dispatch_arity(self, types): + "NOT_RPYTHON" width = len(types) while width > self.dispatch_arity and types[width-1] is W_ANY: width -= 1 @@ -79,6 +83,7 @@ delegate) def do_compile_calllist(self, argclasses, delegate): + "NOT_RPYTHON" calllist = [] self.internal_buildcalllist(argclasses, delegate, calllist) calllist = tuple(calllist) @@ -90,13 +95,15 @@ return result def internal_compilecalllist(self, calllist): + "NOT_RPYTHON" source, glob = self.internal_sourcecalllist(calllist) # compile the function exec source in glob return glob['do'] def internal_sourcecalllist(self, calllist): - """Translate a call list into the source of a Python function + """NOT_RPYTHON + Translate a call list into the source of a Python function which is optimized and doesn't do repeated conversions on the same arguments.""" if len(calllist) == 1: @@ -171,7 +178,8 @@ return '\n'.join(source), glob def internal_buildcalllist(self, argclasses, delegate, calllist): - """Build a list of calls to try for the given classes of the + """NOT_RPYTHON + Build a list of calls to try for the given classes of the arguments. The list contains 'calls' of the following form: (function-to-call, list-of-list-of-converters) The list of converters contains a list of converter functions per @@ -252,7 +260,8 @@ expanded_dispcls = (curdispcls,) + expanded_dispcls def buildchoices(self, allowedtypes): - """Build a list of all possible implementations we can dispatch to, + """NOT_RPYTHON + Build a list of all possible implementations we can dispatch to, sorted best-first, ignoring delegation.""" # 'types' is a tuple of tuples of classes, one tuple of classes per # argument. (After delegation, we need to call buildchoice() with @@ -265,9 +274,10 @@ return result def postprocessresult(self, allowedtypes, result): - pass + "NOT_RPYTHON" def internal_buildchoices(self, initialtypes, currenttypes, result): + "NOT_RPYTHON" if len(currenttypes) == self.dispatch_arity: currenttypes += (W_ANY,) * (self.arity - self.dispatch_arity) for func in self.dispatch_table.get(currenttypes, []): @@ -287,7 +297,9 @@ class MultiMethod(AbstractMultiMethod): def __init__(self, operatorsymbol, arity, specialnames=None, **extras): - "MultiMethod dispatching on the first 'arity' arguments." + """NOT_RPYTHON: cannot create new multimethods dynamically. + MultiMethod dispatching on the first 'arity' arguments. + """ AbstractMultiMethod.__init__(self, operatorsymbol, arity) if arity < 1: raise ValueError, "multimethods cannot dispatch on nothing" @@ -307,6 +319,7 @@ get = __get__ def slice(self, typeclass, bound_position=0): + "NOT_RPYTHON" try: return self.unbound_versions[typeclass, bound_position] except KeyError: @@ -315,6 +328,8 @@ return m def register(self, function, *types): + """NOT_RPYTHON: cannot register new multimethod + implementations dynamically""" if not AbstractMultiMethod.register(self, function, *types): return False # register the function into unbound versions that match @@ -327,16 +342,20 @@ class DelegateMultiMethod(MultiMethod): def __init__(self): + "NOT_RPYTHON: cannot create new multimethods dynamically." MultiMethod.__init__(self, 'delegate', 1, []) self.key = object() def register(self, function, *types): + """NOT_RPYTHON: cannot register new multimethod + implementations dynamically""" if not AbstractMultiMethod.register(self, function, *types): return False self.key = object() # change the key to force recomputation return True def postprocessresult(self, allowedtypes, result): + "NOT_RPYTHON" # add delegation from a class to the *first* immediate parent class # and to W_ANY arg1types, = allowedtypes @@ -381,6 +400,7 @@ class UnboundMultiMethod(AbstractMultiMethod): def __init__(self, basemultimethod, typeclass, bound_position=0): + "NOT_RPYTHON: cannot create new multimethods dynamically." AbstractMultiMethod.__init__(self, basemultimethod.operatorsymbol, basemultimethod.arity) @@ -395,6 +415,8 @@ #print basemultimethod.operatorsymbol, typeclass, self.dispatch_table def register(self, function, *types): + """NOT_RPYTHON: cannot register new multimethod + implementations dynamically""" if not AbstractMultiMethod.register(self, function, *types): return False # propagate the function registeration to the base multimethod @@ -403,6 +425,7 @@ return True def match(self, types): + "NOT_RPYTHON" # check if the 'types' signature statically corresponds to the # restriction of the present UnboundMultiMethod. # Only accept an exact match; having merely subclass should Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 12:04:19 2004 @@ -361,6 +361,7 @@ complex:'&PyComplex_Type', unicode:'&PyUnicode_Type', file: '&PyFile_Type', + type(None): 'Py_None->ob_type', r_int: '&PyInt_Type', r_uint: '&PyInt_Type', From arigo at codespeak.net Sat Nov 20 12:12:06 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:12:06 +0100 (MET) Subject: [pypy-svn] r7498 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041120111206.C57705B43C@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:12:06 2004 New Revision: 7498 Modified: pypy/trunk/src/pypy/objspace/std/listobject.py Log: RPython-ify the implementation of list.sort(). Modified: pypy/trunk/src/pypy/objspace/std/listobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/listobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/listobject.py Sat Nov 20 12:12:06 2004 @@ -499,17 +499,33 @@ _quicksort(list, start, split-1, lt) # ... and sort both halves. _quicksort(list, split+1, end, lt) +class Comparer: + """Just a dumb container class for a space and a w_cmp, because + we can't use nested scopes for that in RPython. + """ + def __init__(self, space, w_cmp): + self.space = space + self.w_cmp = w_cmp + + def simple_lt(self, a, b): + space = self.space + return space.is_true(space.lt(a, b)) + + def complex_lt(self, a, b): + space = self.space + w_cmp = self.w_cmp + result = space.unwrap(space.call_function(w_cmp, a, b)) + if not isinstance(result,int): + raise OperationError(space.w_TypeError, + space.wrap("comparison function must return int")) + return result < 0 + def list_sort__List_ANY(space, w_list, w_cmp): + comparer = Comparer(space, w_cmp) if w_cmp is space.w_None: - def lt(a,b): - return space.is_true(space.lt(a,b)) + lt = comparer.simple_lt else: - def lt(a,b): - result = space.unwrap(space.call_function(w_cmp, a, b)) - if not isinstance(result,int): - raise OperationError(space.w_TypeError, - space.wrap("comparison function must return int")) - return result < 0 + lt = comparer.complex_lt # XXX Basic quicksort implementation # XXX this is not stable !! From arigo at codespeak.net Sat Nov 20 12:29:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:29:09 +0100 (MET) Subject: [pypy-svn] r7499 - in pypy/trunk/src/pypy: module translator Message-ID: <20041120112909.948DC5B112@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:29:09 2004 New Revision: 7499 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/sysinterp.py pypy/trunk/src/pypy/translator/genc.py Log: module hacks to make genc.py happy... Modified: pypy/trunk/src/pypy/module/__builtin__interp.py ============================================================================== --- pypy/trunk/src/pypy/module/__builtin__interp.py (original) +++ pypy/trunk/src/pypy/module/__builtin__interp.py Sat Nov 20 12:29:09 2004 @@ -1,7 +1,6 @@ """ Implementation of interpreter-level builtins. """ -import os from pypy.interpreter.module import Module from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError @@ -32,6 +31,7 @@ def try_import_mod(w_modulename, f, w_parent, w_name, pkgdir=None): + import os w = space.wrap if os.path.exists(f): w_mod = space.wrap(Module(space, w_modulename)) @@ -171,6 +171,7 @@ w_mod = space.get_builtin_module(modulename) if w_mod is not None: return w_mod + import os for path in space.unpackiterable(w_path): dir = os.path.join(space.unwrap(path), partname) if os.path.isdir(dir): Modified: pypy/trunk/src/pypy/module/sysinterp.py ============================================================================== --- pypy/trunk/src/pypy/module/sysinterp.py (original) +++ pypy/trunk/src/pypy/module/sysinterp.py Sat Nov 20 12:29:09 2004 @@ -1,8 +1,6 @@ """ Implementation of interpreter-level 'sys' routines. """ -import os -from pypy.interpreter import autopath #from pypy.interpreter.module import Module from pypy.interpreter.error import OperationError @@ -60,8 +58,12 @@ for fn in builtin_module_names]) # Initialize the default path +import os +from pypy.interpreter import autopath srcdir = os.path.dirname(autopath.pypydir) appdir = os.path.join(autopath.pypydir, 'appspace') +del os, autopath # XXX for the translator. Something is very wrong around here. + w_initialpath = space.newlist([space.wrap(''), space.wrap(appdir)] + [space.wrap(p) for p in cpy_sys.path if p!= srcdir]) @@ -115,4 +117,3 @@ else: return space.newtuple([operror.w_type,operror.w_value, space.wrap(operror.application_traceback)]) - Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 12:29:09 2004 @@ -3,7 +3,7 @@ """ from __future__ import generators -import autopath, os +import autopath, os, sys from pypy.objspace.flow.model import Variable, Constant, SpaceOperation from pypy.objspace.flow.model import FunctionGraph, Block, Link, last_exception from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph @@ -104,9 +104,9 @@ return name def nameof_module(self, value): -## assert not hasattr(value, "__file__") or \ -## not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py')), \ -## "%r is not a builtin module (probably :)"%value + assert not hasattr(value, "__file__") or \ + not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py') or value.__file__.endswith('.pyo')), \ + "%r is not a builtin module (probably :)"%value name = self.uniquename('mod%s'%value.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) @@ -278,16 +278,29 @@ return name def nameof_builtin_function_or_method(self, func): - import __builtin__ if func.__self__ is None: # builtin function - assert func is getattr(__builtin__, func.__name__, None), ( - '%r is not from __builtin__' % (func,)) + # where does it come from? Python2.2 doesn't have func.__module__ + for modname, module in sys.modules.items(): + if hasattr(module, '__file__'): + if (module.__file__.endswith('.py') or + module.__file__.endswith('.pyc') or + module.__file__.endswith('.pyo')): + continue # skip non-builtin modules + if func is getattr(module, func.__name__, None): + break + else: + raise Exception, '%r not found in any built-in module' % (func,) name = self.uniquename('gbltin_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) - self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' - 'PyEval_GetBuiltins(), "%s"))' % ( - name, func.__name__)) + if modname == '__builtin__': + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s"))' % ( + name, func.__name__)) + else: + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(module), func.__name__)) self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) else: # builtin (bound) method @@ -453,7 +466,6 @@ nameof_wrapper_descriptor = nameof_member_descriptor def nameof_file(self, fil): - import sys if fil is sys.stdin: return 'PySys_GetObject("stdin")' if fil is sys.stdout: From arigo at codespeak.net Sat Nov 20 12:41:43 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:41:43 +0100 (MET) Subject: [pypy-svn] r7500 - in pypy/trunk/src/pypy: interpreter translator Message-ID: <20041120114143.2615C5B113@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:41:42 2004 New Revision: 7500 Modified: pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: nameof(subclass_of_Exception) Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Sat Nov 20 12:41:42 2004 @@ -38,6 +38,7 @@ w_dict = self.w_dict # Compile the xxxmodule.py source file + self.__name__ = 'interpreter-level %s' % modulename self.__file__ = sourcefile or os.path.join(autopath.pypydir, 'module', modulename+'module.py') space.setitem(w_dict, space.wrap('__file__'), Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 12:41:42 2004 @@ -197,8 +197,7 @@ PyModule_AddStringConstant(m, "__sourcefile__", __FILE__); \ this_module_globals = PyModule_GetDict(m); \ PyGenCFunction_Type.tp_base = &PyCFunction_Type; \ - PyType_Ready(&PyGenCFunction_Type); \ - PyExc_OperationError = PyErr_NewException(#modname ".OperationError", NULL, NULL); + PyType_Ready(&PyGenCFunction_Type); /*** operations with a variable number of arguments ***/ @@ -596,8 +595,6 @@ } #endif -static PyObject* PyExc_OperationError; - #ifdef USE_CALL_TRACE static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 12:41:42 2004 @@ -316,13 +316,14 @@ if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): raise Exception, "%r should never be reached" % (cls,) + metaclass = "&PyType_Type" if issubclass(cls, Exception): if cls.__module__ == 'exceptions': return 'PyExc_%s'%cls.__name__ else: - assert cls.__name__ == "OperationError" - return 'PyExc_%s'%cls.__name__ - + # exceptions must be old-style classes (grr!) + metaclass = "&PyClass_Type" + name = self.uniquename('gcls_' + cls.__name__) basenames = [self.nameof(base) for base in cls.__bases__] def initclassobj(): @@ -349,8 +350,8 @@ baseargs = ", ".join(basenames) if baseargs: baseargs = ', '+baseargs - self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) &PyType_Type,' - %(name,)) + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) %s,' + %(name, metaclass)) self.initcode.append('\t\t"s(%s){}", "%s"%s))' %("O"*len(basenames), cls.__name__, baseargs)) From mgedmin at codespeak.net Sat Nov 20 12:51:30 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 12:51:30 +0100 (MET) Subject: [pypy-svn] r7501 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041120115130.C37D95B115@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 12:51:30 2004 New Revision: 7501 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: I just got an OverflowError while trying to zoom in a big function flow graph. This checkin adds extra clipping code that should prevent such errors. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sat Nov 20 12:51:30 2004 @@ -276,11 +276,21 @@ self.ofsx = noffsetx self.ofsy = noffsety - + def getboundingbox(self): "Get the rectangle where the graph will be rendered." return (-self.ofsx, -self.ofsy, self.width, self.height) + def visible(self, x1, y1, x2, y2): + "Is any part of the box visible (i.e. within the bounding box)? + + We have to perform clipping ourselves because with big graphs the + coordinates may sometimes become longs and cause OverflowErrors + within pygame. + " + return (x1 < self.width-self.ofsx and x2 > -self.ofsx and + y1 < self.height-self.ofsy and y2 > -self.ofsy) + def map(self, x, y): return (int(x*self.scale) - (self.ofsx - self.margin), int((self.bboxh-y)*self.scale) - (self.ofsy - self.margin)) @@ -392,7 +402,7 @@ if edge.highlight: fgcolor = highlight_color(fgcolor) points = [self.map(*xy) for xy in edge.bezierpoints()] - + def drawedgebody(points=points, fgcolor=fgcolor): pygame.draw.lines(self.screen, fgcolor, False, points) edgebodycmd.append(drawedgebody) @@ -402,14 +412,15 @@ def drawedgehead(points=points, fgcolor=fgcolor): pygame.draw.polygon(self.screen, fgcolor, points, 0) edgeheadcmd.append(drawedgehead) - + if edge.label: x, y = self.map(edge.xl, edge.yl) img = TextSnippet(self, edge.label, (0, 0, 0)) w, h = img.get_size() - def drawedgelabel(img=img, x1=x-w//2, y1=y-h//2): - img.draw(x1, y1) - edgeheadcmd.append(drawedgelabel) + if self.visible(x-w//2, y-h//2, x+w//2, y+h//2): + def drawedgelabel(img=img, x1=x-w//2, y1=y-h//2): + img.draw(x1, y1) + edgeheadcmd.append(drawedgelabel) return edgebodycmd + nodebkgndcmd + edgeheadcmd + nodecmd From arigo at codespeak.net Sat Nov 20 12:52:56 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:52:56 +0100 (MET) Subject: [pypy-svn] r7502 - pypy/trunk/src/pypy/module Message-ID: <20041120115256.DB9E75B116@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:52:56 2004 New Revision: 7502 Modified: pypy/trunk/src/pypy/module/sysinterp.py pypy/trunk/src/pypy/module/sysmodule.py Log: Moved sys.displayhook to app-level. Modified: pypy/trunk/src/pypy/module/sysinterp.py ============================================================================== --- pypy/trunk/src/pypy/module/sysinterp.py (original) +++ pypy/trunk/src/pypy/module/sysinterp.py Sat Nov 20 12:52:56 2004 @@ -95,15 +95,17 @@ "trying to change the builtin-in module %r" % (name,)) space.setitem(w_modules, space.wrap(name), w_module) -def displayhook(w_x): - w = space.wrap - if not space.is_true(space.is_(w_x, space.w_None)): - try: - # XXX don't use print, send to sys.stdout instead - print space.unwrap(space.repr(w_x)) - except OperationError: - print "! could not print", w_x - space.setitem(space.w_builtins, w('_'), w_x) +##def displayhook(w_x): +## w = space.wrap +## if not space.is_true(space.is_(w_x, space.w_None)): +## w_stdout = space.getattr(space.w_sys, space.wrap('stdout')) +## try: +## w_repr = space.repr(w_x) +## except OperationError: +## w_repr = space.wrap("! __repr__ raised an exception") +## w_repr = space.add(w_repr, space.wrap("\n")) +## space.call_method(w_stdout, 'write', +## space.setitem(space.w_builtins, w('_'), w_x) def _getframe(): # XXX No Argument Accepted Yet Modified: pypy/trunk/src/pypy/module/sysmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/sysmodule.py (original) +++ pypy/trunk/src/pypy/module/sysmodule.py Sat Nov 20 12:52:56 2004 @@ -15,7 +15,7 @@ from __interplevel__ import pypy_objspaceclass # Functions from interpreter-level -from __interplevel__ import displayhook, _getframe, exc_info +from __interplevel__ import _getframe, exc_info # Dummy executable = '' @@ -31,3 +31,8 @@ def exit(exitcode=0): raise SystemExit(exitcode) + +def displayhook(obj): + if obj is not None: + __builtins__['_'] = obj + stdout.write(`obj` + '\n') From mgedmin at codespeak.net Sat Nov 20 12:53:40 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 12:53:40 +0100 (MET) Subject: [pypy-svn] r7503 - in pypy/trunk/src/pypy/translator: . tool Message-ID: <20041120115340.A74505B44C@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 12:53:40 2004 New Revision: 7503 Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py pypy/trunk/src/pypy/translator/translator.py Log: Show source lines derived from bytecode offsets in every basic block. Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Sat Nov 20 12:53:40 2004 @@ -4,6 +4,7 @@ """ import autopath, os +import inspect, linecache from pypy.objspace.flow.model import * from pypy.objspace.flow import Space from pypy.tool.udir import udir @@ -78,6 +79,7 @@ def emit_subgraph(self, name, node): name = name.replace('.', '_') self.blocks = {} + self.func = None self.prefix = name self.enter_subgraph(name) traverse(self, node) @@ -101,6 +103,8 @@ if hasattr(funcgraph, 'source'): source = funcgraph.source.replace('"', '\\"') data += "\\n" + "\\l".join(source.split('\n')) + if hasattr(funcgraph, 'func'): + self.func = funcgraph.func self.emit_node(name, label=data, shape="box", fillcolor="green", style="filled") #('%(name)s [fillcolor="green", shape=box, label="%(data)s"];' % locals()) @@ -129,6 +133,22 @@ iargs = " ".join(map(repr, block.inputargs)) data = "%s(%s)\\ninputargs: %s\\n\\n" % (name, block.__class__.__name__, iargs) + if block.operations and self.func: + maxoffs = max([op.offset for op in block.operations]) + if maxoffs >= 0: + minoffs = min([op.offset for op in block.operations + if op.offset >= 0]) + minlineno = lineno_for_offset(self.func.func_code, minoffs) + maxlineno = lineno_for_offset(self.func.func_code, maxoffs) + filename = inspect.getsourcefile(self.func) + source = "\l".join([linecache.getline(filename, line).rstrip() + for line in range(minlineno, maxlineno+1)]) + if minlineno == maxlineno: + data = data + r"line %d:\n%s\l\n" % (minlineno, source) + else: + data = data + r"lines %d-%d:\n%s\l\n" % (minlineno, + maxlineno, source) + data = data + "\l".join(lines) data = data.replace('"', '\\"') # make dot happy @@ -146,6 +166,21 @@ label = "%s: %s" %(link.exitcase, label) self.emit_edge(name, name2, label, style="dotted", color=color) +def lineno_for_offset(code, offset): + """Calculate the source line number for a bytecode offset in a code object. + + Based on tb_lineno from Python 2.2's traceback.py + """ + tab = code.co_lnotab + lineno = code.co_firstlineno + addr = 0 + for i in range(0, len(tab), 2): + addr += ord(tab[i]) + if addr > offset: + break + lineno += ord(tab[i+1]) + return lineno + def make_dot(graphname, graph, storedir=None, target='ps'): return make_dot_graphs(graph.name, [(graphname, graph)], storedir, target) Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sat Nov 20 12:53:40 2004 @@ -80,6 +80,7 @@ self.functions.append(func) try: import inspect + graph.func = func graph.source = inspect.getsource(func) except IOError: pass # e.g. when func is defined interactively From mgedmin at codespeak.net Sat Nov 20 12:55:47 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 12:55:47 +0100 (MET) Subject: [pypy-svn] r7504 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041120115547.652E05B463@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 12:55:46 2004 New Revision: 7504 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Log: Big oops. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sat Nov 20 12:55:46 2004 @@ -282,12 +282,12 @@ return (-self.ofsx, -self.ofsy, self.width, self.height) def visible(self, x1, y1, x2, y2): - "Is any part of the box visible (i.e. within the bounding box)? + """Is any part of the box visible (i.e. within the bounding box)? We have to perform clipping ourselves because with big graphs the coordinates may sometimes become longs and cause OverflowErrors within pygame. - " + """ return (x1 < self.width-self.ofsx and x2 > -self.ofsx and y1 < self.height-self.ofsy and y2 > -self.ofsy) From hpk at codespeak.net Sat Nov 20 12:57:02 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 12:57:02 +0100 (MET) Subject: [pypy-svn] r7505 - pypy/trunk/src/pypy/annotation Message-ID: <20041120115702.9A5F55B470@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 12:57:02 2004 New Revision: 7505 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: "argtypes" specialization now looks a bit deeper, i.e. it looks at any knowntypes of SomeInstances. prevent a problem where we tried to remember information about a builtin's functions class. (storing that on the builtin itself doesn't work and we probably don't care for annotation purposes anyway). We should really flag "debugging" information more. do away with the "unprintanble instance" problem for the BlockedInference class (you always wonder what it might contain otherwise ...) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat Nov 20 12:57:02 2004 @@ -27,6 +27,9 @@ except AttributeError: self.break_at = None + def __repr__(self): + return "" %(self.break_at,) + __str__ = __repr__ class Bookkeeper: """The log of choices that have been made while analysing the operations. @@ -172,16 +175,21 @@ if func.im_self is not None: s_self = immutablevalue(func.im_self) args = [s_self] + list(args) - func.im_func.class_ = func.im_class + try: + func.im_func.class_ = func.im_class + except AttributeError: + # probably a builtin function, we don't care to preserve + # class information then + pass func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? x = getattr(func, '_specialize_', False) if x: if x == 'argtypes': - key = "_".join([arg.__class__.__name__ for arg in args]) - name = func.__name__+'_'+key - func = self.specialize_by_key(func, key, name) + key = short_type_name(args) + func = self.specialize_by_key(func, key, + func.__name__+'__'+key) elif x == "location": # fully specialize: create one version per call position func = self.specialize_by_key(func, self.position_key) @@ -212,6 +220,16 @@ self.bookkeeper.cachespecializations[key] = thing return thing +def short_type_name(args): + l = [] + for x in args: + if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'): + name = "SI_" + x.knowntype.__name__ + else: + name = x.__class__.__name__ + l.append(name) + return "__".join(l) + class ClassDef: "Wraps a user class." From arigo at codespeak.net Sat Nov 20 12:58:39 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 12:58:39 +0100 (MET) Subject: [pypy-svn] r7506 - pypy/trunk/src/pypy/module Message-ID: <20041120115839.277D65B475@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 12:58:38 2004 New Revision: 7506 Modified: pypy/trunk/src/pypy/module/sysmodule.py Log: A nicer version of sys.displayhook. Modified: pypy/trunk/src/pypy/module/sysmodule.py ============================================================================== --- pypy/trunk/src/pypy/module/sysmodule.py (original) +++ pypy/trunk/src/pypy/module/sysmodule.py Sat Nov 20 12:58:38 2004 @@ -35,4 +35,6 @@ def displayhook(obj): if obj is not None: __builtins__['_'] = obj - stdout.write(`obj` + '\n') + # NB. this is slightly more complicated in CPython, + # see e.g. the difference with >>> print 5,; 8 + print `obj` From arigo at codespeak.net Sat Nov 20 13:02:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 13:02:09 +0100 (MET) Subject: [pypy-svn] r7507 - pypy/trunk/src/pypy/module Message-ID: <20041120120209.863655B46A@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 13:02:09 2004 New Revision: 7507 Modified: pypy/trunk/src/pypy/module/sysinterp.py Log: NOT_RPYTHON. Modified: pypy/trunk/src/pypy/module/sysinterp.py ============================================================================== --- pypy/trunk/src/pypy/module/sysinterp.py (original) +++ pypy/trunk/src/pypy/module/sysinterp.py Sat Nov 20 13:02:09 2004 @@ -7,7 +7,7 @@ import sys as cpy_sys def hack_cpython_module(modname): - "Steal a module from CPython." + "NOT_RPYTHON. Steal a module from CPython." cpy_module = __import__(modname, globals(), locals(), None) return cpy_module ## # to build the dictionary of the module, we get all the objects From tismer at codespeak.net Sat Nov 20 13:06:26 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 20 Nov 2004 13:06:26 +0100 (MET) Subject: [pypy-svn] r7508 - pypy/trunk/src/pypy/interpreter Message-ID: <20041120120626.189005B47C@thoth.codespeak.net> Author: tismer Date: Sat Nov 20 13:06:25 2004 New Revision: 7508 Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py pypy/trunk/src/pypy/interpreter/function.py Log: a few decorations via __repr__ I don't know if this makes sense this way, but probably better than those long default names. Modified: pypy/trunk/src/pypy/interpreter/baseobjspace.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/baseobjspace.py (original) +++ pypy/trunk/src/pypy/interpreter/baseobjspace.py Sat Nov 20 13:06:25 2004 @@ -36,6 +36,9 @@ self._gatewaycache = Cache() # sets all the internal descriptors self.initialize() + + def __repr__(self): + return self.__class__.__name__ def make_builtins(self, for_builtins): "NOT_RPYTHON: only for initializing the space." Modified: pypy/trunk/src/pypy/interpreter/function.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/function.py (original) +++ pypy/trunk/src/pypy/interpreter/function.py Sat Nov 20 13:06:25 2004 @@ -25,6 +25,11 @@ self.defs_w = defs_w # list of w_default's self.w_func_dict = space.newdict([]) + def __repr__(self): + # return "function %s.%s" % (self.space, self.name) + # maybe we want this shorter: + return "func %s" % self.name + def call_args(self, args): scope_w = args.parse(self.name, self.code.signature(), self.defs_w) frame = self.code.create_frame(self.space, self.w_func_globals, @@ -83,6 +88,13 @@ self.w_function = w_function self.w_instance = w_instance # or None self.w_class = w_class + + def __repr__(self): + if self.w_instance: + pre = "bound" + else: + pre = "unbound" + return "%s method %s" % (pre, self.w_function.name) def call_args(self, args): if self.w_instance is not None: From hpk at codespeak.net Sat Nov 20 15:32:27 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 15:32:27 +0100 (MET) Subject: [pypy-svn] r7509 - pypy/trunk/src/pypy/translator Message-ID: <20041120143227.8294C5B138@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 15:32:27 2004 New Revision: 7509 Modified: pypy/trunk/src/pypy/translator/genc.py Log: nuke print statement which messes up running the tests ... Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 15:32:27 2004 @@ -200,7 +200,7 @@ func.func_doc.lstrip().startswith('NOT_RPYTHON')): print "skipped", printable_name return self.skipped_function(func) - print "nameof", printable_name + #print "nameof", printable_name name = self.uniquename('gfunc_' + func.__name__) self.globaldecl.append('static PyObject* %s;' % name) self.initcode.append('INITCHK(%s = PyCFunction_New(' From hpk at codespeak.net Sat Nov 20 15:37:26 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 15:37:26 +0100 (MET) Subject: [pypy-svn] r7510 - in pypy/trunk/src/pypy: objspace/flow translator translator/test Message-ID: <20041120143726.520FE5B13D@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 15:37:25 2004 New Revision: 7510 Modified: pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: don't block annotation when encountering functions that have no return path (i.e. they only raise exceptions). there is a once-per-flowgraph hasonlyexceptionreturns() method that traverses the graph to see if the return block is ever reached. added a test for func() calling another func which just raises an exception ... Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Sat Nov 20 15:37:25 2004 @@ -32,6 +32,22 @@ block.exits = () return block + def hasonlyexceptionreturns(self): + try: + return self._onlyex + except AttributeError: + def visit(link): + if isinstance(link, Link): + if link.target == self.returnblock: + raise ValueError(link) + try: + traverse(visit, self) + except ValueError: + self._onlyex = False + else: + self._onlyex = True + return self._onlyex + def show(self): from pypy.translator.tool.pygame.flowviewer import SingleGraphLayout SingleGraphLayout(self).display() Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat Nov 20 15:37:25 2004 @@ -207,9 +207,18 @@ inputcells.append(annmodel.immutablevalue(extra)) inputcells.extend(extracells) self.addpendingblock(func, block, inputcells, factory) + # get the (current) return value v = graph.getreturnvar() - return self.bindings.get(v, annmodel.SomeImpossibleValue()) + try: + return self.bindings[v] + except KeyError: + # let's see if the graph only has exception returns + if graph.hasonlyexceptionreturns(): + # XXX for functions with exceptions what to + # do anyway? + return annmodel.SomeNone() + return annmodel.SomeImpossibleValue() def reflowfromposition(self, position_key): fn, block, index = position_key Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Nov 20 15:37:25 2004 @@ -576,3 +576,10 @@ else: x = func2 return x + +def func_producing_exception(): + raise ValueError, "this might e.g. block the caller" + +def funccallsex(): + return func_producing_exception() + Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Sat Nov 20 15:37:25 2004 @@ -318,6 +318,13 @@ # but let's at least check *something* self.assert_(isinstance(s, SomeCallable)) + def test_func_calls_func_which_just_raises(self): + a = RPythonAnnotator() + s = a.build_types(snippet.funccallsex, []) + # the test is mostly that the above line hasn't blown up + # but let's at least check *something* + #self.assert_(isinstance(s, SomeCallable)) + def g(n): return [0,1,2,n] From bob at codespeak.net Sat Nov 20 16:10:02 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 16:10:02 +0100 (MET) Subject: [pypy-svn] r7511 - pypy/trunk/src/pypy/translator Message-ID: <20041120151002.073445B14B@thoth.codespeak.net> Author: bob Date: Sat Nov 20 16:10:02 2004 New Revision: 7511 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: clean up the generated code and header hack the traceback object to print a useful lineno when an op fails Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 16:10:02 2004 @@ -6,8 +6,9 @@ #include "compile.h" #include "frameobject.h" #include "structmember.h" +#include "traceback.h" -#ifndef MIN +#if !defined(MIN) #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ @@ -15,13 +16,13 @@ /* Turn this off if you don't want the call trace frames to be built */ #define USE_CALL_TRACE + #if 0 #define OBNOXIOUS_PRINT_STATEMENTS #endif -#define INSIDE_FUNCTION "" -#define op_richcmp(x,y,r,err,dir) \ - if (!(r=PyObject_RichCompare(x,y,dir))) goto err; +#define op_richcmp(x,y,r,err,dir) \ + if (!(r=PyObject_RichCompare(x,y,dir))) FAIL(err) #define OP_LT(x,y,r,err) op_richcmp(x,y,r,err, Py_LT) #define OP_LE(x,y,r,err) op_richcmp(x,y,r,err, Py_LE) #define OP_EQ(x,y,r,err) op_richcmp(x,y,r,err, Py_EQ) @@ -29,84 +30,88 @@ #define OP_GT(x,y,r,err) op_richcmp(x,y,r,err, Py_GT) #define OP_GE(x,y,r,err) op_richcmp(x,y,r,err, Py_GE) -#define OP_IS_(x,y,r,err) r = x == y ? Py_True : Py_False; Py_INCREF(r); +#define OP_IS_(x,y,r,err) \ + r = x == y ? Py_True : Py_False; Py_INCREF(r); -#define OP_IS_TRUE(x,r,err) switch (PyObject_IsTrue(x)) { \ - case 0: r=Py_False; break; \ - case 1: r=Py_True; break; \ - default: goto err; \ +#define OP_IS_TRUE(x,r,err) \ + switch (PyObject_IsTrue(x)) { \ + case 0: r=Py_False; break; \ + case 1: r=Py_True; break; \ + default: FAIL(err) \ } \ Py_INCREF(r); -#define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) goto err; -#define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) goto err; -#define OP_INVERT(x,r,err) if (!(r=PyNumber_Invert(x))) goto err; - -#define OP_ADD(x,y,r,err) if (!(r=PyNumber_Add(x,y))) goto err; -#define OP_SUB(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) goto err; -#define OP_MUL(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) goto err; -#define OP_TRUEDIV(x,y,r,err) if (!(r=PyNumber_TrueDivide(x,y))) goto err; -#define OP_FLOORDIV(x,y,r,err) if (!(r=PyNumber_FloorDivide(x,y)))goto err; -#define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) goto err; -#define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) goto err; -#define OP_POW(x,y,r,err) if (!(r=PyNumber_Power(x,y,Py_None)))goto err; -#define OP_LSHIFT(x,y,r,err) if (!(r=PyNumber_Lshift(x,y))) goto err; -#define OP_RSHIFT(x,y,r,err) if (!(r=PyNumber_Rshift(x,y))) goto err; -#define OP_AND_(x,y,r,err) if (!(r=PyNumber_And(x,y))) goto err; -#define OP_OR_(x,y,r,err) if (!(r=PyNumber_Or(x,y))) goto err; -#define OP_XOR(x,y,r,err) if (!(r=PyNumber_Xor(x,y))) goto err; +#define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) FAIL(err) +#define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) FAIL(err) +#define OP_INVERT(x,r,err) if (!(r=PyNumber_Invert(x))) FAIL(err) + +#define OP_ADD(x,y,r,err) if (!(r=PyNumber_Add(x,y))) FAIL(err) +#define OP_SUB(x,y,r,err) if (!(r=PyNumber_Subtract(x,y))) FAIL(err) +#define OP_MUL(x,y,r,err) if (!(r=PyNumber_Multiply(x,y))) FAIL(err) +#define OP_TRUEDIV(x,y,r,err) if (!(r=PyNumber_TrueDivide(x,y))) FAIL(err) +#define OP_FLOORDIV(x,y,r,err) if (!(r=PyNumber_FloorDivide(x,y)))FAIL(err) +#define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) FAIL(err) +#define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) FAIL(err) +#define OP_POW(x,y,r,err) if (!(r=PyNumber_Power(x,y,Py_None)))FAIL(err) +#define OP_LSHIFT(x,y,r,err) if (!(r=PyNumber_Lshift(x,y))) FAIL(err) +#define OP_RSHIFT(x,y,r,err) if (!(r=PyNumber_Rshift(x,y))) FAIL(err) +#define OP_AND_(x,y,r,err) if (!(r=PyNumber_And(x,y))) FAIL(err) +#define OP_OR_(x,y,r,err) if (!(r=PyNumber_Or(x,y))) FAIL(err) +#define OP_XOR(x,y,r,err) if (!(r=PyNumber_Xor(x,y))) FAIL(err) #define OP_INPLACE_ADD(x,y,r,err) if (!(r=PyNumber_InPlaceAdd(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_SUB(x,y,r,err) if (!(r=PyNumber_InPlaceSubtract(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_MUL(x,y,r,err) if (!(r=PyNumber_InPlaceMultiply(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_TRUEDIV(x,y,r,err) if (!(r=PyNumber_InPlaceTrueDivide(x,y)))\ - goto err; + FAIL(err) #define OP_INPLACE_FLOORDIV(x,y,r,err)if(!(r=PyNumber_InPlaceFloorDivide(x,y)))\ - goto err; + FAIL(err) #define OP_INPLACE_DIV(x,y,r,err) if (!(r=PyNumber_InPlaceDivide(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_MOD(x,y,r,err) if (!(r=PyNumber_InPlaceRemainder(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_POW(x,y,r,err) if (!(r=PyNumber_InPlacePower(x,y,Py_None))) \ - goto err; + FAIL(err) #define OP_INPLACE_LSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceLshift(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_RSHIFT(x,y,r,err) if (!(r=PyNumber_InPlaceRshift(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_AND(x,y,r,err) if (!(r=PyNumber_InPlaceAnd(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_OR(x,y,r,err) if (!(r=PyNumber_InPlaceOr(x,y))) \ - goto err; + FAIL(err) #define OP_INPLACE_XOR(x,y,r,err) if (!(r=PyNumber_InPlaceXor(x,y))) \ - goto err; + FAIL(err) -#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) goto err; -#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) goto err; \ +#define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) FAIL(err) +#define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) FAIL(err) \ r=Py_None; Py_INCREF(r); #define OP_CONTAINS(x,y,r,err) switch (PySequence_Contains(x,y)) { \ case 1: \ Py_INCREF(Py_True); r = Py_True; break; \ case 0: \ Py_INCREF(Py_False); r = Py_False; break; \ - default: goto err; } + default: FAIL(err) } -#define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) goto err; -#define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) goto err; \ +#define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) FAIL(err) +#define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) FAIL(err) \ r=Py_None; Py_INCREF(r); -#define OP_DELATTR(x,y,r,err) if ((PyObject_SetAttr(x,y,NULL))<0)goto err; \ +#define OP_DELATTR(x,y,r,err) if ((PyObject_SetAttr(x,y,NULL))<0)FAIL(err) \ r=Py_None; Py_INCREF(r); -#define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) goto err; +#define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) FAIL(err) -#define OP_ITER(x,r,err) if (!(r=PyObject_GetIter(x))) goto err; +#define OP_ITER(x,r,err) if (!(r=PyObject_GetIter(x))) FAIL(err) #define OP_NEXT(x,r,err) if (!(r=PyIter_Next(x))) { \ if (!PyErr_Occurred()) PyErr_SetNone(PyExc_StopIteration); \ - goto err; \ + FAIL(err) \ } +#define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ + FAIL(err) /*** tests ***/ @@ -141,6 +146,38 @@ #define SETUP_INSTANCE(i, cls) \ (i = PyType_GenericAlloc((PyTypeObject *)cls, 0)) + + +#if defined(USE_CALL_TRACE) + +#define FAIL(err) { __f->f_lineno = __LINE__; goto err; } + +#define FUNCTION_HEAD(signature, self, args, names, file, line) \ + PyThreadState *__tstate = PyThreadState_GET(); \ + PyObject *__localnames = PyList_CrazyStringPack names; \ + PyFrameObject *__f = traced_function_head(self, args, signature, file, line, __tstate, __localnames); + +#define FUNCTION_CHECK() \ + assert (__f != NULL); + +#define FUNCTION_RETURN(rval) return traced_function_tail(rval, __f, __tstate); + +#else /* !defined(USE_CALL_TRACE) */ + +#define FAIL(err) { goto err; } + +#define FUNCTION_HEAD(signature, self, args, names, file, line) + +#define FUNCTION_CHECK() + +#define FUNCTION_RETURN(rval) return rval; + +#endif /* defined(USE_CALL_TRACE) */ + + + + + /* we need a subclass of 'builtin_function_or_method' which can be used as methods: builtin function objects that can be bound on instances */ static PyObject * @@ -202,9 +239,9 @@ /*** operations with a variable number of arguments ***/ -#define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) goto err; -#define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) goto err; -#define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) goto err; +#define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) FAIL(err) +#define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) FAIL(err) +#define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) FAIL(err) #if defined(USE_CALL_TRACE) @@ -213,6 +250,130 @@ static int trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val); static int trace_frame_exc(PyThreadState *tstate, PyFrameObject *f); +static int +trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) +{ + int result = 0; + if (!tstate->use_tracing || tstate->tracing) { + /*printf("if (!tstate->use_tracing || tstate->tracing)\n");*/ + return 0; + } + if (tstate->c_profilefunc != NULL) { + /*printf("if (tstate->c_profilefunc != NULL)\n");*/ + tstate->tracing++; + result = tstate->c_profilefunc(tstate->c_profileobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + if (result) { + /*printf(" if (result)\n");*/ + return result; + } + } + if (tstate->c_tracefunc != NULL) { + /*printf("if (tstate->c_tracefunc != NULL)\n");*/ + tstate->tracing++; + result = tstate->c_tracefunc(tstate->c_traceobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + } + /*printf("return result;\n");*/ + return result; +} + +static int +trace_frame_exc(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *type, *value, *traceback, *arg; + int err; + + if (tstate->c_tracefunc == NULL) { + return 0; + } + + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = PyTuple_Pack(3, type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return 0; + } + err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg); + Py_DECREF(arg); + if (err == 0) { + PyErr_Restore(type, value, traceback); + } else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } + return err; +} + +static PyCodeObject* +getcode(char *func_name, char *func_filename, int lineno) +{ + PyObject *code = NULL; + PyObject *name = NULL; + PyObject *nulltuple = NULL; + PyObject *filename = NULL; + PyCodeObject *tb_code = NULL; + int i; + +#if defined(OBNOXIOUS_PRINT_STATEMENTS) + printf("%5d: ", lineno); + assert(callstack_depth >= 0); + if (callstack_depth) { + for (i=0; icurexc_traceback == NULL) { - PyTraceBack_Here(f); + if (PyTraceBack_Here(f) != -1) { + /* XXX - this is probably evil */ + ((PyTracebackObject*)tstate->curexc_traceback)->tb_lineno = f->f_lineno; + } } if (trace_frame_exc(tstate, f) < 0) { goto end; @@ -313,123 +474,6 @@ return rval; } -static PyObject *traced_function_call(PyObject *allargs, char *c_signature, char *filename, int c_lineno) { - /* - STEALS a reference to allargs - */ - PyFrameObject *f; - PyObject *rval; - PyThreadState *tstate; - PyObject *function; - PyObject *args; - - if (allargs == NULL) { - return NULL; - } - args = PyTuple_GetSlice(allargs, 1, PyTuple_Size(allargs)); - function = PyTuple_GetItem(allargs, 0); - if (args == NULL || function == NULL) { - return NULL; - } - Py_INCREF(function); - Py_DECREF(allargs); - - tstate = PyThreadState_GET(); - f = traced_function_head(function, args, c_signature, filename, c_lineno, tstate, NULL); - if (f == NULL) { - Py_DECREF(function); - Py_DECREF(args); - return NULL; - } - - rval = PyObject_Call(function, args, NULL); - Py_DECREF(function); - Py_DECREF(args); - return traced_function_tail(rval, f, tstate); -} - -#define OP_SIMPLE_CALL(args, r, err) if ((r = traced_function_call(PyTuple_CrazyPack args, INSIDE_FUNCTION " OP_SIMPLE_CALL" #args, __FILE__, __LINE__)) == NULL) \ - goto err; - -#define FUNCTION_HEAD(signature, self, args, names) \ - PyThreadState *__tstate = PyThreadState_GET(); \ - PyObject *__localnames = PyList_CrazyStringPack names; \ - PyFrameObject *__f = traced_function_head(self, args, signature, __FILE__, __LINE__, __tstate, __localnames); \ - if (__f == NULL) { \ - printf("frame is null, wtf?!\n"); \ - return NULL; \ - } - -#define FUNCTION_RETURN(rval) return traced_function_tail(rval, __f, __tstate); - - -#else - -#define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ - goto err; - -#define FUNCTION_HEAD(signature, self, args) -#define FUNCTION_RETURN(rval) return rval; - -#endif - -static PyObject* PyTuple_CrazyPack(PyObject *begin, ...) -{ - int i; - PyObject *o; - PyObject *result; - PyObject *tuple; - va_list vargs; - - result = PyList_New(0); - if (result == NULL || begin == NULL) { - return result; - } - va_start(vargs, begin); - if (PyList_Append(result, begin) == -1) { - Py_XDECREF(result); - return result; - } - while ((o = va_arg(vargs, PyObject *)) != NULL) { - if (PyList_Append(result, o) == -1) { - Py_XDECREF(result); - return NULL; - } - } - va_end(vargs); - if ((tuple = PySequence_Tuple(result)) == NULL) { - Py_DECREF(result); - return NULL; - } - Py_DECREF(result); - return tuple; -} - -static PyObject* PyList_CrazyPack(PyObject *begin, ...) -{ - int i; - PyObject *o; - PyObject *result; - va_list vargs; - - result = PyList_New(0); - if (result == NULL || begin == NULL) { - return result; - } - va_start(vargs, begin); - if (PyList_Append(result, begin) == -1) { - Py_XDECREF(result); - return result; - } - while ((o = va_arg(vargs, PyObject *)) != NULL) { - if (PyList_Append(result, o) == -1) { - Py_XDECREF(result); - return NULL; - } - } - va_end(vargs); - return result; -} static PyObject* PyList_CrazyStringPack(char *begin, ...) { int i; @@ -470,7 +514,7 @@ return result; } - +#endif /* defined(USE_CALL_TRACE) */ static PyObject* PyList_Pack(int n, ...) { @@ -595,127 +639,6 @@ } #endif -#ifdef USE_CALL_TRACE -static int -trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) -{ - int result = 0; - if (!tstate->use_tracing || tstate->tracing) { - return 0; - } - if (tstate->c_profilefunc != NULL) { - tstate->tracing++; - result = tstate->c_profilefunc(tstate->c_profileobj, - f, code , val); - tstate->use_tracing = ((tstate->c_tracefunc != NULL) - || (tstate->c_profilefunc != NULL)); - tstate->tracing--; - if (result) { - return result; - } - } - if (tstate->c_tracefunc != NULL) { - tstate->tracing++; - result = tstate->c_tracefunc(tstate->c_traceobj, - f, code , val); - tstate->use_tracing = ((tstate->c_tracefunc != NULL) - || (tstate->c_profilefunc != NULL)); - tstate->tracing--; - } - return result; -} - -static int -trace_frame_exc(PyThreadState *tstate, PyFrameObject *f) -{ - PyObject *type, *value, *traceback, *arg; - int err; - - if (tstate->c_tracefunc == NULL) { - return 0; - } - - PyErr_Fetch(&type, &value, &traceback); - if (value == NULL) { - value = Py_None; - Py_INCREF(value); - } - arg = PyTuple_Pack(3, type, value, traceback); - if (arg == NULL) { - PyErr_Restore(type, value, traceback); - return 0; - } - err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg); - Py_DECREF(arg); - if (err == 0) { - PyErr_Restore(type, value, traceback); - } else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - } - return err; -} - -static PyCodeObject* -getcode(char *func_name, char *func_filename, int lineno) -{ - PyObject *code = NULL; - PyObject *name = NULL; - PyObject *nulltuple = NULL; - PyObject *filename = NULL; - PyCodeObject *tb_code = NULL; - int i; - -#if defined(OBNOXIOUS_PRINT_STATEMENTS) - printf("%5d: ", lineno); - assert(callstack_depth >= 0); - if (callstack_depth) { - for (i=0; i> f, 'static PyObject* %s(PyObject* self, PyObject* args)' % ( - f_name,) + print >> f, 'static PyObject*' + print >> f, '%s(PyObject* self, PyObject* args)' % (f_name,) print >> f, '{' - print >> f, '\t#undef INSIDE_FUNCTION' - print >> f, '\t#define INSIDE_FUNCTION "%s"' % (f_name,) - print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s)' % ( + print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( c_string('%s(%s)' % (name, ', '.join(name_of_defaults))), name, '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), @@ -549,9 +547,11 @@ if isinstance(node, Block): localslst.extend(node.getvariables()) traverse(visit, graph) - for a in uniqueitems(localslst): - print >> f, '\tPyObject* %s;' % a.name + localnames = [a.name for a in uniqueitems(localslst)] + print >> f, '\tPyObject *%s;' % (', *'.join(localnames),) print >> f + + print >> f, '\tFUNCTION_CHECK()' # argument unpacking if func.func_code.co_flags & CO_VARARGS: @@ -606,8 +606,6 @@ else: fmt = '%s\n' f.write(fmt % line) - print >> f, '#undef INSIDE_FUNCTION' - print >> f, '#define INSIDE_FUNCTION "unknown"' print >> f, '}' # print the PyMethodDef From mwh at codespeak.net Sat Nov 20 16:33:21 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 20 Nov 2004 16:33:21 +0100 (MET) Subject: [pypy-svn] r7512 - pypy/trunk/src/pypy/annotation Message-ID: <20041120153321.3AC3C5B156@thoth.codespeak.net> Author: mwh Date: Sat Nov 20 16:33:20 2004 New Revision: 7512 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: This seems to work around a bug in dot? Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat Nov 20 16:33:20 2004 @@ -266,7 +266,7 @@ self.generalize(name, s_value, bookkeeper) def __repr__(self): - return '' % (self.cls.__module__, self.cls.__name__) + return "" % (self.cls.__module__, self.cls.__name__) def commonbase(self, other): while other is not None and not issubclass(self.cls, other.cls): From tismer at codespeak.net Sat Nov 20 16:33:25 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 20 Nov 2004 16:33:25 +0100 (MET) Subject: [pypy-svn] r7513 - pypy/trunk/src/pypy/translator Message-ID: <20041120153325.65A465B164@thoth.codespeak.net> Author: tismer Date: Sat Nov 20 16:33:24 2004 New Revision: 7513 Modified: pypy/trunk/src/pypy/translator/simplify.py Log: in order to (ab)use flow space and simplify for regular python, I added an "rpython" option which defaults to true. Not saure if this is ok, but Armin will complain if not. :) Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Sat Nov 20 16:33:24 2004 @@ -80,11 +80,12 @@ link.prevblock.exits = tuple(lst) traverse(visit, graph) -def simplify_graph(graph): +def simplify_graph(graph, rpython=True): """inplace-apply all the existing optimisations to the graph.""" checkgraph(graph) eliminate_empty_blocks(graph) - remove_implicit_exceptions(graph) + if rpython: + remove_implicit_exceptions(graph) join_blocks(graph) checkgraph(graph) From bob at codespeak.net Sat Nov 20 16:35:22 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 16:35:22 +0100 (MET) Subject: [pypy-svn] r7514 - in pypy/trunk/src: goal pypy/translator/tool/pygame Message-ID: <20041120153522.258F25B157@thoth.codespeak.net> Author: bob Date: Sat Nov 20 16:35:21 2004 New Revision: 7514 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: avoid threads when not necessary (-text) make pdb the "controlling terminal" by giving graphdisplay an async quit method that the pdb thread can fire, and join the pdb thread if graphdisplay quits first. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Sat Nov 20 16:35:21 2004 @@ -100,6 +100,12 @@ someobjnum, num) print "=" * 70 +def run_in_thread(fn, args, cleanup=None, cleanup_args=()): + def _run_in_thread(): + fn(*args) + if cleanup is not None: + cleanup(*cleanup_args) + return threading.Thread(target=_run_in_thread, args=()) if __name__ == '__main__': @@ -142,8 +148,10 @@ def run_server(): from pypy.translator.tool.pygame.flowviewer import TranslatorLayout from pypy.translator.tool.pygame.graphdisplay import GraphDisplay + import pygame display = GraphDisplay(TranslatorLayout(t)) - display.run() + async_quit = display.async_quit + return display.run, async_quit, pygame.quit def debug(got_error): if got_error: @@ -160,19 +168,21 @@ print '-'*60 print >> sys.stderr - th = threading.Thread(target=pdb.post_mortem, args=(tb,)) + func, args = pdb.post_mortem, (tb,) else: print '-'*60 print 'Done.' print - th = threading.Thread(target=pdb.set_trace, args=()) - th.start() + func, args = pdb.set_trace, () if options['-text']: - th.join() + func(*args) else: - run_server() - import pygame - pygame.quit() + start, stop, cleanup = run_server() + debugger = run_in_thread(func, args, stop) + debugger.start() + start() + debugger.join() + cleanup() try: analyse() Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Sat Nov 20 16:35:21 2004 @@ -565,6 +565,9 @@ def process_Quit(self, event): self.quit() + def async_quit(self): + pygame.event.post(pygame.event.Event(QUIT)) + def quit(self): raise StopIteration From bob at codespeak.net Sat Nov 20 16:59:31 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 16:59:31 +0100 (MET) Subject: [pypy-svn] r7515 - pypy/trunk/src/pypy/translator Message-ID: <20041120155931.38EC95B159@thoth.codespeak.net> Author: bob Date: Sat Nov 20 16:59:30 2004 New Revision: 7515 Modified: pypy/trunk/src/pypy/translator/genc.h Log: PyTracebackObject wasn't public in Python 2.3. Ugh. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 16:59:30 2004 @@ -8,6 +8,17 @@ #include "structmember.h" #include "traceback.h" +#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ +struct _frame; +typedef struct _traceback { + PyObject_HEAD + struct _traceback *tb_next; + struct _frame *tb_frame; + int tb_lasti; + int tb_lineno; +} PyTracebackObject; +#endif + #if !defined(MIN) #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ From mgedmin at codespeak.net Sat Nov 20 17:00:06 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 17:00:06 +0100 (MET) Subject: [pypy-svn] r7516 - pypy/trunk/src/pypy/translator Message-ID: <20041120160006.C09885B47D@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 17:00:06 2004 New Revision: 7516 Modified: pypy/trunk/src/pypy/translator/transform.py Log: Ignore partially annotated (aka "blocked") blocks in transform_dead_code. Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Sat Nov 20 17:00:06 2004 @@ -314,7 +314,11 @@ """Remove dead code: these are the blocks that are not annotated at all because the annotation considered that no conditional jump could reach them.""" - for block in self.annotated: + for block, is_annotated in self.annotated.items(): + if not is_annotated: + # We do not want to accidentally turn blocked blocks into return + # blocks + continue for link in block.exits: if link not in self.links_followed: lst = list(block.exits) From mgedmin at codespeak.net Sat Nov 20 17:00:40 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 17:00:40 +0100 (MET) Subject: [pypy-svn] r7517 - pypy/trunk/src/goal Message-ID: <20041120160040.081FC5B481@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 17:00:39 2004 New Revision: 7517 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Make --mark-some-objects cope with the situation of missing annotations. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Sat Nov 20 17:00:39 2004 @@ -63,7 +63,10 @@ return False def short_binding(var): - binding = annotator.binding(var) + try: + binding = annotator.binding(var) + except KeyError: + return "?" if binding.is_constant(): return 'const %s' % binding.__class__.__name__ else: From tismer at codespeak.net Sat Nov 20 17:15:51 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 20 Nov 2004 17:15:51 +0100 (MET) Subject: [pypy-svn] r7518 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041120161551.A76885B17B@thoth.codespeak.net> Author: tismer Date: Sat Nov 20 17:15:51 2004 New Revision: 7518 Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py Log: replaced lineno_by_offset by pytraceback.offset2lineno Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Sat Nov 20 17:15:51 2004 @@ -9,6 +9,7 @@ from pypy.objspace.flow import Space from pypy.tool.udir import udir from py.process import cmdexec +from pypy.interpreter.pytraceback import offset2lineno class DotGen: @@ -138,8 +139,8 @@ if maxoffs >= 0: minoffs = min([op.offset for op in block.operations if op.offset >= 0]) - minlineno = lineno_for_offset(self.func.func_code, minoffs) - maxlineno = lineno_for_offset(self.func.func_code, maxoffs) + minlineno = offset2lineno(self.func.func_code, minoffs) + maxlineno = offset2lineno(self.func.func_code, maxoffs) filename = inspect.getsourcefile(self.func) source = "\l".join([linecache.getline(filename, line).rstrip() for line in range(minlineno, maxlineno+1)]) @@ -166,21 +167,6 @@ label = "%s: %s" %(link.exitcase, label) self.emit_edge(name, name2, label, style="dotted", color=color) -def lineno_for_offset(code, offset): - """Calculate the source line number for a bytecode offset in a code object. - - Based on tb_lineno from Python 2.2's traceback.py - """ - tab = code.co_lnotab - lineno = code.co_firstlineno - addr = 0 - for i in range(0, len(tab), 2): - addr += ord(tab[i]) - if addr > offset: - break - lineno += ord(tab[i+1]) - return lineno - def make_dot(graphname, graph, storedir=None, target='ps'): return make_dot_graphs(graph.name, [(graphname, graph)], storedir, target) From hpk at codespeak.net Sat Nov 20 17:28:27 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 17:28:27 +0100 (MET) Subject: [pypy-svn] r7519 - in pypy/trunk/src/pypy: objspace/flow translator/test Message-ID: <20041120162827.7EF605B17D@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 17:28:26 2004 New Revision: 7519 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: allow tuple assignment/unpacking to retain type information by special casing unpackiterable to treat the case where it receives a Constant and has to return an expected_length number of items ... Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 17:28:26 2004 @@ -171,6 +171,10 @@ items.append(w_item) i += 1 return items + elif isinstance(w_iterable, Constant) and expected_length is not None: + assert len(w_iterable.value) == expected_length + return [self.do_operation('getitem', w_iterable, self.wrap(i)) + for i in range(expected_length)] # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK return ObjSpace.unpackiterable(self, w_iterable, expected_length) Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sat Nov 20 17:28:26 2004 @@ -583,3 +583,7 @@ def funccallsex(): return func_producing_exception() + +def func_arg_unpack(): + a,b = 3, "hello" + return a Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Sat Nov 20 17:28:26 2004 @@ -325,6 +325,12 @@ # but let's at least check *something* #self.assert_(isinstance(s, SomeCallable)) + def test_tuple_unpack_from_const_tuple_with_different_types(self): + a = RPythonAnnotator() + s = a.build_types(snippet.func_arg_unpack, []) + self.assert_(isinstance(s, annmodel.SomeInteger)) + self.assertEquals(s.const, 3) + def g(n): return [0,1,2,n] From mwh at codespeak.net Sat Nov 20 17:28:31 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Sat, 20 Nov 2004 17:28:31 +0100 (MET) Subject: [pypy-svn] r7520 - pypy/trunk/src/pypy/annotation Message-ID: <20041120162831.4C70E5B49E@thoth.codespeak.net> Author: mwh Date: Sat Nov 20 17:28:30 2004 New Revision: 7520 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Slightly de-Rigo the code. Well, I find this version easier to understand, but maybe that's just because I wrote it... Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat Nov 20 17:28:30 2004 @@ -251,7 +251,6 @@ if self.basedef: self.basedef.subdefs[cls] = self # collect the (supposed constant) class attributes - s_self = SomeInstance(self) for name, value in cls.__dict__.items(): # ignore some special attributes if name.startswith('_') and not isinstance(value, FunctionType): @@ -263,7 +262,7 @@ # generalizes existing values in parent classes s_value = immutablevalue(value) s_value = s_value.bindcallables(self) - self.generalize(name, s_value, bookkeeper) + self.generalize_attr(name, s_value, bookkeeper) def __repr__(self): return "" % (self.cls.__module__, self.cls.__name__) @@ -294,15 +293,8 @@ factories.update(clsdef.instancefactories) return factories - def generalize(self, attr, s_value, bookkeeper=None, readonly=True): - # we make sure that an attribute never appears both in a class - # and in some subclass, in two steps: - # (1) check if the attribute is already in a superclass - for clsdef in self.getmro(): - if attr in clsdef.attrs: - self = clsdef # generalize the parent class instead - break - # (2) remove the attribute from subclasses + def _generalize_attr(self, attr, s_value, bookkeeper, readonly): + # first remove the attribute from subclasses -- including us! subclass_values = [] for subdef in self.getallsubdefs(): if attr in subdef.attrs: @@ -312,13 +304,26 @@ del subdef.readonly[attr] # bump the revision number of this class and all subclasses subdef.revision += 1 + + # do the generalization self.attrs[attr] = unionof(s_value, *subclass_values) self.readonly[attr] = readonly + # reflow from all factories if bookkeeper: for factory in self.getallfactories(): bookkeeper.annotator.reflowfromposition(factory.position_key) + + def generalize_attr(self, attr, s_value, bookkeeper=None, readonly=True): + # if the attribute exists in a superclass, generalize there. + for clsdef in self.getmro(): + if attr in clsdef.attrs: + clsdef._generalize_attr(attr, s_value, bookkeeper, readonly) + return + else: + self._generalize_attr(attr, s_value, bookkeeper, readonly) + def about_attribute(self, name): for cdef in self.getmro(): if name in cdef.attrs: Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Sat Nov 20 17:28:30 2004 @@ -126,7 +126,7 @@ return clsdef.attrs[attr] # maybe the attribute exists in some subclass? if so, lift it clsdef = ins.classdef - clsdef.generalize(attr, SomeImpossibleValue(), getbookkeeper()) + clsdef.generalize_attr(attr, SomeImpossibleValue(), getbookkeeper()) raise BlockedInference return SomeObject() @@ -145,7 +145,7 @@ # if the attribute doesn't exist yet, create it here clsdef = ins.classdef # create or update the attribute in clsdef - clsdef.generalize(attr, s_value, getbookkeeper(), readonly=False) + clsdef.generalize_attr(attr, s_value, getbookkeeper(), readonly=False) raise BlockedInference return SomeObject() From hpk at codespeak.net Sat Nov 20 17:41:32 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Sat, 20 Nov 2004 17:41:32 +0100 (MET) Subject: [pypy-svn] r7521 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041120164132.AEA1E5B485@thoth.codespeak.net> Author: hpk Date: Sat Nov 20 17:41:32 2004 New Revision: 7521 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: do the unpackiterable-hack more often: it's reasonably safe to assume that if have an expected length for a given w_iterable that we can perform getitem's on the object Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 17:41:32 2004 @@ -171,8 +171,7 @@ items.append(w_item) i += 1 return items - elif isinstance(w_iterable, Constant) and expected_length is not None: - assert len(w_iterable.value) == expected_length + elif expected_length is not None: return [self.do_operation('getitem', w_iterable, self.wrap(i)) for i in range(expected_length)] # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK From bob at codespeak.net Sat Nov 20 18:13:06 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 18:13:06 +0100 (MET) Subject: [pypy-svn] r7522 - pypy/trunk/src/pypy/translator Message-ID: <20041120171306.2A22C5B172@thoth.codespeak.net> Author: bob Date: Sat Nov 20 18:13:05 2004 New Revision: 7522 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: locals as of the opcode that failed are now available in the frame dict Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 18:13:05 2004 @@ -8,17 +8,6 @@ #include "structmember.h" #include "traceback.h" -#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ -struct _frame; -typedef struct _traceback { - PyObject_HEAD - struct _traceback *tb_next; - struct _frame *tb_frame; - int tb_lasti; - int tb_lineno; -} PyTracebackObject; -#endif - #if !defined(MIN) #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ @@ -161,7 +150,7 @@ #if defined(USE_CALL_TRACE) -#define FAIL(err) { __f->f_lineno = __LINE__; goto err; } +#define FAIL(err) { __f->f_lineno = __f->f_code->co_firstlineno = __LINE__; goto err; } #define FUNCTION_HEAD(signature, self, args, names, file, line) \ PyThreadState *__tstate = PyThreadState_GET(); \ @@ -171,6 +160,8 @@ #define FUNCTION_CHECK() \ assert (__f != NULL); +#define ERR_DECREF(arg) { if (__f->f_locals) { PyDict_SetItemString(__f->f_locals, #arg, arg); } Py_DECREF(arg); } + #define FUNCTION_RETURN(rval) return traced_function_tail(rval, __f, __tstate); #else /* !defined(USE_CALL_TRACE) */ @@ -179,6 +170,7 @@ #define FUNCTION_HEAD(signature, self, args, names, file, line) +#define ERR_DECREF(arg) { Py_DECREF(arg); } #define FUNCTION_CHECK() #define FUNCTION_RETURN(rval) return rval; @@ -463,10 +455,7 @@ } if (rval == NULL) { if (tstate->curexc_traceback == NULL) { - if (PyTraceBack_Here(f) != -1) { - /* XXX - this is probably evil */ - ((PyTracebackObject*)tstate->curexc_traceback)->tb_lineno = f->f_lineno; - } + PyTraceBack_Here(f); } if (trace_frame_exc(tstate, f) < 0) { goto end; Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 18:13:05 2004 @@ -53,8 +53,8 @@ # for later in initxxx() -- for recursive # objects self.globaldecl = [] + self.globalobjects = [] self.pendingfunctions = [] - self.initglobals = [] self.debugstack = () # linked list of nested nameof() self.gen_source() @@ -98,9 +98,8 @@ if type(value) is not object: raise Exception, "nameof(%r)" % (value,) name = self.uniquename('g_object') - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_module(self, value): @@ -108,9 +107,8 @@ not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py') or value.__file__.endswith('.pyo')), \ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod%s'%value.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name @@ -119,10 +117,9 @@ name = 'gint_%d' % value else: name = 'gint_minus%d' % abs(value) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = ' 'PyInt_FromLong(%d))' % (name, value)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_long(self, value): @@ -131,10 +128,9 @@ name = 'glong%d' % value else: name = 'glong_minus%d' % abs(value) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = ' 'PyLong_FromLong(%d))' % (name, value)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_float(self, value): @@ -147,10 +143,9 @@ '_' == c )] name = ''.join(chrs) name = self.uniquename(name) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = ' 'PyFloat_FromFloat(%r))' % (name, value)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_str(self, value): @@ -159,7 +154,7 @@ '0' <= c <='9' or '_' == c )] name = self.uniquename('gstr_' + ''.join(chrs)) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) if [c for c in value if not (' '<=c<='~')]: # non-printable string s = 'chr_%s' % name @@ -170,20 +165,18 @@ s = '"%s"' % value self.initcode.append('INITCHK(%s = PyString_FromStringAndSize(' '%s, %d))' % (name, s, len(value))) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def skipped_function(self, func): # debugging only! Generates a placeholder for missing functions # that raises an exception when called. name = self.uniquename('gskippedfunc_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) self.initcode.append('\tPy_INCREF(%s);' % name) self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_function(self, func): @@ -202,11 +195,10 @@ return self.skipped_function(func) #print "nameof", printable_name name = self.uniquename('gfunc_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.pendingfunctions.append(func) return name @@ -217,10 +209,9 @@ assert func in self.translator.flowgraphs, func name = self.uniquename('gsm_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.pendingfunctions.append(func) return name @@ -234,11 +225,10 @@ func = self.nameof(meth.im_func) typ = self.nameof(meth.im_class) name = self.uniquename('gmeth_'+meth.im_func.__name__) - self.globaldecl.append('static PyObject* %s;'%(name,)) + self.globalobjects.append(name) self.initcode.append( 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( name, func, ob, typ)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def should_translate_attr(self, pbc, attr): @@ -270,10 +260,9 @@ if self.should_translate_attr(instance, key): yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.later(initinstance()) return name @@ -292,7 +281,7 @@ else: raise Exception, '%r not found in any built-in module' % (func,) name = self.uniquename('gbltin_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) if modname == '__builtin__': self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' 'PyEval_GetBuiltins(), "%s"))' % ( @@ -301,15 +290,13 @@ self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' '%s, "%s"))' % ( name, self.nameof(module), func.__name__)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) else: # builtin (bound) method name = self.uniquename('gbltinmethod_' + func.__name__) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' '%s, "%s"))' % ( name, self.nameof(func.__self__), func.__name__)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_classobj(self, cls): @@ -345,7 +332,7 @@ yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) baseargs = ", ".join(basenames) if baseargs: @@ -355,7 +342,6 @@ self.initcode.append('\t\t"s(%s){}", "%s"%s))' %("O"*len(basenames), cls.__name__, baseargs)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.later(initclassobj()) return name @@ -406,12 +392,11 @@ def nameof_tuple(self, tup): name = self.uniquename('g%dtuple' % len(tup)) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) args = [self.nameof(x) for x in tup] args.insert(0, '%d' % len(tup)) args = ', '.join(args) self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name def nameof_list(self, lis): @@ -421,9 +406,8 @@ item = self.nameof(lis[i]) yield '\tPy_INCREF(%s);' % item yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.later(initlist()) return name @@ -442,9 +426,8 @@ yield ('\tINITCHK(PyDict_SetItem' '(%s, %s, %s) >= 0)'%( name, self.nameof(k), self.nameof(dic[k]))) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) self.later(initdict()) return name @@ -453,14 +436,13 @@ def nameof_member_descriptor(self, md): name = self.uniquename('gdescriptor_%s_%s' % ( md.__objclass__.__name__, md.__name__)) - self.globaldecl.append('static PyObject* %s;' % name) + self.globalobjects.append(name) cls = self.nameof(md.__objclass__) self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % cls) self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' '((PyTypeObject*) %s)->tp_dict, "%s"))' % (name, cls, md.__name__)) - self.initglobals.append('REGISTER_GLOBAL(%s)' % (name,)) return name nameof_getset_descriptor = nameof_member_descriptor nameof_method_descriptor = nameof_member_descriptor @@ -502,12 +484,14 @@ print >> f, self.C_INIT_HEADER % info for codeline in self.initcode: print >> f, '\t' + codeline - for codeline in self.initglobals: - print >> f, '\t' + codeline + for name in self.globalobjects: + print >> f, '\t' + 'REGISTER_GLOBAL(%s)' % (name,) print >> f, self.C_INIT_FOOTER % info def gen_global_declarations(self): g = self.globaldecl + for name in self.globalobjects: + g.append('static PyObject *%s;' % (name,)) if g: f = self.f print >> f, '/* global declaration%s */' % ('s'*(len(g)>1)) @@ -564,12 +548,12 @@ print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % ( len(positional_args),) print >> f, '\tif (args == NULL) {' - print >> f, '\t\tPy_DECREF(%s);' % vararg + print >> f, '\t\tERR_DECREF(%s)' % vararg print >> f, '\t\tFUNCTION_RETURN(NULL)' print >> f, '\t}' tail = """{ -\t\tPy_DECREF(args); -\t\tPy_DECREF(%s); +\t\tERR_DECREF(args) +\t\tERR_DECREF(%s) \t\tFUNCTION_RETURN(NULL); \t} \tPy_DECREF(args);""" % vararg @@ -729,7 +713,7 @@ while to_release: v = to_release.pop() if err_reachable: - yield 'Py_DECREF(%s);' % v.name + yield 'ERR_DECREF(%s)' % v.name yield 'err%d_%d:' % (blocknum[block], len(to_release)) err_reachable = True if err_reachable: From arigo at codespeak.net Sat Nov 20 18:30:03 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 18:30:03 +0100 (MET) Subject: [pypy-svn] r7523 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/flow/test translator Message-ID: <20041120173003.126C45B175@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 18:30:02 2004 New Revision: 7523 Modified: pypy/trunk/src/pypy/interpreter/pyframe.py pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/framestate.py pypy/trunk/src/pypy/objspace/flow/specialcase.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py pypy/trunk/src/pypy/translator/genc.h Log: Better support for exceptions: at least, the flow objspace can make sense out of 'raise something' constructs. Modified: pypy/trunk/src/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/src/pypy/interpreter/pyframe.py Sat Nov 20 18:30:02 2004 @@ -266,6 +266,13 @@ # could occur e.g. when a BREAK_LOOP is not actually within a loop raise BytecodeCorruption, "block stack exhausted" + # for the flow object space, a way to "pickle" and "unpickle" the + # ControlFlowException by enumerating the Variables it contains. + def state_unpack_variables(self, space): + return [] # by default, overridden below + def state_pack_variables(self, space, *values_w): + assert len(values_w) == 0 + class SApplicationException(ControlFlowException): """Unroll the stack because of an application-level exception (i.e. an OperationException).""" @@ -286,6 +293,13 @@ operationerr = self.args[0] raise operationerr + def state_unpack_variables(self, space): + e = self.args[0] + assert isinstance(e, OperationError) + return [e.w_type, e.w_value] + def state_pack_variables(self, space, w_type, w_value): + self.args = (OperationError(w_type, w_value),) + class SBreakLoop(ControlFlowException): """Signals a 'break' statement.""" @@ -293,6 +307,12 @@ """Signals a 'continue' statement. Argument is the bytecode position of the beginning of the loop.""" + def state_unpack_variables(self, space): + jump_to = self.args[0] + return [space.wrap(jump_to)] + def state_pack_variables(self, space, w_jump_to): + self.args = (space.unwrap(w_jump_to),) + class SReturnValue(ControlFlowException): """Signals a 'return' statement. Argument is the wrapped object to return.""" @@ -300,6 +320,12 @@ w_returnvalue = self.args[0] raise ExitFrame(w_returnvalue) + def state_unpack_variables(self, space): + w_returnvalue = self.args[0] + return [w_returnvalue] + def state_pack_variables(self, space, w_returnvalue): + self.args = (w_returnvalue,) + class ExitFrame(Exception): """Signals the end of the frame execution. The argument is the returned or yielded value, already wrapped.""" Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sat Nov 20 18:30:02 2004 @@ -179,6 +179,7 @@ cases = [None] + list(classes)) def build_flow(self): + from pypy.objspace.flow.objspace import UnwrapException while self.pendingblocks: block = self.pendingblocks.pop(0) frame = self.create_frame() @@ -189,7 +190,10 @@ try: w_result = frame.eval(self) except OperationError, e: - exc_type = self.space.unwrap(e.w_type) + try: + exc_type = self.space.unwrap(e.w_type) + except UnwrapException: + exc_type = unknown_exception link = Link([e.w_value], self.graph.getexceptblock(exc_type)) self.crnt_block.closeblock(link) else: @@ -209,3 +213,7 @@ mapping[a] = Variable() node.renamevariables(mapping) traverse(fixegg, self.graph) + + +class unknown_exception(object): # not meant to be raised! + pass Modified: pypy/trunk/src/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/framestate.py (original) +++ pypy/trunk/src/pypy/objspace/flow/framestate.py Sat Nov 20 18:30:02 2004 @@ -6,7 +6,9 @@ def __init__(self, state): if isinstance(state, PyFrame): - self.mergeable = state.getfastscope() + state.valuestack.items + data = state.getfastscope() + state.valuestack.items + recursively_flatten(state.space, data) + self.mergeable = data self.nonmergeable = ( state.blockstack.items[:], state.last_exception, @@ -25,8 +27,10 @@ def restoreframe(self, frame): if isinstance(frame, PyFrame): fastlocals = len(frame.fastlocals_w) - frame.setfastscope(self.mergeable[:fastlocals]) - frame.valuestack.items[:] = self.mergeable[fastlocals:] + data = self.mergeable[:] + recursively_unflatten(frame.space, data) + frame.setfastscope(data[:fastlocals]) + frame.valuestack.items[:] = data[fastlocals:] ( frame.blockstack.items[:], frame.last_exception, @@ -103,11 +107,56 @@ # This is needed for try:except: and try:finally:, though # it makes the control flow a bit larger by duplicating the # handlers. - dont_merge_w1 = isinstance(w1.value, ControlFlowException) - dont_merge_w2 = isinstance(w2.value, ControlFlowException) + dont_merge_w1 = w1 in UNPICKLE_TAGS + dont_merge_w2 = w2 in UNPICKLE_TAGS if dont_merge_w1 or dont_merge_w2: raise UnionError else: return Variable() # generalize different constants raise TypeError('union of %r and %r' % (w1.__class__.__name__, w2.__class__.__name__)) + +# ____________________________________________________________ +# +# We have to flatten out the state of the frame into a list of +# Variables and Constants. This is done above by collecting the +# locals and the items on the value stack, but the latter may contain +# ControlFlowExceptions. We have to handle these specially, because +# some of them hide references to more Variables and Constants. +# The trick is to flatten ("pickle") them into the list so that the +# extra Variables show up directly in the list too. + +class PickleTag: + pass + +PICKLE_TAGS = {} +UNPICKLE_TAGS = {} + +def recursively_flatten(space, lst): + i = 0 + while i < len(lst): + item = lst[i] + if not (isinstance(item, Constant) and + isinstance(item.value, ControlFlowException)): + i += 1 + else: + unroller = item.value + vars = unroller.state_unpack_variables(space) + key = unroller.__class__, len(vars) + try: + tag = PICKLE_TAGS[key] + except: + tag = PICKLE_TAGS[key] = Constant(PickleTag()) + UNPICKLE_TAGS[tag] = key + lst[i:i+1] = [tag] + vars + +def recursively_unflatten(space, lst): + for i in range(len(lst)-1, -1, -1): + item = lst[i] + if item in UNPICKLE_TAGS: + unrollerclass, argcount = UNPICKLE_TAGS[item] + arguments = lst[i+1: i+1+argcount] + del lst[i+1: i+1+argcount] + unroller = unrollerclass() + unroller.state_pack_variables(space, *arguments) + lst[i] = Constant(unroller) Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Sat Nov 20 18:30:02 2004 @@ -17,29 +17,46 @@ def sc_normalize_exception(space, fn, args): - """Special-case for 'raise' statements. + """Special-case for 'raise' statements. Case-by-case analysis: - Only accept the following syntaxes: * raise Class - * raise Class, Arg + - with a constant Class, it is easy to recognize. + The associated value is Class(). + * raise Class(...) + - when the class is instantiated in-place, we can figure that out + + * raise Instance + - assumes that it's not a class, and raises an exception whose class + is variable and whose value is Instance. + + * raise Class, Arg + - assumes that Arg is the value you want for the exception, and + that Class is exactly the exception class. No check or normalization. """ assert len(args.args_w) == 2 and args.kwds_w == {} w_arg1, w_arg2 = args.args_w + if w_arg2 != space.w_None: + # raise Class, Arg: no normalization + return (w_arg1, w_arg2) etype = getconstclass(space, w_arg1) if etype is not None: - # raise Class or raise Class, Arg: no normalization + # raise Class + w_arg2 = space.do_operation('simple_call', w_arg1) return (w_arg1, w_arg2) - else: - # raise Instance: we need a hack to figure out of which class it is. - # Normally, Instance should have been created by the previous operation - # which should be a simple_call(, ...). - # Fetch the out of there. (This doesn't work while replaying) + # raise Class(..)? We need a hack to figure out of which class it is. + # Normally, Instance should have been created by the previous operation + # which should be a simple_call(, ...). + # Fetch the out of there. (This doesn't work while replaying) + if space.executioncontext.crnt_ops: spaceop = space.executioncontext.crnt_ops[-1] - assert spaceop.opname == 'simple_call' - assert spaceop.result is w_arg1 - w_type = spaceop.args[0] - return (w_type, w_arg2) + if (spaceop.opname == 'simple_call' and + spaceop.result is w_arg1): + w_type = spaceop.args[0] + return (w_type, w_arg1) + # raise Instance. Fall-back. + w_type = space.do_operation('type', w_arg1) + return (w_type, w_arg1) # this function returns a real tuple that can be handled # by FlowObjSpace.unpacktuple() Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Sat Nov 20 18:30:02 2004 @@ -1,5 +1,6 @@ import autopath from pypy.tool import testit +from pypy.objspace.flow.model import Constant class TestFlowObjSpace(testit.TestCase): @@ -18,10 +19,11 @@ return graph def reallyshow(self, x): - import os - from pypy.translator.tool.make_dot import make_dot - dest = make_dot(x.name, x) - os.system('gv %s' % str(dest)) + x.show() + #import os + #from pypy.translator.tool.make_dot import make_dot + #dest = make_dot(x.name, x) + #os.system('gv %s' % str(dest)) def show(self, x): pass # or self.reallyshow(x) @@ -228,6 +230,11 @@ def test_raise1(self): x = self.codetest(self.raise1) + assert len(x.startblock.operations) == 1 + assert x.startblock.operations[0].opname == 'simple_call' + assert list(x.startblock.operations[0].args) == [Constant(IndexError)] + assert x.startblock.operations[0].result is x.startblock.exits[0].args[0] + assert x.startblock.exits[0].target is x.exceptblocks[IndexError] self.show(x) #__________________________________________________________ @@ -236,6 +243,8 @@ def test_raise2(self): x = self.codetest(self.raise2) + assert len(x.startblock.operations) == 0 + assert x.startblock.exits[0].target is x.exceptblocks[IndexError] self.show(x) #__________________________________________________________ @@ -244,6 +253,32 @@ def test_raise3(self): x = self.codetest(self.raise3) + assert len(x.startblock.operations) == 1 + assert x.startblock.operations[0].opname == 'simple_call' + assert list(x.startblock.operations[0].args) == [ + Constant(IndexError), x.startblock.inputargs[0]] + assert x.startblock.operations[0].result is x.startblock.exits[0].args[0] + assert x.startblock.exits[0].target is x.exceptblocks[IndexError] + self.show(x) + + #__________________________________________________________ + def raise4(stuff): + raise stuff + + def test_raise4(self): + x = self.codetest(self.raise4) + self.show(x) + + #__________________________________________________________ + def raise_and_catch_1(exception_instance): + try: + raise exception_instance + except IndexError: + return -1 + return 0 + + def test_raise_and_catch_1(self): + x = self.codetest(self.raise_and_catch_1) self.show(x) #__________________________________________________________ Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 18:30:02 2004 @@ -113,6 +113,11 @@ #define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ FAIL(err) +#define OP_TYPE() /* to whoever needs to implement this: if 'x' is an + old-style exception instance, then OP_TYPE(x) + should really return its (old-style) class */ +#define OP_ISSUBTYPE() /* same comments */ + /*** tests ***/ #define EQ_False(o) (o == Py_False) From arigo at codespeak.net Sat Nov 20 18:31:03 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 18:31:03 +0100 (MET) Subject: [pypy-svn] r7524 - in pypy/trunk/src/pypy: interpreter objspace/std translator Message-ID: <20041120173103.F0BDB5B17F@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 18:31:03 2004 New Revision: 7524 Modified: pypy/trunk/src/pypy/interpreter/error.py pypy/trunk/src/pypy/interpreter/extmodule.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/translator/genc.py Log: More NOT_RPYTHON tags. Modified: pypy/trunk/src/pypy/interpreter/error.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/error.py (original) +++ pypy/trunk/src/pypy/interpreter/error.py Sat Nov 20 18:31:03 2004 @@ -31,11 +31,11 @@ return space.exception_match(self.w_type, w_check_class) def __str__(self): - "Convenience for tracebacks." + "NOT_RPYTHON: Convenience for tracebacks." return '[%s: %s]' % (self.w_type, self.w_value) def errorstr(self, space): - "The exception class and value, as a string." + "NOT_RPYTHON: The exception class and value, as a string." exc_type = space.unwrap( space.getattr(self.w_type, space.wrap('__name__'))) exc_value = space.unwrap(space.str(self.w_value)) @@ -49,18 +49,19 @@ return None def record_interpreter_traceback(self): - """Records the current traceback inside the interpreter. + """NOT_RPYTHON: Records the current traceback inside the interpreter. This traceback is only useful to debug the interpreter, not the application.""" self.debug_excs.append(sys.exc_info()) def print_application_traceback(self, space, file=None): - "Dump a standard application-level traceback." + "NOT_RPYTHON: Dump a standard application-level traceback." if file is None: file = sys.stderr self.print_app_tb_only(file) print >> file, self.errorstr(space) def print_app_tb_only(self, file): + "NOT_RPYTHON" tb = self.application_traceback if tb: import linecache @@ -87,8 +88,8 @@ tb = tb.next def print_detailed_traceback(self, space=None, file=None): - """Dump a nice detailed interpreter- and application-level traceback, - useful to debug the interpreter.""" + """NOT_RPYTHON: Dump a nice detailed interpreter- and + application-level traceback, useful to debug the interpreter.""" if file is None: file = sys.stderr for i in range(len(self.debug_excs)-1, -1, -1): import traceback Modified: pypy/trunk/src/pypy/interpreter/extmodule.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/extmodule.py (original) +++ pypy/trunk/src/pypy/interpreter/extmodule.py Sat Nov 20 18:31:03 2004 @@ -22,7 +22,8 @@ NOT_RPYTHON_ATTRIBUTES = ['__builtins__'] def __init__(self, space, modulename, w_dict=None, sourcefile=None): - """Load the named built-in module, by default from the source file + """NOT_RPYTHON + Load the named built-in module, by default from the source file 'pypy/module/module.py', which is app-level Python code with a few special features that allow it to include interp-level bits. (See pypy/module/test/foomodule.py) @@ -73,13 +74,17 @@ space.w_builtins) # Temporarily install an '__applevel__' pseudo-module - sys.modules['__applevel__'] = BuiltinModule.AppModuleHack(self) + sys.modules['__applevel__'] = AppModuleHack(self) # Run the app-level module definition (xxxmodule.py) pycode.exec_code(space, w_dict, w_dict) # Remove the pseudo-module del sys.modules['__applevel__'] + try: + del self.__applevel__ + except AttributeError: + pass # Remove/restore the hooks unless they have been modified at app-level for name, w_hook in newhooks.items(): @@ -98,14 +103,14 @@ del self.__saved_hooks def interplevelexec(self, w_codestring): - "'exec' a string at interp-level." + "NOT_RPYTHON: 'exec' a string at interp-level." codestring = self.space.unwrap(w_codestring) exec codestring in self.__dict__ return self.space.w_None def interpleveleval(self, w_codestring): - """'eval' a string at interp-level. The result must be None or - a wrapped object, which is returned to the caller.""" + """NOT_RPYTHON: 'eval' a string at interp-level. The result must + be None or a wrapped object, which is returned to the caller.""" space = self.space codestring = space.unwrap(w_codestring) w_result = eval(codestring, self.__dict__) @@ -114,15 +119,15 @@ return w_result def interplevelexecfile(self, w_filename): - """'exec' a file at interp-level. The file should be in the same - directory as the xxxmodule.py source file of the module.""" + """NOT_RPYTON: 'exec' a file at interp-level. The file should be in + the same directory as the xxxmodule.py source file of the module.""" filename = self.space.unwrap(w_filename) filename = os.path.join(os.path.dirname(self.__file__), filename) execfile(filename, self.__dict__) return self.space.w_None def interplevelimport(self, w_modulename, w_globals, w_locals, w_fromlist): - """Hook for 'from __interplevel__ import something'. + """NOT_RPYTHON: Hook for 'from __interplevel__ import something'. If there is a wrapped interp-level object 'w_something', returns it. If there is an interp-level function 'def something(w_x, w_y...)', build an appropriate gateway and returns it. @@ -150,15 +155,18 @@ w_modulename, w_globals, w_locals, w_fromlist) - class AppModuleHack: - """For interp-level convenience: 'from __applevel__ import func' - imports the app-level function 'func' via an appropriate gateway. - """ - def __init__(self, builtinmodule): - self.space = builtinmodule.space - self.w_dict = builtinmodule.w_dict - def __getattr__(self, name): - w_func = self.space.getitem(self.w_dict, self.space.wrap(name)) - def caller(*args, **kwds): - return self.space.call_function(w_func, *args, **kwds) - return caller +class AppModuleHack: + """NOT_RPYTHON + For interp-level convenience: 'from __applevel__ import func' + imports the app-level function 'func' via an appropriate gateway. + """ + def __init__(self, builtinmodule): + self.space = builtinmodule.space + self.w_dict = builtinmodule.w_dict + def __getattr__(self, name): + if name.startswith('__'): + raise AttributeError, name + w_func = self.space.getitem(self.w_dict, self.space.wrap(name)) + def caller(*args): + return self.space.call_function(w_func, *args) + return caller Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Sat Nov 20 18:31:03 2004 @@ -16,6 +16,7 @@ # real-to-wrapped exceptions def wrap_exception(space): + "NOT_RPYTHON" # XXX this needs to end up in the translated code somehow! exc, value, tb = sys.exc_info() if exc is OperationError: raise exc, value, tb # just re-raise it Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 20 18:31:03 2004 @@ -103,8 +103,10 @@ return name def nameof_module(self, value): - assert not hasattr(value, "__file__") or \ - not (value.__file__.endswith('.pyc') or value.__file__.endswith('.py') or value.__file__.endswith('.pyo')), \ + assert value is os or not hasattr(value, "__file__") or \ + not (value.__file__.endswith('.pyc') or + value.__file__.endswith('.py') or + value.__file__.endswith('.pyo')), \ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod%s'%value.__name__) self.globalobjects.append(name) From arigo at codespeak.net Sat Nov 20 18:47:55 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 18:47:55 +0100 (MET) Subject: [pypy-svn] r7525 - in pypy/trunk/src/pypy/objspace/flow: . test Message-ID: <20041120174755.9B2B75B181@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 18:47:55 2004 New Revision: 7525 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Log: Handling of exceptions between functions in the flow objspace. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sat Nov 20 18:47:55 2004 @@ -1,5 +1,5 @@ # ______________________________________________________________________ -import sys, operator +import sys, operator, types from pypy.interpreter.baseobjspace import ObjSpace from pypy.interpreter.pycode import PyCode from pypy.interpreter.error import OperationError @@ -216,9 +216,53 @@ if args.kwds_w: w_args, w_kwds = args.pack() - return self.do_operation('call', w_callable, w_args, w_kwds) + w_res = self.do_operation('call', w_callable, w_args, w_kwds) else: - return self.do_operation('simple_call', w_callable, *args.args_w) + w_res = self.do_operation('simple_call', w_callable, *args.args_w) + + # maybe the call has generated an exception (any one) + # but, let's say, not if we are calling a built-in class or function + # because this gets in the way of the special-casing of + # + # raise SomeError(x) + # + # as shown by test_objspace.test_raise3. + + exceptions = True # *any* exception by default + if isinstance(w_callable, Constant): + c = w_callable.value + if isinstance(c, (types.BuiltinFunctionType, + types.BuiltinMethodType)): + exceptions = None + elif (isinstance(c, (type, types.ClassType)) and + c.__module__ in ['__builtin__', 'exceptions']): + exceptions = None + self.handle_implicit_exceptions(exceptions) + return w_res + + def handle_implicit_exceptions(self, exceptions): + if exceptions: + # catch possible exceptions implicitly. If the OperationError + # below is not caught in the same function, it will produce an + # exception-raising return block in the flow graph. The special + # value 'wrap(last_exception)' is used as a marker for this kind + # of implicit exceptions, and simplify.py will remove it as per + # the RPython definition: implicit exceptions not explicitly + # caught in the same function are assumed not to occur. + context = self.getexecutioncontext() + if exceptions == True: + # any exception + outcome = context.guessexception(Exception) + if outcome is not None: + w_value = self.wrap(last_exception) + w_type = self.do_operation('type', w_value) + raise OperationError(w_type, w_value) + else: + # only the specified exception(s) + outcome = context.guessexception(*exceptions) + if outcome is not None: + raise OperationError(self.wrap(outcome), + self.wrap(last_exception)) # ______________________________________________________________________ @@ -280,19 +324,7 @@ #print >> sys.stderr, 'Variable operation', name, args_w w_result = self.do_operation(name, *args_w) - if exceptions: - # catch possible exceptions implicitly. If the OperationError - # below is not caught in the same function, it will produce an - # exception-raising return block in the flow graph. The special - # value 'wrap(last_exception)' is used as a marker for this kind - # of implicit exceptions, and simplify.py will remove it as per - # the RPython definition: implicit exceptions not explicitly - # caught in the same function are assumed not to occur. - context = self.getexecutioncontext() - outcome = context.guessexception(*exceptions) - if outcome is not None: - raise OperationError(self.wrap(outcome), - self.wrap(last_exception)) + self.handle_implicit_exceptions(exceptions) return w_result setattr(FlowObjSpace, name, generic_operator) Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Sat Nov 20 18:47:55 2004 @@ -282,6 +282,18 @@ self.show(x) #__________________________________________________________ + def catch_simple_call(): + try: + user_defined_function() + except IndexError: + return -1 + return 0 + + def test_catch_simple_call(self): + x = self.codetest(self.catch_simple_call) + self.show(x) + + #__________________________________________________________ def dellocal(): x = 1 del x @@ -332,5 +344,8 @@ DATA = {'x': 5, 'y': 6} +def user_defined_function(): + pass + if __name__ == '__main__': testit.main() From mgedmin at codespeak.net Sat Nov 20 18:50:01 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 18:50:01 +0100 (MET) Subject: [pypy-svn] r7526 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041120175001.BA0985B498@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 18:50:00 2004 New Revision: 7526 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Implement searching for edges as well as nodes. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sat Nov 20 18:50:00 2004 @@ -448,19 +448,24 @@ for cmd in self.draw_commands(): cmd() - def search_for_node(self, searchstr, start_at=None): - """Find a node that contains a search string.""" - iter = self.graphlayout.nodes.itervalues() + def _search_for(self, items, searchstr, start_at=None): + """Find an object that contains a search string.""" + it = iter(items) if start_at is not None: - # Skip all nodes up to and including 'start_at' - for node in iter: - if node is start_at: + # Skip all items up to and including 'start_at' + for item in it: + if item is start_at: break - for node in iter: - if searchstr in node.label: - return node + for item in it: + if item.label and searchstr in item.label: + return item return None + def search(self, searchstr, start_at=None): + """Find a node or an edge that contains a search string.""" + items = self.graphlayout.nodes.values() + self.graphlayout.edges + return self._search_for(items, searchstr, start_at) + def at_position(self, (x, y)): """Figure out the word under the cursor.""" for rx, ry, rw, rh, word in self.textzones: Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Sat Nov 20 18:50:00 2004 @@ -4,6 +4,7 @@ import pygame from pygame.locals import * from pypy.translator.tool.pygame.drawgraph import GraphRenderer +from pypy.translator.tool.pygame.drawgraph import Node, Edge METAKEYS = dict([ @@ -282,15 +283,21 @@ def find_next(self): if not self.searchstr: return - node = self.viewer.search_for_node(self.searchstr, - start_at=self.searchpos) - if node: - self.searchpos = node - self.sethighlight(obj=node) - self.look_at_node(node, keep_highlight=True) - self.sethighlight(obj=node) - else: + item = self.viewer.search(self.searchstr, start_at=self.searchpos) + if item is None: self.setstatusbar('Not found: %s' % self.searchstr) + return + self.searchpos = item + self.sethighlight(obj=item) + if isinstance(item, Node): + self.setstatusbar('Found node containing %s' % self.searchstr) + self.look_at_node(item, keep_highlight=True) + elif isinstance(item, Edge): + self.setstatusbar('Found edge containing %s' % self.searchstr) + self.look_at_edge(item, keep_highlight=True) + else: + # should never happen + self.setstatusbar('Found %r containing %s' % (item, self.searchstr)) def setlayout(self, layout): if self.viewer: @@ -298,6 +305,7 @@ del self.forward_viewers_history[:] self.layout = layout self.viewer = GraphRenderer(self.screen, layout) + self.searchpos = None self.zoom_to_fit() def zoom_actual_size(self): @@ -345,9 +353,8 @@ self.reoffset() if not keep_highlight: self.sethighlight() - self.statusbarinfo = None + self.update_status_bar() self.must_redraw = True - self.update_status_bar() def layout_back(self): if self.viewers_history: @@ -469,12 +476,30 @@ def look_at_node(self, node, keep_highlight=False): """Shift the node in view.""" - endscale = min(float(self.width-40) / node.w, - float(self.height-40) / node.h, + self.look_at(node.x, node.y, node.w, node.h, keep_highlight) + + def look_at_edge(self, edge, keep_highlight=False): + """Shift the edge's label into view.""" + points = edge.bezierpoints() + xmin = min([x for (x, y) in points]) + xmax = max([x for (x, y) in points]) + ymin = min([y for (x, y) in points]) + ymax = max([y for (x, y) in points]) + x = (xmin + xmax) / 2 + y = (ymin + ymax) / 2 + w = max(1, xmax - xmin) + h = max(1, ymax - ymin) + self.look_at(x, y, w, h, keep_highlight) + + def look_at(self, targetx, targety, targetw, targeth, + keep_highlight=False): + """Shift the node in view.""" + endscale = min(float(self.width-40) / targetw, + float(self.height-40) / targeth, 75) startscale = self.viewer.scale cx1, cy1 = self.viewer.getcenter() - cx2, cy2 = node.x, node.y + cx2, cy2 = targetx, targety moving = (abs(startscale-endscale) + abs(cx1-cx2) + abs(cy1-cy2) > 0.4) if moving: @@ -486,8 +511,8 @@ bumpscale = 4.0 * (middlescale - 0.5*(startscale+endscale)) else: bumpscale = 0.0 - self.statusbarinfo = None if not keep_highlight: + self.statusbarinfo = None self.sethighlight() for t in self.animation(): self.viewer.setscale(startscale*(1-t) + endscale*t + @@ -495,6 +520,10 @@ self.viewer.setcenter(cx1*(1-t) + cx2*t, cy1*(1-t) + cy2*t) self.updated_viewer(keep_highlight=keep_highlight) self.viewer.render() + if self.statusbarinfo: + self.drawstatusbar() + else: + self.status_bar_height = 0 pygame.display.flip() return moving From mgedmin at codespeak.net Sat Nov 20 19:02:21 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Sat, 20 Nov 2004 19:02:21 +0100 (MET) Subject: [pypy-svn] r7527 - pypy/trunk/src/pypy/translator Message-ID: <20041120180221.260965B49B@thoth.codespeak.net> Author: mgedmin Date: Sat Nov 20 19:02:20 2004 New Revision: 7527 Modified: pypy/trunk/src/pypy/translator/transform.py Log: Ignore blocked blocks during transformations. This fixes a bunch of assertion errors if you are transforming a flow graph that contains blocked blocks. This doesn't change anything in practice because if there are any blocked blocks, the annotator raises an assertion error and no transformations are performed. Armin suggested that in some instances (e.g. calling a function that always raises an exception) the blocked block should stay blocked and we should proceed with the translation anyway. Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Sat Nov 20 19:02:20 2004 @@ -19,9 +19,15 @@ # --> # d = alloc_and_set(b, a) +def fully_annotated_blocks(self): + """Ignore blocked blocks.""" + for block, is_annotated in self.annotated.iteritems(): + if is_annotated: + yield block + def transform_allocate(self): """Transforms [a] * b to alloc_and_set(b, a) where b is int.""" - for block in self.annotated: + for block in fully_annotated_blocks(self): operations = block.operations[:] n_op = len(operations) for i in range(0, n_op-1): @@ -46,7 +52,7 @@ def transform_slice(self): """Transforms a[b:c] to getslice(a, b, c).""" - for block in self.annotated: + for block in fully_annotated_blocks(self): operations = block.operations[:] n_op = len(operations) for i in range(0, n_op-1): @@ -112,7 +118,7 @@ variable_flow = {} # map {Var: list-of-Vars-it-depends-on} # compute variable_flow and an initial read_vars - for block in self.annotated: + for block in fully_annotated_blocks(self): # figure out which variables are ever read for op in block.operations: if op.opname not in CanRemove: # mark the inputs as really needed @@ -151,7 +157,7 @@ read_vars[prevvar] = True pending.append(prevvar) - for block in self.annotated: + for block in fully_annotated_blocks(self): # look for removable operations whose result is never used for i in range(len(block.operations)-1, -1, -1): @@ -175,12 +181,16 @@ # link.target.inputargs. for link in block.exits: assert len(link.args) == len(link.target.inputargs) + if not self.annotated.get(link.target, False): + # Can't remove -- link.target is not annotated, therefore + # link.target.inputargs will never be touched + continue for i in range(len(link.args)-1, -1, -1): if link.target.inputargs[i] not in read_vars: del link.args[i] # the above assert would fail here - for block in self.annotated: + for block in fully_annotated_blocks(self): # look for input variables never used # The corresponding link.args have already been all removed above for i in range(len(block.inputargs)-1, -1, -1): @@ -314,11 +324,7 @@ """Remove dead code: these are the blocks that are not annotated at all because the annotation considered that no conditional jump could reach them.""" - for block, is_annotated in self.annotated.items(): - if not is_annotated: - # We do not want to accidentally turn blocked blocks into return - # blocks - continue + for block in fully_annotated_blocks(self): for link in block.exits: if link not in self.links_followed: lst = list(block.exits) From bob at codespeak.net Sat Nov 20 19:37:50 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Sat, 20 Nov 2004 19:37:50 +0100 (MET) Subject: [pypy-svn] r7529 - pypy/trunk/src/pypy/translator Message-ID: <20041120183750.6B4BF5B49C@thoth.codespeak.net> Author: bob Date: Sat Nov 20 19:37:49 2004 New Revision: 7529 Modified: pypy/trunk/src/pypy/translator/genc.h Log: probably working OP_TYPE and OP_ISSUBTYPE refactor Py_True / Py_False returning into op_bool uberhack to workaround the fact that the translator actually tries to raise PyExc_unknown_exception without creating such a beast. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sat Nov 20 19:37:49 2004 @@ -8,6 +8,8 @@ #include "structmember.h" #include "traceback.h" +/* XXX HACK HACK HACK HACK HACK HACK HACK HACK HACK */ +#define PyExc_unknown_exception PyExc_Exception #if !defined(MIN) #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ @@ -21,6 +23,14 @@ #define OBNOXIOUS_PRINT_STATEMENTS #endif +#define op_bool(r,err,what) { \ + int retval = what; \ + if (retval < 0) { \ + FAIL(err) \ + } \ + r = PyBool_FromLong(retval); \ + } + #define op_richcmp(x,y,r,err,dir) \ if (!(r=PyObject_RichCompare(x,y,dir))) FAIL(err) #define OP_LT(x,y,r,err) op_richcmp(x,y,r,err, Py_LT) @@ -30,16 +40,9 @@ #define OP_GT(x,y,r,err) op_richcmp(x,y,r,err, Py_GT) #define OP_GE(x,y,r,err) op_richcmp(x,y,r,err, Py_GE) -#define OP_IS_(x,y,r,err) \ - r = x == y ? Py_True : Py_False; Py_INCREF(r); +#define OP_IS_(x,y,r,err) op_bool(r,err,(x == y)) -#define OP_IS_TRUE(x,r,err) \ - switch (PyObject_IsTrue(x)) { \ - case 0: r=Py_False; break; \ - case 1: r=Py_True; break; \ - default: FAIL(err) \ - } \ - Py_INCREF(r); +#define OP_IS_TRUE(x,r,err) op_bool(r,err,PyObject_IsTrue(x)) #define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) FAIL(err) #define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) FAIL(err) @@ -89,12 +92,7 @@ #define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) FAIL(err) #define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) FAIL(err) \ r=Py_None; Py_INCREF(r); -#define OP_CONTAINS(x,y,r,err) switch (PySequence_Contains(x,y)) { \ - case 1: \ - Py_INCREF(Py_True); r = Py_True; break; \ - case 0: \ - Py_INCREF(Py_False); r = Py_False; break; \ - default: FAIL(err) } +#define OP_CONTAINS(x,y,r,err) op_bool(r,err,(PySequence_Contains(x,y))) #define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) FAIL(err) #define OP_SETATTR(x,y,z,r,err) if ((PyObject_SetAttr(x,y,z))<0) FAIL(err) \ @@ -113,10 +111,20 @@ #define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ FAIL(err) -#define OP_TYPE() /* to whoever needs to implement this: if 'x' is an - old-style exception instance, then OP_TYPE(x) - should really return its (old-style) class */ -#define OP_ISSUBTYPE() /* same comments */ +/* Needs to act like getattr(x, '__class__', type(x)) */ +#define OP_TYPE(x,r,err) { \ + PyObject *o = x; \ + if (PyInstance_Check(o)) { \ + r = (PyObject*)(((PyInstanceObject*)o)->in_class); \ + } else { \ + r = (PyObject*)o->ob_type; \ + } \ + Py_INCREF(r); \ + } + +/* Needs to act like instance(x,y) */ +#define OP_ISSUBTYPE(x,y,r,err) \ + op_bool(r,err,PyClass_IsSubclass(x, y)) /*** tests ***/ From jacob at codespeak.net Sat Nov 20 19:52:22 2004 From: jacob at codespeak.net (jacob at codespeak.net) Date: Sat, 20 Nov 2004 19:52:22 +0100 (MET) Subject: [pypy-svn] r7530 - in pypy/trunk/src/pypy/appspace: . test Message-ID: <20041120185222.2A7F05B49F@thoth.codespeak.net> Author: jacob Date: Sat Nov 20 19:52:21 2004 New Revision: 7530 Added: pypy/trunk/src/pypy/appspace/_file.py pypy/trunk/src/pypy/appspace/sio.py pypy/trunk/src/pypy/appspace/test/test_file.py pypy/trunk/src/pypy/appspace/test/test_sio.py Log: Added builtin file with support. Reading and writing work both buffered and unbuffered. Writing works linebuffered as well. Universal newline support works. Buffered combined read/write does not work yet. Linebuffered read does not work yet. Added: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/_file.py Sat Nov 20 19:52:21 2004 @@ -0,0 +1,51 @@ +import sio + +class file_(object): + """An implementation of file objects in Python. it relies on Guido's + sio.py implementation. + """ + def __init__(self, filename, mode='r', bufsize=None): + self.reading = False + self.writing = False + + if not mode: + raise IOError('invalid mode : ') + if mode[0] not in ['r', 'w', 'a', 'U']: + raise IOError('invalid mode : %s' % mode) + else: + if mode[0] in ['r', 'U']: + self.reading = True + else: + self.writing = True + try: + if mode[1] == 'b': + plus = mode[2] + else: + plus = mode[1] + if plus == '+': + self.reading = self.writing = True + except IndexError: + pass + + self.fd = sio.DiskFile(filename, mode) + if mode in ['U', 'rU']: + # Wants universal newlines + self.fd = sio.TextInputFilter(self.fd) + if bufsize < 0: + bufsize = None + if not self.writing and (bufsize is None or bufsize > 0): + self.fd = sio.BufferingInputStream(self.fd, bufsize) + if not self.reading: + if bufsize is None or bufsize > 1: + self.fd = sio.BufferingOutputStream(self.fd, bufsize) + elif bufsize == 1: + self.fd = sio.LineBufferingOutputStream(self.fd) + return self.fd + + def __getattr__(self, name): + """ + Delegate all other methods to the underlying file object. + """ + return getattr(self.fd, name) + + Added: pypy/trunk/src/pypy/appspace/sio.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/sio.py Sat Nov 20 19:52:21 2004 @@ -0,0 +1,790 @@ +"""New standard I/O library. + +This code is still very young and experimental! + +There are fairly complete unit tests in test_sio.py. + +The design is simple: + +- A raw stream supports read(n), write(s), seek(offset, whence=0) and + tell(). This is generally unbuffered. Raw streams may support + Unicode. + +- A basis stream provides the raw stream API and builds on a much more + low-level API, e.g. the os, mmap or socket modules. + +- A filtering stream is raw stream built on top of another raw stream. + There are filtering streams for universal newline translation and + for unicode translation. + +- A buffering stream supports the full classic Python I/O API: + read(n=-1), readline(), readlines(sizehint=0), tell(), seek(offset, + whence=0), write(s), writelines(lst), as well as __iter__() and + next(). (There's also readall() but that's a synonym for read() + without arguments.) This is a superset of the raw stream API. I + haven't thought about fileno() and isatty() yet, nor about + truncate() or the various attributes like name and mode. Also, + close() is not implemented right. We really need only one buffering + stream implementation, which is a filtering stream. + +You typically take a basis stream, place zero or more filtering +streams on top of it, and then top it off with a buffering stream. + +""" + +import os +import mmap + +class BufferingInputStream(object): + + """Standard buffering input stream. + + This is typically the top of the stack. + """ + + bigsize = 2**19 # Half a Meg + bufsize = 2**13 # 8 K + + def __init__(self, base, bufsize=None): + self.do_read = getattr(base, "read", None) + # function to fill buffer some more + self.do_tell = getattr(base, "tell", None) + # None, or return a byte offset + self.do_seek = getattr(base, "seek", None) + # None, or seek to a byte offset + self.close = base.close + + if bufsize is None: # Get default from the class + bufsize = self.bufsize + self.bufsize = bufsize # buffer size (hint only) + self.lines = [] # ready-made lines (sans "\n") + self.buf = "" # raw data (may contain "\n") + # Invariant: readahead == "\n".join(self.lines + [self.buf]) + # self.lines contains no "\n" + # self.buf may contain "\n" + + def tell(self): + bytes = self.do_tell() # This may fail + offset = len(self.buf) + for line in self.lines: + offset += len(line) + 1 + assert bytes >= offset, (locals(), self.__dict__) + return bytes - offset + + def seek(self, offset, whence=0): + # This may fail on the do_seek() or do_tell() call. + # But it won't call either on a relative forward seek. + # Nor on a seek to the very end. + if whence == 0 or (whence == 2 and self.do_seek is not None): + self.do_seek(offset, whence) + self.lines = [] + self.buf = "" + return + if whence == 2: + # Skip relative to EOF by reading and saving only just as + # much as needed + assert self.do_seek is None + data = "\n".join(self.lines + [self.buf]) + total = len(data) + buffers = [data] + self.lines = [] + self.buf = "" + while 1: + data = self.do_read(self.bufsize) + if not data: + break + buffers.append(data) + total += len(data) + while buffers and total >= len(buffers[0]) - offset: + total -= len(buffers[0]) + del buffers[0] + cutoff = total + offset + if cutoff < 0: + raise TypeError, "cannot seek back" + if buffers: + buffers[0] = buffers[0][cutoff:] + self.buf = "".join(buffers) + self.lines = [] + return + if whence == 1: + if offset < 0: + self.do_seek(self.tell() + offset, 0) + self.lines = [] + self.buf = "" + return + while self.lines: + line = self.lines[0] + if offset <= len(line): + self.lines[0] = line[offset:] + return + offset -= len(self.lines[0]) - 1 + del self.lines[0] + assert not self.lines + if offset <= len(self.buf): + self.buf = self.buf[offset:] + return + offset -= len(self.buf) + self.buf = "" + if self.do_seek is None: + self.read(offset) + else: + self.do_seek(offset, 1) + return + raise ValueError, "whence should be 0, 1 or 2" + + def readall(self): + self.lines.append(self.buf) + more = ["\n".join(self.lines)] + self.lines = [] + self.buf = "" + bufsize = self.bufsize + while 1: + data = self.do_read(bufsize) + if not data: + break + more.append(data) + bufsize = max(bufsize*2, self.bigsize) + return "".join(more) + + def read(self, n=-1): + if n < 0: + return self.readall() + + if self.lines: + # See if this can be satisfied from self.lines[0] + line = self.lines[0] + if len(line) >= n: + self.lines[0] = line[n:] + return line[:n] + + # See if this can be satisfied *without exhausting* self.lines + k = 0 + i = 0 + for line in self.lines: + k += len(line) + if k >= n: + lines = self.lines[:i] + data = self.lines[i] + cutoff = len(data) - (k-n) + lines.append(data[:cutoff]) + self.lines[:i+1] = [data[cutoff:]] + return "\n".join(lines) + k += 1 + i += 1 + + # See if this can be satisfied from self.lines plus self.buf + if k + len(self.buf) >= n: + lines = self.lines + self.lines = [] + cutoff = n - k + lines.append(self.buf[:cutoff]) + self.buf = self.buf[cutoff:] + return "\n".join(lines) + + else: + # See if this can be satisfied from self.buf + data = self.buf + k = len(data) + if k >= n: + cutoff = len(data) - (k-n) + self.buf = data[cutoff:] + return data[:cutoff] + + lines = self.lines + self.lines = [] + lines.append(self.buf) + self.buf = "" + data = "\n".join(lines) + more = [data] + k = len(data) + while k < n: + data = self.do_read(max(self.bufsize, n-k)) + k += len(data) + more.append(data) + if not data: + break + cutoff = len(data) - (k-n) + self.buf = data[cutoff:] + more[-1] = data[:cutoff] + return "".join(more) + + def __iter__(self): + return self + + def next(self): + if self.lines: + return self.lines.pop(0) + "\n" + + # This block is needed because read() can leave self.buf + # containing newlines + self.lines = self.buf.split("\n") + self.buf = self.lines.pop() + if self.lines: + return self.lines.pop(0) + "\n" + + buf = self.buf and [self.buf] or [] + while 1: + self.buf = self.do_read(self.bufsize) + self.lines = self.buf.split("\n") + self.buf = self.lines.pop() + if self.lines: + buf.append(self.lines.pop(0)) + buf.append("\n") + break + if not self.buf: + break + buf.append(self.buf) + + line = "".join(buf) + if not line: + raise StopIteration + return line + + def readline(self): + try: + return self.next() + except StopIteration: + return "" + + def readlines(self, sizehint=0): + return list(self) + +class BufferingOutputStream(object): + + """Standard buffering output stream. + + This is typically the top of the stack. + """ + + bigsize = 2**19 # Half a Meg + bufsize = 2**13 # 8 K + + def __init__(self, base, bufsize=None): + self.do_write = base.write # Flush buffer + self.do_tell = base.tell + # Return a byte offset; has to exist or this __init__() will fail + self.do_seek = getattr(base, "seek", None) + # None, or seek to a byte offset + self.do_close = base.close # Close file + + if bufsize is None: # Get default from the class + bufsize = self.bufsize + self.bufsize = bufsize # buffer size (hint only) + self.buf = "" + self.tell() + + def tell(self): + assert self.do_tell is not None + if not hasattr(self, 'pos'): + self.pos = self.do_tell() + + return self.pos + + def seek(self, offset, whence=0): + self.do_write(self.buf) + self.buf = '' + self.do_seek(offset, whence) + self.pos = self.do_tell() + + def write(self, data): + buflen = len(self.buf) + datalen = len(data) + if datalen + buflen < self.bufsize: + self.buf += data + self.pos += datalen + else: + self.buf += data[:self.bufsize-buflen] + self.pos += self.bufsize-buflen + self.do_write(self.buf) + self.buf = '' + self.write(data[self.bufsize-buflen:]) + + def close(self): + self.do_write(self.buf) + self.buf = '' + if self.do_close(): + self.do_close() + +class LineBufferingOutputStream(BufferingOutputStream): + + """Line buffering output stream. + + This is typically the top of the stack. + """ + + def __init__(self, base, bufsize=None): + self.do_write = base.write # Flush buffer + self.do_tell = base.tell + # Return a byte offset; has to exist or this __init__() will fail + self.do_seek = getattr(base, "seek", None) + # None, or seek to a byte offset + self.do_close = base.close # Close file + + self.linesep = os.linesep + self.buf = "" # raw data (may contain "\n") + self.tell() + + def tell(self): + assert self.do_tell is not None + if not hasattr(self, 'pos'): + self.pos = self.do_tell() + + return self.pos + + def seek(self, offset, whence=0): + self.do_write(self.buf) + self.buf = '' + self.do_seek(offset, whence) + self.pos = self.do_tell() + + def write(self, data): + all_lines = data.split(self.linesep) + full_lines = all_lines[:-1] + for line in full_lines: + line += self.linesep + buflen = len(self.buf) + linelen = len(line) + if linelen + buflen < self.bufsize: + self.buf += line + self.pos += linelen + self.do_write(self.buf) + self.buf = '' + else: + self.buf += line[:self.bufsize-buflen] + self.pos += self.bufsize-buflen + self.do_write(self.buf) + self.buf = '' + self.write(line[self.bufsize-buflen:]) + + # The last part of the split data never has a terminating linesep. + # If the data has a terminating linesep, the last element is an + # empty string. + + line = all_lines[-1] + buflen = len(self.buf) + linelen = len(line) + if linelen + buflen < self.bufsize: + self.buf += line + self.pos += linelen + else: + self.buf += line[:self.bufsize-buflen] + self.pos += self.bufsize-buflen + self.do_write(self.buf) + self.buf = '' + self.write(line[self.bufsize-buflen:]) + + def close(self): + self.do_write(self.buf) + self.buf = '' + if self.do_close(): + self.do_close() + +class CRLFFilter(object): + + """Filtering stream for universal newlines. + + TextInputFilter is more general, but this is faster when you don't + need tell/seek. + """ + + def __init__(self, base): + self.do_read = base.read + self.atcr = False + self.close = base.close + + def read(self, n): + data = self.do_read(n) + if self.atcr: + if data.startswith("\n"): + data = data[1:] # Very rare case: in the middle of "\r\n" + self.atcr = False + if "\r" in data: + self.atcr = data.endswith("\r") # Test this before removing \r + data = data.replace("\r\n", "\n") # Catch \r\n this first + data = data.replace("\r", "\n") # Remaining \r are standalone + return data + +class MMapFile(object): + + """Standard I/O basis stream using mmap.""" + + def __init__(self, filename, mode="r"): + self.filename = filename + self.mode = mode + if mode == "r": + flag = os.O_RDONLY + self.access = mmap.ACCESS_READ + else: + if mode == "w": + flag = os.O_RDWR | os.O_CREAT + elif mode == "a": + flag = os.O_RDWR + else: + raise ValueError, "mode should be 'r', 'w' or 'a'" + self.access = mmap.ACCESS_WRITE + if hasattr(os, "O_BINARY"): + flag |= os.O_BINARY + self.fd = os.open(filename, flag) + size = os.fstat(self.fd).st_size + self.mm = mmap.mmap(self.fd, size, access=self.access) + self.pos = 0 + + def __del__(self): + self.close() + + mm = fd = None + + def close(self): + if self.mm is not None: + self.mm.close() + self.mm = None + if self.fd is not None: + os.close(self.fd) + self.fd = None + + def tell(self): + return self.pos + + def seek(self, offset, whence=0): + if whence == 0: + self.pos = max(0, offset) + elif whence == 1: + self.pos = max(0, self.pos + offset) + elif whence == 2: + self.pos = max(0, self.mm.size() + offset) + else: + raise ValueError, "seek(): whence must be 0, 1 or 2" + + def readall(self): + return self.read() + + def read(self, n=-1): + if n >= 0: + aim = self.pos + n + else: + aim = self.mm.size() # Actual file size, may be more than mapped + n = aim - self.pos + data = self.mm[self.pos:aim] + if len(data) < n: + del data + # File grew since opened; remap to get the new data + size = os.fstat(self.fd).st_size + self.mm = mmap.mmap(self.fd, size, access=self.access) + data = self.mm[self.pos:aim] + self.pos += len(data) + return data + + def __iter__(self): + return self + + def readline(self): + hit = self.mm.find("\n", self.pos) + 1 + if hit: + data = self.mm[self.pos:hit] + self.pos = hit + return data + # Remap the file just in case + size = os.fstat(self.fd).st_size + self.mm = mmap.mmap(self.fd, size, access=self.access) + hit = self.mm.find("\n", self.pos) + 1 + if hit: + # Got a whole line after remapping + data = self.mm[self.pos:hit] + self.pos = hit + return data + # Read whatever we've got -- may be empty + data = self.mm[self.pos:self.mm.size()] + self.pos += len(data) + return data + + def next(self): + hit = self.mm.find("\n", self.pos) + 1 + if hit: + data = self.mm[self.pos:hit] + self.pos = hit + return data + # Remap the file just in case + size = os.fstat(self.fd).st_size + self.mm = mmap.mmap(self.fd, size, access=self.access) + hit = self.mm.find("\n", self.pos) + 1 + if hit: + # Got a whole line after remapping + data = self.mm[self.pos:hit] + self.pos = hit + return data + # Read whatever we've got -- may be empty + data = self.mm[self.pos:self.mm.size()] + if not data: + raise StopIteration + self.pos += len(data) + return data + + def readlines(self, sizehint=0): + return list(iter(self.readline, "")) + + def write(self, data): + end = self.pos + len(data) + try: + self.mm[self.pos:end] = data + # This can raise IndexError on Windows, ValueError on Unix + except (IndexError, ValueError): + # XXX On Unix, this resize() call doesn't work + self.mm.resize(end) + self.mm[self.pos:end] = data + self.pos = end + + def writelines(self, lines): + filter(self.write, lines) + +class DiskFile(object): + + """Standard I/O basis stream using os.open/close/read/write/lseek""" + modes = { + 'r' : os.O_RDONLY, + 'rb' : os.O_RDONLY, + 'rU' : os.O_RDONLY, + 'U' : os.O_RDONLY, + 'w' : os.O_WRONLY, + 'wb' : os.O_WRONLY, + 'a' : os.O_WRONLY | os.O_CREAT | os.O_EXCL, + 'ab' : os.O_WRONLY | os.O_CREAT | os.O_EXCL, + 'r+' : os.O_RDWR, + 'rb+': os.O_RDWR, + 'r+b': os.O_RDWR, + 'w+' : os.O_RDWR | os.O_CREAT, + 'wb+': os.O_RDWR | os.O_CREAT, + 'w+b': os.O_RDWR | os.O_CREAT, + 'a+' : os.O_RDWR | os.O_CREAT | os.O_EXCL, + 'ab+': os.O_RDWR | os.O_CREAT | os.O_EXCL, + 'a+b': os.O_RDWR | os.O_CREAT | os.O_EXCL, + } + def __init__(self, filename, mode="r"): + self.filename = filename + self.mode = mode + try: + flag = DiskFile.modes[mode] + except KeyError: + raise ValueError, "mode should be 'r', 'r+', 'w', 'w+' or 'a+'" + + if hasattr(os, "O_BINARY"): + flag |= os.O_BINARY + try: + self.fd = os.open(filename, flag) + except OSError: + # Opening in mode 'a' or 'a+' and file already exists + flag = flag & (os.O_RDWR | os.O_BINARY) + self.fd = os.open(filename, flag) + if mode[0] == 'a': + os.lseek(self.fd, 0, 2) # Move to end of file + + def seek(self, offset, whence=0): + os.lseek(self.fd, offset, whence) + + def tell(self): + return os.lseek(self.fd, 0, 1) + + def read(self, n): + return os.read(self.fd, n) + + def write(self, data): + while data: + n = os.write(self.fd, data) + data = data[n:] + + def close(self): + fd = self.fd + if fd is not None: + self.fd = None + os.close(fd) + + def __del__(self): + try: + self.close() + except: + pass + +class TextInputFilter(object): + + """Filtering input stream for universal newline translation.""" + + def __init__(self, base): + self.base = base # must implement read, may implement tell, seek + self.atcr = False # Set when last char read was \r + self.buf = "" # Optional one-character read-ahead buffer + self.close = base.close + self.CR = False + self.NL = False + self.CRLF = False + + def __getattr__(self, name): + if name == 'newlines': + foundchars = self.CR * 1 + self.NL * 2 + self.CRLF * 4 + if not foundchars: + return None + if foundchars in [1, 2, 4]: + if self.CR: + return '\r' + elif self.NL: + return '\n' + else: + return '\r\n' + else: + result = [] + if self.CR: + result.append('\r') + if self.NL: + result.append('\n') + if self.CRLF: + result.append('\r\n') + return tuple(result) + + def read(self, n): + """Read up to n bytes.""" + if n <= 0: + return "" + if self.buf: + assert not self.atcr + data = self.buf + self.buf = "" + return data + data = self.base.read(n) + + # The following whole ugly mess is because we need to keep track of + # exactly which line separators we have seen for self.newlines, + # grumble, grumble. This has an interesting corner-case. + # + # Consider a file consisting of exactly one line ending with '\r'. + # The first time you read(), you will not know whether it is a + # CR separator or half of a CRLF separator. Neither will be marked + # as seen, since you are waiting for your next read to determine + # what you have seen. But there's no more to read ... + + if self.atcr: + if data.startswith("\n"): + data = data[1:] + self.CRLF = True + if not data: + data = self.base.read(n) + else: + self.CR = True + self.atcr = False + + for i in range(len(data)): + if data[i] == '\n': + if i > 0 and data[i-1] == '\r': + self.CRLF = True + else: + self.NL = True + elif data[i] == '\r': + if i < len(data)-1 and data[i+1] != '\n': + self.CR = True + + if "\r" in data: + self.atcr = data.endswith("\r") + data = data.replace("\r\n", "\n").replace("\r", "\n") + + return data + + def seek(self, offset, whence=0): + """Seeks based on knowledge that does not come from a tell() + may go to the wrong place, since the number of + characters seen may not match the number of characters + that are actually in the file (where \r\n is the + line separator). Arithmetics on the result + of a tell() that moves beyond a newline character may in the + same way give the wrong result. + """ + self.base.seek(offset, whence) + self.atcr = False + self.buf = "" + + def tell(self): + pos = self.base.tell() + if self.atcr: + # Must read the next byte to see if it's \n, + # because then we must report the next position. + assert not self.buf + self.buf = self.base.read(1) + pos += 1 + self.atcr = False + if self.buf == "\n": + self.buf = "" + return pos - len(self.buf) + +class TextOutputFilter(object): + + """Filtering output stream for universal newline translation.""" + + def __init__(self, base, linesep=os.linesep): + assert linesep in ["\n", "\r\n", "\r"] + self.base = base # must implement write, may implement seek, tell + self.linesep = linesep + self.close = base.close + + def write(self, data): + if self.linesep is not "\n" and "\n" in data: + data = data.replace("\n", self.linesep) + self.base.write(data) + + def seek(self, offset, whence=0): + self.base.seek(offset, whence) + + def tell(self): + return self.base.tell() + +class DecodingInputFilter(object): + + """Filtering input stream that decodes an encoded file.""" + + def __init__(self, base, encoding="utf8", errors="strict"): + self.base = base + self.encoding = encoding + self.errors = errors + self.tell = base.tell + self.seek = base.seek + self.close = base.close + + def read(self, n): + """Read *approximately* n bytes, then decode them. + + Under extreme circumstances, + the return length could be longer than n! + + Always return a unicode string. + + This does *not* translate newlines; + you can stack TextInputFilter. + """ + data = self.base.read(n) + try: + return data.decode(self.encoding, self.errors) + except ValueError: + # XXX Sigh. decode() doesn't handle incomplete strings well. + # Use the retry strategy from codecs.StreamReader. + for i in range(9): + more = self.base.read(1) + if not more: + raise + data += more + try: + return data.decode(self.encoding, self.errors) + except ValueError: + pass + raise + +class EncodingOutputFilter(object): + + """Filtering output stream that writes to an encoded file.""" + + def __init__(self, base, encoding="utf8", errors="strict"): + self.base = base + self.encoding = encoding + self.errors = errors + self.tell = base.tell + self.seek = base.seek + self.close = base.close + + def write(self, chars): + if isinstance(chars, str): + chars = unicode(chars) # Fail if it's not ASCII + self.base.write(chars.encode(self.encoding, self.errors)) Added: pypy/trunk/src/pypy/appspace/test/test_file.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test/test_file.py Sat Nov 20 19:52:21 2004 @@ -0,0 +1,20 @@ +import autopath +from pypy.appspace import _file +import unittest + +class FileTestCase(unittest.TestCase): + def setUp(self): + self.fd = _file.file_('test_file.py', 'r') + + def tearDown(self): + self.fd.close() + + def test_case_1(self): + self.assertEquals(self.fd.tell(), 0) + +def test_main(): + unittest.main() + + +if __name__ == "__main__": + test_main() Added: pypy/trunk/src/pypy/appspace/test/test_sio.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/appspace/test/test_sio.py Sat Nov 20 19:52:21 2004 @@ -0,0 +1,673 @@ +"""Unit tests for sio (new standard I/O).""" + +import os +import time +import tempfile +import unittest + +import sio + +class TestSource(object): + + def __init__(self, packets): + for x in packets: + assert x + self.orig_packets = list(packets) + self.packets = list(packets) + self.pos = 0 + + def tell(self): + return self.pos + + def seek(self, offset, whence=0): + if whence == 1: + offset += self.pos + elif whence == 2: + for packet in self.orig_packets: + offset += len(packet) + else: + assert whence == 0 + self.packets = list(self.orig_packets) + self.pos = 0 + while self.pos < offset: + data = self.read(offset - self.pos) + if not data: + break + assert self.pos == offset + + def read(self, n): + try: + data = self.packets.pop(0) + except IndexError: + return "" + if len(data) > n: + data, rest = data[:n], data[n:] + self.packets.insert(0, rest) + self.pos += len(data) + return data + + def close(self): + pass + +class TestReader(object): + + def __init__(self, packets): + for x in packets: + assert x + self.orig_packets = list(packets) + self.packets = list(packets) + self.pos = 0 + + def tell(self): + return self.pos + + def seek(self, offset, whence=0): + if whence == 1: + offset += self.pos + elif whence == 2: + for packet in self.orig_packets: + offset += len(packet) + else: + assert whence == 0 + self.packets = list(self.orig_packets) + self.pos = 0 + while self.pos < offset: + data = self.read(offset - self.pos) + if not data: + break + assert self.pos == offset + + def read(self, n): + try: + data = self.packets.pop(0) + except IndexError: + return "" + if len(data) > n: + data, rest = data[:n], data[n:] + self.packets.insert(0, rest) + self.pos += len(data) + return data + + def close(self): + pass + +class TestWriter(object): + + def __init__(self): + self.buf = "" + self.pos = 0 + + def write(self, data): + if self.pos >= len(self.buf): + self.buf += "\0" * (self.pos - len(self.buf)) + data + self.pos = len(self.buf) + else: + self.buf = (self.buf[:self.pos] + data + + self.buf[self.pos + len(data):]) + self.pos += len(data) + + def tell(self): + return self.pos + + def seek(self, offset, whence=0): + if whence == 0: + pass + elif whence == 1: + offset += self.pos + elif whence == 2: + offset += len(self.buf) + else: + raise ValueError, "whence should be 0, 1 or 2" + if offset < 0: + offset = 0 + self.pos = offset + + def close(self): + pass + +class BufferingInputStreamTests(unittest.TestCase): + + packets = ["a", "b", "\n", "def", "\nxy\npq\nuv", "wx"] + lines = ["ab\n", "def\n", "xy\n", "pq\n", "uvwx"] + + def makeStream(self, tell=False, seek=False, bufsize=None): + base = TestSource(self.packets) + if not tell: + base.tell = None + if not seek: + base.seek = None + return sio.BufferingInputStream(base, bufsize) + + def test_readline(self): + file = self.makeStream() + self.assertEqual(list(iter(file.readline, "")), self.lines) + + def test_readlines(self): + # This also tests next() and __iter__() + file = self.makeStream() + self.assertEqual(file.readlines(), self.lines) + + def test_readlines_small_bufsize(self): + file = self.makeStream(bufsize=1) + self.assertEqual(list(file), self.lines) + + def test_readall(self): + file = self.makeStream() + self.assertEqual(file.readall(), "".join(self.lines)) + + def test_readall_small_bufsize(self): + file = self.makeStream(bufsize=1) + self.assertEqual(file.readall(), "".join(self.lines)) + + def test_readall_after_readline(self): + file = self.makeStream() + self.assertEqual(file.readline(), self.lines[0]) + self.assertEqual(file.readline(), self.lines[1]) + self.assertEqual(file.readall(), "".join(self.lines[2:])) + + def test_read_1_after_readline(self): + file = self.makeStream() + self.assertEqual(file.readline(), "ab\n") + self.assertEqual(file.readline(), "def\n") + blocks = [] + while 1: + block = file.read(1) + if not block: + break + blocks.append(block) + self.assertEqual(file.read(0), "") + self.assertEqual(blocks, list("".join(self.lines)[7:])) + + def test_read_1(self): + file = self.makeStream() + blocks = [] + while 1: + block = file.read(1) + if not block: + break + blocks.append(block) + self.assertEqual(file.read(0), "") + self.assertEqual(blocks, list("".join(self.lines))) + + def test_read_2(self): + file = self.makeStream() + blocks = [] + while 1: + block = file.read(2) + if not block: + break + blocks.append(block) + self.assertEqual(file.read(0), "") + self.assertEqual(blocks, ["ab", "\nd", "ef", "\nx", "y\n", "pq", + "\nu", "vw", "x"]) + + def test_read_4(self): + file = self.makeStream() + blocks = [] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + self.assertEqual(file.read(0), "") + self.assertEqual(blocks, ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"]) + + def test_read_4_after_readline(self): + file = self.makeStream() + self.assertEqual(file.readline(), "ab\n") + self.assertEqual(file.readline(), "def\n") + blocks = [file.read(4)] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + self.assertEqual(file.read(0), "") + self.assertEqual(blocks, ["xy\np", "q\nuv", "wx"]) + + def test_read_4_small_bufsize(self): + file = self.makeStream(bufsize=1) + blocks = [] + while 1: + block = file.read(4) + if not block: + break + blocks.append(block) + self.assertEqual(blocks, ["ab\nd", "ef\nx", "y\npq", "\nuvw", "x"]) + + def test_tell_1(self): + file = self.makeStream(tell=True) + pos = 0 + while 1: + self.assertEqual(file.tell(), pos) + n = len(file.read(1)) + if not n: + break + pos += n + + def test_tell_1_after_readline(self): + file = self.makeStream(tell=True) + pos = 0 + pos += len(file.readline()) + self.assertEqual(file.tell(), pos) + pos += len(file.readline()) + self.assertEqual(file.tell(), pos) + while 1: + self.assertEqual(file.tell(), pos) + n = len(file.read(1)) + if not n: + break + pos += n + + def test_tell_2(self): + file = self.makeStream(tell=True) + pos = 0 + while 1: + self.assertEqual(file.tell(), pos) + n = len(file.read(2)) + if not n: + break + pos += n + + def test_tell_4(self): + file = self.makeStream(tell=True) + pos = 0 + while 1: + self.assertEqual(file.tell(), pos) + n = len(file.read(4)) + if not n: + break + pos += n + + def test_tell_readline(self): + file = self.makeStream(tell=True) + pos = 0 + while 1: + self.assertEqual(file.tell(), pos) + n = len(file.readline()) + if not n: + break + pos += n + + def test_seek(self): + file = self.makeStream(tell=True, seek=True) + all = file.readall() + end = len(all) + for readto in range(0, end+1): + for seekto in range(0, end+1): + for whence in 0, 1, 2: + file.seek(0) + self.assertEqual(file.tell(), 0) + head = file.read(readto) + self.assertEqual(head, all[:readto]) + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + else: + offset = seekto + file.seek(offset, whence) + here = file.tell() + self.assertEqual(here, seekto) + rest = file.readall() + self.assertEqual(rest, all[seekto:]) + + def test_seek_noseek(self): + file = self.makeStream() + all = file.readall() + end = len(all) + for readto in range(0, end+1): + for seekto in range(readto, end+1): + for whence in 1, 2: + file = self.makeStream() + head = file.read(readto) + self.assertEqual(head, all[:readto]) + if whence == 1: + offset = seekto - readto + elif whence == 2: + offset = seekto - end + file.seek(offset, whence) + rest = file.readall() + self.assertEqual(rest, all[seekto:]) + +class BufferingOutputStreamTests(unittest.TestCase): + + def test_write(self): + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.write("123") + self.assertEqual(base.buf, "") + self.assertEquals(filter.tell(), 3) + filter.write("456") + self.assertEqual(base.buf, "1234") + filter.write("789ABCDEF") + self.assertEqual(base.buf, "123456789ABC") + filter.write("0123") + self.assertEqual(base.buf, "123456789ABCDEF0") + self.assertEquals(filter.tell(), 19) + filter.close() + self.assertEqual(base.buf, "123456789ABCDEF0123") + + def test_write_seek(self): + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.write("x"*6) + filter.seek(3) + filter.write("y"*2) + filter.close() + self.assertEqual(base.buf, "x"*3 + "y"*2 + "x"*1) + +class LineBufferingOutputStreamTests(unittest.TestCase): + + def test_write(self): + base = TestWriter() + filter = sio.LineBufferingOutputStream(base) + filter.bufsize = 4 # More handy for testing than the default + filter.write("123") + self.assertEqual(base.buf, "") + self.assertEquals(filter.tell(), 3) + filter.write("456") + self.assertEqual(base.buf, "1234") + filter.write("789ABCDEF\n") + self.assertEqual(base.buf, "123456789ABCDEF\n") + filter.write("0123") + self.assertEqual(base.buf, "123456789ABCDEF\n0123") + self.assertEquals(filter.tell(), 20) + filter.close() + self.assertEqual(base.buf, "123456789ABCDEF\n0123") + + def xtest_write_seek(self): + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.write("x"*6) + filter.seek(3) + filter.write("y"*2) + filter.close() + self.assertEqual(base.buf, "x"*3 + "y"*2 + "x"*1) + +class CRLFFilterTests(unittest.TestCase): + + def test_filter(self): + packets = ["abc\ndef\rghi\r\nxyz\r", "123\r", "\n456"] + expected = ["abc\ndef\nghi\nxyz\n", "123\n", "456"] + crlf = sio.CRLFFilter(TestSource(packets)) + blocks = [] + while 1: + block = crlf.read(100) + if not block: + break + blocks.append(block) + self.assertEqual(blocks, expected) + +class MMapFileTests(BufferingInputStreamTests): + + tfn = None + + def tearDown(self): + tfn = self.tfn + if tfn: + self.tfn = None + try: + os.remove(tfn) + except os.error, msg: + print "can't remove %s: %s" % (tfn, msg) + + def makeStream(self, tell=None, seek=None, bufsize=None, mode="r"): + self.tfn = tempfile.mktemp() + f = open(self.tfn, "wb") + f.writelines(self.packets) + f.close() + return sio.MMapFile(self.tfn, mode) + + def test_write(self): + if os.name == "posix": + return # write() does't work on Unix :-( + file = self.makeStream(mode="w") + file.write("BooHoo\n") + file.write("Barf\n") + file.writelines(["a\n", "b\n", "c\n"]) + self.assertEqual(file.tell(), len("BooHoo\nBarf\na\nb\nc\n")) + file.seek(0) + self.assertEqual(file.read(), "BooHoo\nBarf\na\nb\nc\n") + file.seek(0) + self.assertEqual(file.readlines(), + ["BooHoo\n", "Barf\n", "a\n", "b\n", "c\n"]) + self.assertEqual(file.tell(), len("BooHoo\nBarf\na\nb\nc\n")) + +class TextInputFilterTests(unittest.TestCase): + + packets = [ + "foo\r", + "bar\r", + "\nfoo\r\n", + "abc\ndef\rghi\r\nxyz", + "\nuvw\npqr\r", + "\n", + "abc\n", + ] + expected = [ + ("foo\n", 4), + ("bar\n", 9), + ("foo\n", 14), + ("abc\ndef\nghi\nxyz", 30), + ("\nuvw\npqr\n", 40), + ("abc\n", 44), + ("", 44), + ("", 44), + ] + + expected_with_tell = [ + ("foo\n", 4), + ("b", 5), + ("ar\n", 9), + ("foo\n", 14), + ("abc\ndef\nghi\nxyz", 30), + ("\nuvw\npqr\n", 40), + ("abc\n", 44), + ("", 44), + ("", 44), + ] + + expected_newlines = [ + (["abcd"], [None]), + (["abcd\n"], ["\n"]), + (["abcd\r\n"],["\r\n"]), + (["abcd\r"],[None]), # wrong, but requires precognition to fix + (["abcd\r", "\nefgh"], [None, "\r\n"]), + (["abcd", "\nefg\r", "hij", "k\r\n"], [None, "\n", ("\r", "\n"), + ("\r", "\n", "\r\n")]), + (["abcd", "\refg\r", "\nhij", "k\n"], [None, "\r", ("\r", "\r\n"), + ("\r", "\n", "\r\n")]) + ] + + def test_read(self): + base = TestReader(self.packets) + filter = sio.TextInputFilter(base) + for data, pos in self.expected: + self.assertEqual(filter.read(100), data) + + def test_read_tell(self): + base = TestReader(self.packets) + filter = sio.TextInputFilter(base) + for data, pos in self.expected_with_tell: + self.assertEqual(filter.read(100), data) + self.assertEqual(filter.tell(), pos) + self.assertEqual(filter.tell(), pos) # Repeat the tell() ! + + def test_seek(self): + base = TestReader(self.packets) + filter = sio.TextInputFilter(base) + sofar = "" + pairs = [] + while True: + pairs.append((sofar, filter.tell())) + c = filter.read(1) + if not c: + break + self.assertEqual(len(c), 1) + sofar += c + all = sofar + for i in range(len(pairs)): + sofar, pos = pairs[i] + filter.seek(pos) + self.assertEqual(filter.tell(), pos) + self.assertEqual(filter.tell(), pos) + bufs = [sofar] + while True: + data = filter.read(100) + if not data: + self.assertEqual(filter.read(100), "") + break + bufs.append(data) + self.assertEqual("".join(bufs), all) + + def test_newlines_attribute(self): + + for packets, expected in self.expected_newlines: + base = TestReader(packets) + filter = sio.TextInputFilter(base) + for e in expected: + filter.read(100) + self.assertEquals(filter.newlines, e) + +class TextOutputFilterTests(unittest.TestCase): + + def test_write_nl(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\n") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + self.assertEqual(base.buf, "abcdef\npqr\nuvw\n123\n") + + def test_write_cr(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\r") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + self.assertEqual(base.buf, "abcdef\rpqr\ruvw\r123\r") + + def test_write_crnl(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\r\n") + filter.write("abc") + filter.write("def\npqr\nuvw") + filter.write("\n123\n") + self.assertEqual(base.buf, "abcdef\r\npqr\r\nuvw\r\n123\r\n") + + def test_write_tell_nl(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\n") + filter.write("xxx") + self.assertEqual(filter.tell(), 3) + filter.write("\nabc\n") + self.assertEqual(filter.tell(), 8) + + def test_write_tell_cr(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\r") + filter.write("xxx") + self.assertEqual(filter.tell(), 3) + filter.write("\nabc\n") + self.assertEqual(filter.tell(), 8) + + def test_write_tell_crnl(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\r\n") + filter.write("xxx") + self.assertEqual(filter.tell(), 3) + filter.write("\nabc\n") + self.assertEqual(filter.tell(), 10) + + def test_write_seek(self): + base = TestWriter() + filter = sio.TextOutputFilter(base, linesep="\n") + filter.write("x"*100) + filter.seek(50) + filter.write("y"*10) + self.assertEqual(base.buf, "x"*50 + "y"*10 + "x"*40) + +class DecodingInputFilterTests(unittest.TestCase): + + def test_read(self): + chars = u"abc\xff\u1234\u4321\x80xyz" + data = chars.encode("utf8") + base = TestReader([data]) + filter = sio.DecodingInputFilter(base) + bufs = [] + for n in range(1, 11): + while 1: + c = filter.read(n) + self.assertEqual(type(c), unicode) + if not c: + break + bufs.append(c) + self.assertEqual(u"".join(bufs), chars) + +class EncodingOutputFilterTests(unittest.TestCase): + + def test_write(self): + chars = u"abc\xff\u1234\u4321\x80xyz" + data = chars.encode("utf8") + for n in range(1, 11): + base = TestWriter() + filter = sio.EncodingOutputFilter(base) + pos = 0 + while 1: + c = chars[pos:pos+n] + if not c: + break + pos += len(c) + filter.write(c) + self.assertEqual(base.buf, data) + +# Speed test + +FN = "BIG" + +def timeit(fn=FN, opener=sio.MMapFile): + f = opener(fn, "r") + lines = bytes = 0 + t0 = time.clock() + for line in f: + lines += 1 + bytes += len(line) + t1 = time.clock() + print "%d lines (%d bytes) in %.3f seconds for %s" % ( + lines, bytes, t1-t0, opener.__name__) + +def speed_main(): + def diskopen(fn, mode): + base = sio.DiskFile(fn, mode) + return sio.BufferingInputStream(base) + timeit(opener=diskopen) + timeit(opener=sio.MMapFile) + timeit(opener=open) + +# Functional test + +def functional_main(): + f = sio.DiskFile("sio.py") + f = sio.DecodingInputFilter(f) + f = sio.TextInputFilter(f) + f = sio.BufferingInputStream(f) + for i in range(10): + print repr(f.readline()) + +def makeSuite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(BufferingInputStreamTests)) + suite.addTest(unittest.makeSuite(BufferingOutputStreamTests)) + suite.addTest(unittest.makeSuite(LineBufferingOutputStreamTests)) + suite.addTest(unittest.makeSuite(CRLFFilterTests)) + suite.addTest(unittest.makeSuite(MMapFileTests)) + suite.addTest(unittest.makeSuite(TextInputFilterTests)) + suite.addTest(unittest.makeSuite(TextOutputFilterTests)) + suite.addTest(unittest.makeSuite(DecodingInputFilterTests)) + suite.addTest(unittest.makeSuite(EncodingOutputFilterTests)) + + return suite + +if __name__ == "__main__": + unittest.TextTestRunner().run(makeSuite()) From tismer at codespeak.net Sat Nov 20 19:54:29 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Sat, 20 Nov 2004 19:54:29 +0100 (MET) Subject: [pypy-svn] r7531 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041120185429.5EF4C5B4A0@thoth.codespeak.net> Author: tismer Date: Sat Nov 20 19:54:28 2004 New Revision: 7531 Modified: pypy/trunk/src/pypy/objspace/flow/model.py Log: a few more decorations via __str__ and __repr__ for simple display of blocks and links. Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Sat Nov 20 19:54:28 2004 @@ -60,6 +60,9 @@ self.exitcase = exitcase # this is a concrete value self.prevblock = None # the block this Link is an exit of + def __repr__(self): + return "link from %s to %s" % (str(self.prevblock), str(self.target)) + class Block: isstartblock = False @@ -70,6 +73,19 @@ # Constant(last_exception), see below self.exits = [] # list of Link(s) + def __str__(self): + if self.operations: + txt = "block@%d" % self.operations[0].offset + else: + txt = "codeless block" + return txt + + def __repr__(self): + txt = "%s with %d exits" % (str(self), len(self.exits)) + if self.exitswitch: + txt = "%s(%s)" % (txt, self.exitswitch) + return txt + def getvariables(self): "Return all variables mentioned in this Block." result = self.inputargs[:] From arigo at codespeak.net Sat Nov 20 19:57:41 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 20 Nov 2004 19:57:41 +0100 (MET) Subject: [pypy-svn] r7532 - in pypy/trunk/src/pypy: objspace/flow objspace/flow/test translator Message-ID: <20041120185741.2CDCA5B4A2@thoth.codespeak.net> Author: arigo Date: Sat Nov 20 19:57:40 2004 New Revision: 7532 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py pypy/trunk/src/pypy/translator/simplify.py Log: most probably maybe this should be tested, but time is running out. Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sat Nov 20 19:57:40 2004 @@ -148,7 +148,8 @@ newblock.patchframe(frame, self) self.joinpoints[next_instr].insert(0, newblock) - def guessbool(self, w_condition, cases=[False,True]): + def guessbool(self, w_condition, cases=[False,True], + ignore_last_variable_except_in_first_case = False): if isinstance(self.crnt_ops, list): block = self.crnt_block vars = block.getvariables() @@ -158,6 +159,9 @@ self.pendingblocks.append(egg) link = Link(vars, egg, case) links.append(link) + if ignore_last_variable_except_in_first_case: + vars.remove(block.operations[-1].result) + ignore_last_variable_except_in_first_case = False block.exitswitch = w_condition block.closeblock(*links) # forked the graph. Note that False comes before True by default @@ -176,7 +180,8 @@ def guessexception(self, *classes): return self.guessbool(Constant(last_exception), - cases = [None] + list(classes)) + cases = [None] + list(classes), + ignore_last_variable_except_in_first_case = True) def build_flow(self): from pypy.objspace.flow.objspace import UnwrapException Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Sat Nov 20 19:57:40 2004 @@ -291,7 +291,7 @@ def test_catch_simple_call(self): x = self.codetest(self.catch_simple_call) - self.show(x) + self.reallyshow(x) #__________________________________________________________ def dellocal(): Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Sat Nov 20 19:57:40 2004 @@ -67,26 +67,38 @@ function removes such exceptions entierely. This gets rid for example of possible IndexErrors by 'getitem', assuming they cannot happen unless there is an exception handler in the same function.""" + def is_except_link(link): + return (link.args == [Constant(last_exception)] and + len(link.target.exits) == 0 and + hasattr(link.target, 'exc_type')) def visit(link): if isinstance(link, Link) and link in link.prevblock.exits: if (isinstance(link.exitcase, type(Exception)) and - issubclass(link.exitcase, Exception) and - link.args == [Constant(last_exception)] and - len(link.target.exits) == 0 and - hasattr(link.target, 'exc_type')): - # remove direct links to implicit exception return blocks - lst = list(link.prevblock.exits) - lst.remove(link) - link.prevblock.exits = tuple(lst) + issubclass(link.exitcase, Exception)): + # two cases: a jump directly to an exception-raising end block, + # or a jump to a block containing only a 'type' operation + # and then jumping to such an exception-raising end block. + # Argh. + block = link.target + if (is_except_link(link) or + (len(block.operations) == 1 and + block.operations[0].opname == 'type' and + len(block.exits) == 1 and + is_except_link(block.exits[0]) and + block.operations[0].result not in block.exits[0].args)): + # remove the link + lst = list(link.prevblock.exits) + lst.remove(link) + link.prevblock.exits = tuple(lst) traverse(visit, graph) def simplify_graph(graph, rpython=True): """inplace-apply all the existing optimisations to the graph.""" checkgraph(graph) eliminate_empty_blocks(graph) + join_blocks(graph) if rpython: remove_implicit_exceptions(graph) - join_blocks(graph) checkgraph(graph) def remove_direct_loops(graph): From arigo at codespeak.net Sun Nov 21 16:40:49 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 21 Nov 2004 16:40:49 +0100 (MET) Subject: [pypy-svn] r7533 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041121154049.5A3985A70E@thoth.codespeak.net> Author: arigo Date: Sun Nov 21 16:40:48 2004 New Revision: 7533 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: - increased the margin to see the blocks that are at the bottom of the graph (they were always partially masked by the status bar) - len(reasonable_key_bindings) > 1 because len(keyboard_layouts) > 1 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Sun Nov 21 16:40:48 2004 @@ -193,7 +193,7 @@ class GraphRenderer: - MARGIN = 0.2 + MARGIN = 0.6 SCALEMIN = 3 SCALEMAX = 100 FONTCACHE = {} Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Sun Nov 21 16:40:48 2004 @@ -25,7 +25,7 @@ for ident in dir(pygame.locals) if ident.startswith('K_') ]) -KEYS['plus'] = ('=', '+') +KEYS['plus'] = ('=', '+', '.') KEYS['quit'] = ('q', 'escape') KEYS['help'] = ('h', '?', 'f1') @@ -103,7 +103,7 @@ HELP_MSG = """ Key bindings: - + or = Zoom in + +, = or . Zoom in - Zoom out 1 Zoom to fit 0 Actual size From arigo at codespeak.net Sun Nov 21 16:50:22 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 21 Nov 2004 16:50:22 +0100 (MET) Subject: [pypy-svn] r7534 - in pypy/trunk/src/pypy: objspace/flow objspace/flow/test translator translator/test translator/tool Message-ID: <20041121155022.D9C5C5AA26@thoth.codespeak.net> Author: arigo Date: Sun Nov 21 16:50:21 2004 New Revision: 7534 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/gencl.py pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/tool/flowtrace.py pypy/trunk/src/pypy/translator/tool/make_dot.py pypy/trunk/src/pypy/translator/transform.py Log: Made the flow graph model more regular with respect to exception handling. Graphs now have only two exit blocks: a regular return block and a "raise" exit block. The latter takes two input arguments, which are the class and the value of the exception to raise. 'last_exception' and 'last_exc_value' are now just "local" hacks: they can only appear at the point where we want to catch an exception. From there the graph can capture and propagate the exception class and value by linking 'last_exception' and 'last_exc_value' to the next block's input variables. Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sun Nov 21 16:50:21 2004 @@ -149,19 +149,24 @@ self.joinpoints[next_instr].insert(0, newblock) def guessbool(self, w_condition, cases=[False,True], - ignore_last_variable_except_in_first_case = False): + replace_last_variable_except_in_first_case = None): if isinstance(self.crnt_ops, list): block = self.crnt_block - vars = block.getvariables() + vars = vars2 = block.getvariables() links = [] for case in cases: - egg = EggBlock(vars, block, case) + egg = EggBlock(vars2, block, case) self.pendingblocks.append(egg) link = Link(vars, egg, case) links.append(link) - if ignore_last_variable_except_in_first_case: - vars.remove(block.operations[-1].result) - ignore_last_variable_except_in_first_case = False + if replace_last_variable_except_in_first_case is not None: + assert block.operations[-1].result is vars[-1] + vars = vars[:-1] + vars.extend(replace_last_variable_except_in_first_case) + vars2 = vars2[:-1] + while len(vars2) < len(vars): + vars2.append(Variable()) + replace_last_variable_except_in_first_case = None block.exitswitch = w_condition block.closeblock(*links) # forked the graph. Note that False comes before True by default @@ -179,9 +184,16 @@ w_condition,) def guessexception(self, *classes): - return self.guessbool(Constant(last_exception), - cases = [None] + list(classes), - ignore_last_variable_except_in_first_case = True) + outcome = self.guessbool(Constant(last_exception), + cases = [None] + list(classes), + replace_last_variable_except_in_first_case = [ + Constant(last_exception), # exc. class + Constant(last_exc_value)]) # exc. value + if outcome is None: + w_exc_cls, w_exc_value = None, None + else: + w_exc_cls, w_exc_value = self.crnt_block.inputargs[-2:] + return outcome, w_exc_cls, w_exc_value def build_flow(self): from pypy.objspace.flow.objspace import UnwrapException @@ -195,11 +207,7 @@ try: w_result = frame.eval(self) except OperationError, e: - try: - exc_type = self.space.unwrap(e.w_type) - except UnwrapException: - exc_type = unknown_exception - link = Link([e.w_value], self.graph.getexceptblock(exc_type)) + link = Link([e.w_type, e.w_value], self.graph.exceptblock) self.crnt_block.closeblock(link) else: if w_result is not None: @@ -218,7 +226,3 @@ mapping[a] = Variable() node.renamevariables(mapping) traverse(fixegg, self.graph) - - -class unknown_exception(object): # not meant to be raised! - pass Modified: pypy/trunk/src/pypy/objspace/flow/model.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/model.py (original) +++ pypy/trunk/src/pypy/objspace/flow/model.py Sun Nov 21 16:50:21 2004 @@ -14,7 +14,11 @@ self.returnblock = Block([return_var or Variable()]) self.returnblock.operations = () self.returnblock.exits = () - self.exceptblocks = {} # Blocks corresponding to exception results + # block corresponding to exception results + self.exceptblock = Block([Variable(), # exception class + Variable()]) # exception value + self.exceptblock.operations = () + self.exceptblock.exits = () def getargs(self): return self.startblock.inputargs @@ -22,16 +26,6 @@ def getreturnvar(self): return self.returnblock.inputargs[0] - def getexceptblock(self, exc_type): - try: - block = self.exceptblocks[exc_type] - except KeyError: - block = self.exceptblocks[exc_type] = Block([Variable()]) - block.exc_type = exc_type - block.operations = () - block.exits = () - return block - def hasonlyexceptionreturns(self): try: return self._onlyex @@ -102,6 +96,8 @@ return uniqueitems([w for w in result if isinstance(w, Constant)]) def renamevariables(self, mapping): + for a in mapping: + assert isinstance(a, Variable), a self.inputargs = [mapping.get(a, a) for a in self.inputargs] for op in self.operations: op.args = [mapping.get(a, a) for a in op.args] @@ -191,10 +187,14 @@ def __repr__(self): return "%r = %s(%s)" % (self.result, self.opname, ", ".join(map(repr, self.args))) -class LastExceptionValue: +class Atom: + "NOT_RPYTHON" + def __init__(self, name): + self.name = name def __repr__(self): - return 'last_exception' -last_exception = LastExceptionValue() + return self.name +last_exception = Atom('last_exception') +last_exc_value = Atom('last_exc_value') # if Block().exitswitch == Constant(last_exception), it means that we are # interested in catching the exception that the *last operation* of the # block could raise. The exitcases of the links are None for no exception @@ -286,7 +286,8 @@ "Check the consistency of a flow graph." if __debug__: this_block = [None] - exitblocks = [graph.returnblock] + graph.exceptblocks.values() + exitblocks = {graph.returnblock: 1, # retval + graph.exceptblock: 2} # exc_cls, exc_value def visit(block): if isinstance(block, Block): @@ -330,9 +331,9 @@ vars_previous_blocks.update(vars) try: - for block in exitblocks: + for block, nbargs in exitblocks.items(): this_block[0] = block - assert len(block.inputargs) == 1 + assert len(block.inputargs) == nbargs assert not block.operations assert not block.exits Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sun Nov 21 16:50:21 2004 @@ -199,7 +199,7 @@ def next(self, w_iter): w_item = self.do_operation("next", w_iter) context = self.getexecutioncontext() - outcome = context.guessexception(StopIteration) + outcome, w_exc_cls, w_exc_value = context.guessexception(StopIteration) if outcome is StopIteration: raise OperationError(self.w_StopIteration, self.w_None) else: @@ -228,7 +228,7 @@ # # as shown by test_objspace.test_raise3. - exceptions = True # *any* exception by default + exceptions = [Exception] # *any* exception by default if isinstance(w_callable, Constant): c = w_callable.value if isinstance(c, (types.BuiltinFunctionType, @@ -250,19 +250,14 @@ # the RPython definition: implicit exceptions not explicitly # caught in the same function are assumed not to occur. context = self.getexecutioncontext() - if exceptions == True: - # any exception - outcome = context.guessexception(Exception) - if outcome is not None: - w_value = self.wrap(last_exception) - w_type = self.do_operation('type', w_value) - raise OperationError(w_type, w_value) - else: - # only the specified exception(s) - outcome = context.guessexception(*exceptions) - if outcome is not None: - raise OperationError(self.wrap(outcome), - self.wrap(last_exception)) + outcome, w_exc_cls, w_exc_value = context.guessexception(*exceptions) + if outcome is not None: + # we assume that the caught exc_cls will be exactly the + # one specified by 'outcome', and not a subclass of it, + # unless 'outcome' is Exception. + if outcome is not Exception: + w_exc_cls = Constant(outcome) + raise OperationError(w_exc_cls, w_exc_value) # ______________________________________________________________________ Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Sun Nov 21 16:50:21 2004 @@ -230,12 +230,14 @@ def test_raise1(self): x = self.codetest(self.raise1) + self.show(x) assert len(x.startblock.operations) == 1 assert x.startblock.operations[0].opname == 'simple_call' assert list(x.startblock.operations[0].args) == [Constant(IndexError)] - assert x.startblock.operations[0].result is x.startblock.exits[0].args[0] - assert x.startblock.exits[0].target is x.exceptblocks[IndexError] - self.show(x) + assert x.startblock.exits[0].args == [ + Constant(IndexError), + x.startblock.operations[0].result] + assert x.startblock.exits[0].target is x.exceptblock #__________________________________________________________ def raise2(msg): @@ -243,9 +245,12 @@ def test_raise2(self): x = self.codetest(self.raise2) - assert len(x.startblock.operations) == 0 - assert x.startblock.exits[0].target is x.exceptblocks[IndexError] self.show(x) + assert len(x.startblock.operations) == 0 + assert x.startblock.exits[0].args == [ + Constant(IndexError), + x.startblock.inputargs[0]] + assert x.startblock.exits[0].target is x.exceptblock #__________________________________________________________ def raise3(msg): @@ -253,13 +258,16 @@ def test_raise3(self): x = self.codetest(self.raise3) + self.show(x) assert len(x.startblock.operations) == 1 assert x.startblock.operations[0].opname == 'simple_call' assert list(x.startblock.operations[0].args) == [ - Constant(IndexError), x.startblock.inputargs[0]] - assert x.startblock.operations[0].result is x.startblock.exits[0].args[0] - assert x.startblock.exits[0].target is x.exceptblocks[IndexError] - self.show(x) + Constant(IndexError), + x.startblock.inputargs[0]] + assert x.startblock.exits[0].args == [ + Constant(IndexError), + x.startblock.operations[0].result] + assert x.startblock.exits[0].target is x.exceptblock #__________________________________________________________ def raise4(stuff): @@ -291,7 +299,7 @@ def test_catch_simple_call(self): x = self.codetest(self.catch_simple_call) - self.reallyshow(x) + self.show(x) #__________________________________________________________ def dellocal(): Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sun Nov 21 16:50:21 2004 @@ -48,7 +48,7 @@ func = func_or_flowgraph if self.translator is None: from pypy.translator.translator import Translator - self.translator = Translator(func) + self.translator = Translator(func, simplifying=True) self.translator.annotator = self flowgraph = self.translator.getflowgraph(func) # make input arguments and set their type Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sun Nov 21 16:50:21 2004 @@ -8,8 +8,6 @@ #include "structmember.h" #include "traceback.h" -/* XXX HACK HACK HACK HACK HACK HACK HACK HACK HACK */ -#define PyExc_unknown_exception PyExc_Exception #if !defined(MIN) #define MIN(a,b) (((a)<(b))?(a):(b)) #endif /* MIN */ Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sun Nov 21 16:50:21 2004 @@ -5,7 +5,8 @@ from __future__ import generators import autopath, os, sys from pypy.objspace.flow.model import Variable, Constant, SpaceOperation -from pypy.objspace.flow.model import FunctionGraph, Block, Link, last_exception +from pypy.objspace.flow.model import FunctionGraph, Block, Link +from pypy.objspace.flow.model import last_exception, last_exc_value from pypy.objspace.flow.model import traverse, uniqueitems, checkgraph from pypy.translator.simplify import remove_direct_loops from pypy.interpreter.pycode import CO_VARARGS @@ -90,6 +91,8 @@ n = self.seennames.get(basename, 0) self.seennames[basename] = n+1 if n == 0: + self.globalobjects.append(basename) + self.globaldecl.append('static PyObject *%s;' % (basename,)) return basename else: return self.uniquename('%s_%d' % (basename, n)) @@ -98,7 +101,6 @@ if type(value) is not object: raise Exception, "nameof(%r)" % (value,) name = self.uniquename('g_object') - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) return name @@ -109,7 +111,6 @@ value.__file__.endswith('.pyo')), \ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod%s'%value.__name__) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) return name @@ -119,7 +120,7 @@ name = 'gint_%d' % value else: name = 'gint_minus%d' % abs(value) - self.globalobjects.append(name) + name = self.uniquename(name) self.initcode.append('INITCHK(%s = ' 'PyInt_FromLong(%d))' % (name, value)) return name @@ -130,7 +131,7 @@ name = 'glong%d' % value else: name = 'glong_minus%d' % abs(value) - self.globalobjects.append(name) + name = self.uniquename(name) self.initcode.append('INITCHK(%s = ' 'PyLong_FromLong(%d))' % (name, value)) return name @@ -145,7 +146,6 @@ '_' == c )] name = ''.join(chrs) name = self.uniquename(name) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = ' 'PyFloat_FromFloat(%r))' % (name, value)) return name @@ -156,7 +156,6 @@ '0' <= c <='9' or '_' == c )] name = self.uniquename('gstr_' + ''.join(chrs)) - self.globalobjects.append(name) if [c for c in value if not (' '<=c<='~')]: # non-printable string s = 'chr_%s' % name @@ -173,7 +172,6 @@ # debugging only! Generates a placeholder for missing functions # that raises an exception when called. name = self.uniquename('gskippedfunc_' + func.__name__) - self.globalobjects.append(name) self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) @@ -197,7 +195,6 @@ return self.skipped_function(func) #print "nameof", printable_name name = self.uniquename('gfunc_' + func.__name__) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) @@ -211,7 +208,6 @@ assert func in self.translator.flowgraphs, func name = self.uniquename('gsm_' + func.__name__) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) self.pendingfunctions.append(func) @@ -227,7 +223,6 @@ func = self.nameof(meth.im_func) typ = self.nameof(meth.im_class) name = self.uniquename('gmeth_'+meth.im_func.__name__) - self.globalobjects.append(name) self.initcode.append( 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( name, func, ob, typ)) @@ -262,7 +257,6 @@ if self.should_translate_attr(instance, key): yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) - self.globalobjects.append(name) self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( name, cls)) self.later(initinstance()) @@ -283,7 +277,6 @@ else: raise Exception, '%r not found in any built-in module' % (func,) name = self.uniquename('gbltin_' + func.__name__) - self.globalobjects.append(name) if modname == '__builtin__': self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' 'PyEval_GetBuiltins(), "%s"))' % ( @@ -295,7 +288,6 @@ else: # builtin (bound) method name = self.uniquename('gbltinmethod_' + func.__name__) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' '%s, "%s"))' % ( name, self.nameof(func.__self__), func.__name__)) @@ -334,7 +326,6 @@ yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( name, key, self.nameof(value)) - self.globalobjects.append(name) baseargs = ", ".join(basenames) if baseargs: @@ -394,7 +385,6 @@ def nameof_tuple(self, tup): name = self.uniquename('g%dtuple' % len(tup)) - self.globalobjects.append(name) args = [self.nameof(x) for x in tup] args.insert(0, '%d' % len(tup)) args = ', '.join(args) @@ -408,7 +398,6 @@ item = self.nameof(lis[i]) yield '\tPy_INCREF(%s);' % item yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) self.later(initlist()) return name @@ -428,7 +417,6 @@ yield ('\tINITCHK(PyDict_SetItem' '(%s, %s, %s) >= 0)'%( name, self.nameof(k), self.nameof(dic[k]))) - self.globalobjects.append(name) self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) self.later(initdict()) return name @@ -438,7 +426,6 @@ def nameof_member_descriptor(self, md): name = self.uniquename('gdescriptor_%s_%s' % ( md.__objclass__.__name__, md.__name__)) - self.globalobjects.append(name) cls = self.nameof(md.__objclass__) self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % cls) @@ -492,8 +479,6 @@ def gen_global_declarations(self): g = self.globaldecl - for name in self.globalobjects: - g.append('static PyObject *%s;' % (name,)) if g: f = self.f print >> f, '/* global declaration%s */' % ('s'*(len(g)>1)) @@ -616,21 +601,26 @@ else: raise TypeError, "expr(%r)" % (v,) - def gen_link(link): + def gen_link(link, linklocalvars=None): "Generate the code to jump across the given Link." has_ref = {} + linklocalvars = linklocalvars or {} for v in to_release: - has_ref[v] = True + linklocalvars[v] = v.name + has_ref = linklocalvars.copy() for a1, a2 in zip(link.args, link.target.inputargs): - line = 'MOVE(%s, %s)' % (expr(a1), a2.name) + if a1 in linklocalvars: + src = linklocalvars[a1] + else: + src = expr(a1) + line = 'MOVE(%s, %s)' % (src, a2.name) if a1 in has_ref: del has_ref[a1] else: line += '\tPy_INCREF(%s);' % a2.name yield line - for v in to_release: - if v in has_ref: - yield 'Py_DECREF(%s);' % v.name + for v in has_ref: + yield 'Py_DECREF(%s);' % linklocalvars[v] yield 'goto block%d;' % blocknum[link.target] # collect all blocks @@ -659,14 +649,15 @@ err_reachable = False if len(block.exits) == 0: - retval = expr(block.inputargs[0]) - if hasattr(block, 'exc_type'): + if len(block.inputargs) == 2: # exc_cls, exc_value # exceptional return block - yield 'PyErr_SetObject(PyExc_%s, %s);' % ( - block.exc_type.__name__, retval) + exc_cls = expr(block.inputargs[0]) + exc_value = expr(block.inputargs[1]) + yield 'PyErr_SetObject(%s, %s);' % (exc_cls, retval) yield 'FUNCTION_RETURN(NULL)' else: # regular return block + retval = expr(block.inputargs[0]) yield 'FUNCTION_RETURN(%s)' % retval continue elif block.exitswitch is None: @@ -690,10 +681,18 @@ yield '' for link in block.exits[1:]: assert issubclass(link.exitcase, Exception) - yield 'if (PyErr_ExceptionMatches(PyExc_%s)) {' % ( - link.exitcase.__name__,) - yield '\tPyErr_Clear();' - for op in gen_link(link): + yield 'if (PyErr_ExceptionMatches(%s)) {' % ( + self.nameof(link.exitcase),) + yield '\tPyObject *exc_cls, *exc_value, *exc_tb;' + yield '\tPyErr_Fetch(&exc_cls, &exc_value, &exc_tb);' + yield '\tif (exc_value == NULL) {' + yield '\t\texc_value = Py_None;' + yield '\t\tPy_INCREF(Py_None);' + yield '\t}' + yield '\tPy_XDECREF(exc_tb);' + for op in gen_link(link, { + Constant(last_exception): 'exc_cls', + Constant(last_exc_value): 'exc_value'}): yield '\t' + op yield '}' err_reachable = True @@ -723,7 +722,7 @@ # ____________________________________________________________ - C_HEADER = '#include "genc.h"' + C_HEADER = '#include "genc.h"\n' C_SEP = "/************************************************************/" Modified: pypy/trunk/src/pypy/translator/gencl.py ============================================================================== --- pypy/trunk/src/pypy/translator/gencl.py (original) +++ pypy/trunk/src/pypy/translator/gencl.py Sun Nov 21 16:50:21 2004 @@ -189,6 +189,8 @@ return "'%s" % val.__name__ elif val is last_exception: return "last-exc" + elif val is last_exc_value: + return "'last-exc-value" else: return "#<%r>" % (val,) def emitcode(self): @@ -274,9 +276,10 @@ print "(progn ; else should be", self.conv(exits[-1].exitcase) self.emit_link(exits[-1]) print ")" * len(exits) - elif hasattr(block, 'exc_type'): - excname = block.exc_type.__name__ - print "(something-like-throw-exception '%s)" % excname + elif len(block.inputargs) == 2: # exc_cls, exc_value + exc_cls = self.str(block.inputargs[0]) + exc_value = self.str(block.inputargs[1]) + print "(something-like-throw-exception %s %s)" % (exc_cls, exc_value) else: retval = self.str(block.inputargs[0]) print "(return", retval, ")" Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Sun Nov 21 16:50:21 2004 @@ -4,7 +4,7 @@ """ from pypy.interpreter.baseobjspace import ObjSpace from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant -from pypy.objspace.flow.model import mkentrymap +from pypy.objspace.flow.model import mkentrymap, last_exception from pypy.translator.annrpython import RPythonAnnotator from pypy.annotation.model import SomeCallable from pypy.annotation.factory import isclassdef @@ -59,15 +59,8 @@ return "%s = %s(%s)" % (self.resultname, self.op.opname, ", ".join(self.argnames)) def op_next(self): - lines = [] args = self.argnames - lines.append("try:") - lines.append(" %s = %s.next()" % (self.resultname, args[0])) - lines.append("except StopIteration:") - lines.append(" last_exc = StopIteration") - lines.append("else:") - lines.append(" last_exc = None") - return "\n".join(lines) + return "%s = %s.next()" % (self.resultname, args[0]) def op_getitem(self): direct = "%s = %s[%s]" % ((self.resultname,) + tuple(self.argnames)) @@ -149,9 +142,6 @@ def op_is_true(self): return "%s = not not %s" % (self.resultname, self.argnames[0]) - def op_exception(self): - return "%s, last_exc = last_exc, None" % (self.resultname,) - class GenPyrex: def __init__(self, functiongraph): self.functiongraph = functiongraph @@ -191,7 +181,6 @@ currentlines = self.lines self.lines = [] self.indent += 1 - self.putline("last_exc = None") self.gen_block(fun.startblock) self.indent -= 1 # emit the header after the body @@ -338,31 +327,60 @@ #the label is only written if there are multiple refs to the block if len(self.entrymap[block]) > 1: self.putline('cinline "Label%s:"' % blockids[block]) - for op in block.operations: + + if block.exitswitch == Constant(last_exception): + catch_exc = len(block.operations)-1 + else: + catch_exc = None + + for i, op in zip(range(len(block.operations)), block.operations): + if i == catch_exc: + self.putline("try:") + self.indent += 1 opg = Op(op, self, block) self.putline(opg()) - - exits = block.exits - if len(exits) == 1: - self.gen_link(block, exits[0]) - elif len(exits) > 1: - varname = self._str(block.exitswitch, block) - for i in range(len(exits)): - exit = exits[-i-1] # reverse order - cond = self._str(Constant(exit.exitcase), block) - if i == 0: - self.putline("if %s == %s:" % (varname, cond)) - elif i < len(exits) - 1: - self.putline("elif %s == %s:" % (varname, cond)) - else: - self.putline("else: # %s == %s" % (varname, cond)) + if i == catch_exc: + # generate all exception handlers + self.indent -= 1 + exits = block.exits + for exit in exits[1:]: + self.putline("except %s, last_exc_value:" % + exit.exitcase.__name__) + self.indent += 1 + self.putline("last_exception = last_exc_value.__class__") + self.gen_link(block, exit) + self.indent -= 1 + self.putline("else:") # no-exception case self.indent += 1 - self.gen_link(block, exit) + assert exits[0].exitcase is None + self.gen_link(block, exits[0]) self.indent -= 1 - elif hasattr(block, 'exc_type'): - self.putline("raise %s" % block.exc_type.__name__) + break + else: - self.putline("return %s" % self._str(block.inputargs[0], block)) + exits = block.exits + if len(exits) == 1: + self.gen_link(block, exits[0]) + elif len(exits) > 1: + varname = self._str(block.exitswitch, block) + for i in range(len(exits)): + exit = exits[-i-1] # reverse order + cond = self._str(Constant(exit.exitcase), block) + if i == 0: + self.putline("if %s == %s:" % (varname, cond)) + elif i < len(exits) - 1: + self.putline("elif %s == %s:" % (varname, cond)) + else: + self.putline("else: # %s == %s" % (varname, cond)) + self.indent += 1 + self.gen_link(block, exit) + self.indent -= 1 + elif len(block.inputargs) == 2: # exc_cls, exc_value + exc_cls = self._str(block.inputargs[0], block) + exc_value = self._str(block.inputargs[1], block) + self.putline("raise %s, %s" % (exc_cls, exc_value)) + else: + self.putline("return %s" % self._str(block.inputargs[0], block)) def gen_link(self, prevblock, link): _str = self._str Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Sun Nov 21 16:50:21 2004 @@ -67,38 +67,27 @@ function removes such exceptions entierely. This gets rid for example of possible IndexErrors by 'getitem', assuming they cannot happen unless there is an exception handler in the same function.""" - def is_except_link(link): - return (link.args == [Constant(last_exception)] and - len(link.target.exits) == 0 and - hasattr(link.target, 'exc_type')) def visit(link): if isinstance(link, Link) and link in link.prevblock.exits: - if (isinstance(link.exitcase, type(Exception)) and - issubclass(link.exitcase, Exception)): - # two cases: a jump directly to an exception-raising end block, - # or a jump to a block containing only a 'type' operation - # and then jumping to such an exception-raising end block. - # Argh. - block = link.target - if (is_except_link(link) or - (len(block.operations) == 1 and - block.operations[0].opname == 'type' and - len(block.exits) == 1 and - is_except_link(block.exits[0]) and - block.operations[0].result not in block.exits[0].args)): - # remove the link - lst = list(link.prevblock.exits) - lst.remove(link) - link.prevblock.exits = tuple(lst) + if (link.target is graph.exceptblock and + link.prevblock.exitswitch == Constant(last_exception) and + isinstance(link.exitcase, type(Exception)) and + issubclass(link.exitcase, Exception) and + list(link.args) == [Constant(last_exception), + Constant(last_exc_value)]): + # remove the link + lst = list(link.prevblock.exits) + lst.remove(link) + link.prevblock.exits = tuple(lst) traverse(visit, graph) def simplify_graph(graph, rpython=True): """inplace-apply all the existing optimisations to the graph.""" checkgraph(graph) eliminate_empty_blocks(graph) - join_blocks(graph) if rpython: remove_implicit_exceptions(graph) + join_blocks(graph) checkgraph(graph) def remove_direct_loops(graph): Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Sun Nov 21 16:50:21 2004 @@ -256,7 +256,7 @@ def test_constant_result(self): a = RPythonAnnotator() s = a.build_types(snippet.constant_result, []) - a.translator.simplify() + #a.translator.simplify() # must return "yadda" self.assertEquals(s, annmodel.immutablevalue("yadda")) keys = a.translator.flowgraphs.keys() Modified: pypy/trunk/src/pypy/translator/tool/flowtrace.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/flowtrace.py (original) +++ pypy/trunk/src/pypy/translator/tool/flowtrace.py Sun Nov 21 16:50:21 2004 @@ -210,8 +210,12 @@ if self.trace: print - elif hasattr(curblock, 'exc_type'): - raise curblock.exc_type + elif len(curblock.inputargs) == 2: # exc_cls, exc_value + exc_cls, exc_value = curblock.inputargs + if self.trace: + print "Raising -", + print self.pprint(exc_cls), self.pprint(exc_value) + raise exc_cls.e_value, exc_value.e_value else: result = curblock.inputargs[0] Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Sun Nov 21 16:50:21 2004 @@ -123,8 +123,10 @@ if not numblocks: shape = "box" fillcolor="green" - if hasattr(block, 'exc_type'): - lines.insert(0, 'exc_type: %s' % block.exc_type.__name__) + if len(block.inputargs) == 1: + lines[-1] += 'return %s' % tuple(block.inputargs) + elif len(block.inputargs) == 2: + lines[-1] += 'raise %s, %s' % tuple(block.inputargs) elif numblocks == 1: shape = "box" else: Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Sun Nov 21 16:50:21 2004 @@ -139,9 +139,9 @@ deps = variable_flow.setdefault(targetarg, []) deps.append(arg) else: - # return blocks implicitely use their single input variable - assert len(block.inputargs) == 1 - read_vars[block.inputargs[0]] = True + # return and except blocks implicitely use their input variable(s) + for arg in block.inputargs: + read_vars[arg] = True # an input block's inputargs should not be modified, even if some # of the function's input arguments are not actually used if block.isstartblock: @@ -337,6 +337,8 @@ def transform_graph(ann): """Apply set of transformations available.""" + # WARNING: this produces incorrect results if the graph has been + # modified by t.simplify() after is had been annotated. if ann.translator: ann.translator.checkgraphs() transform_dead_code(ann) From arigo at codespeak.net Sun Nov 21 20:13:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 21 Nov 2004 20:13:09 +0100 (MET) Subject: [pypy-svn] r7535 - in pypy/trunk/src/pypy: interpreter interpreter/test objspace/flow objspace/std tool translator translator/test Message-ID: <20041121191309.44EC85AA0E@thoth.codespeak.net> Author: arigo Date: Sun Nov 21 20:13:08 2004 New Revision: 7535 Modified: pypy/trunk/src/pypy/interpreter/eval.py pypy/trunk/src/pypy/interpreter/executioncontext.py pypy/trunk/src/pypy/interpreter/generator.py pypy/trunk/src/pypy/interpreter/miscutils.py pypy/trunk/src/pypy/interpreter/pyframe.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/interpreter/test/test_interpreter.py pypy/trunk/src/pypy/interpreter/typedef.py pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/framestate.py pypy/trunk/src/pypy/objspace/flow/objspace.py pypy/trunk/src/pypy/objspace/flow/specialcase.py pypy/trunk/src/pypy/objspace/std/fake.py pypy/trunk/src/pypy/objspace/std/typeobject.py pypy/trunk/src/pypy/tool/cache.py pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py pypy/trunk/src/pypy/translator/translator.py Log: Progress on translate_pypy -no-a. Now it's starting to complain on real bugs on our RPython code, like typos in never-tested branches or locals that could be undefined in some rare cases. - a typo in EXTENDED_ARG. In other words it never worked. Added a test (not so easy...). - a few extra NOT_RPYTHON annotations, an extra Cache() usage. - bare raise statements (to re-raise exceptions) now supported by the flow object space. Required minor changes in the methods of the pypy.interpreter.eval.Frame class. - in the flow graphs, "raise Class" doesn't try to build a Class() instance as the exception value any more; it uses None. (It doesn't try to do any normalization at all.) - always check the length of the iterable in FlowObjSpace.unpackiterable(). - NameErroring typo in untested code in fake.py. - typeobject.compute_C3_mro() shows an exemple of code that the flow object space complains about: 'candidate' might be undefined. We now it cannot be; let's use a return statement to help the flow objspace. - a few memory-saving hacks in genc.py allow it to consume a nearly constant amount of heap, instead of growing fast. - OP_LEN in genc.h. - (hopefully temporary) got tired of finding where to freeze the caches, and did it in Cache.__hash__(). Modified: pypy/trunk/src/pypy/interpreter/eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/eval.py (original) +++ pypy/trunk/src/pypy/interpreter/eval.py Sun Nov 21 20:13:08 2004 @@ -70,12 +70,7 @@ def run(self): "Run the frame." executioncontext = self.space.getexecutioncontext() - previous = executioncontext.enter(self) - try: - result = self.eval(executioncontext) - finally: - executioncontext.leave(previous) - return result + return executioncontext.run_frame(self) def eval(self, executioncontext): "Abstract method to override." Modified: pypy/trunk/src/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/executioncontext.py (original) +++ pypy/trunk/src/pypy/interpreter/executioncontext.py Sun Nov 21 20:13:08 2004 @@ -9,17 +9,18 @@ self.space = space self.framestack = Stack() - def enter(self, frame): + def run_frame(self, frame): locals = getthreadlocals() - self.framestack.push(frame) previous_ec = locals.executioncontext locals.executioncontext = self - return previous_ec - - def leave(self, previous_ec): - locals = getthreadlocals() - locals.executioncontext = previous_ec - self.framestack.pop() + self.framestack.push(frame) + try: + w_result = frame.eval(self) + finally: + self.framestack.pop() + locals = getthreadlocals() + locals.executioncontext = previous_ec + return w_result def get_w_builtins(self): if self.framestack.empty(): Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Sun Nov 21 20:13:08 2004 @@ -47,16 +47,17 @@ return self.space.wrap(self) def descr_next(self): - space = self.frame.space + space = self.space if self.running: raise OperationError(space.w_ValueError, space.wrap('generator already executing')) if self.frame.exhausted: raise OperationError(space.w_StopIteration, space.w_None) + executioncontext = space.getexecutioncontext() self.running = True try: try: - return Frame.run(self.frame) + return executioncontext.run_frame(self.frame) except OperationError, e: if e.match(self.space, self.space.w_StopIteration): raise OperationError(space.w_StopIteration, space.w_None) Modified: pypy/trunk/src/pypy/interpreter/miscutils.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/miscutils.py (original) +++ pypy/trunk/src/pypy/interpreter/miscutils.py Sun Nov 21 20:13:08 2004 @@ -40,8 +40,8 @@ class InitializedClass(type): - """A meta-class that allows a class to initialize itself (or its - subclasses) by calling __initclass__() as a class method.""" + """NOT_RPYTHON. A meta-class that allows a class to initialize itself (or + its subclasses) by calling __initclass__() as a class method.""" def __init__(self, name, bases, dict): super(InitializedClass, self).__init__(name, bases, dict) for basecls in self.__mro__: @@ -51,8 +51,9 @@ class RwDictProxy(object): - """A dict-like class standing for 'cls.__dict__', to work around - the fact that the latter is a read-only proxy for new-style classes.""" + """NOT_RPYTHON. A dict-like class standing for 'cls.__dict__', to work + around the fact that the latter is a read-only proxy for new-style + classes.""" def __init__(self, cls): self.cls = cls Modified: pypy/trunk/src/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/src/pypy/interpreter/pyframe.py Sun Nov 21 20:13:08 2004 @@ -41,9 +41,9 @@ "Interpreter main loop!" try: while True: + executioncontext.bytecode_trace(self) + last_instr = self.next_instr try: - executioncontext.bytecode_trace(self) - last_instr = self.next_instr try: # fetch and dispatch the next opcode # dispatch() is abstract, see pyopcode. Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Sun Nov 21 20:13:08 2004 @@ -754,7 +754,7 @@ def EXTENDED_ARG(f, oparg): opcode = f.nextop() oparg = oparg<<16 | f.nextarg() - fn = self.dispatch_table[opcode] + fn = f.dispatch_table[opcode] if not fn.has_arg: raise pyframe.BytecodeCorruption fn(f, oparg) Modified: pypy/trunk/src/pypy/interpreter/test/test_interpreter.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/test/test_interpreter.py (original) +++ pypy/trunk/src/pypy/interpreter/test/test_interpreter.py Sun Nov 21 20:13:08 2004 @@ -160,6 +160,26 @@ ''') self.codetest(code, 'f', []) + def test_extended_arg(self): + longexpr = 'x = x or ' + '-x' * 2500 + code = ''' +def f(x): + %s + %s + %s + %s + %s + %s + %s + %s + %s + %s + while x: + x -= 1 # EXTENDED_ARG is for the JUMP_ABSOLUTE at the end of the loop + return x +''' % ((longexpr,)*10) + self.assertEquals(self.codetest(code, 'f', [3]), 0) + class AppTestInterpreter(testit.AppTestCase): def test_trivial(self): Modified: pypy/trunk/src/pypy/interpreter/typedef.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/typedef.py (original) +++ pypy/trunk/src/pypy/interpreter/typedef.py Sun Nov 21 20:13:08 2004 @@ -5,60 +5,63 @@ from pypy.interpreter.gateway import interp2app from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.error import OperationError +from pypy.tool.cache import Cache +import new class TypeDef: def __init__(self, __name, __base=None, **rawdict): + "NOT_RPYTHON: initialization-time only" self.name = __name self.base = __base self.hasdict = '__dict__' in rawdict or (__base and __base.hasdict) self.rawdict = rawdict -unique_interplevel_subclass_cache = {} +unique_interplevel_subclass_cache = Cache() def get_unique_interplevel_subclass(cls): - try: - return unique_interplevel_subclass_cache[cls] - except KeyError: - typedef = cls.typedef - name = 'User' + cls.__name__ - body = {} - - class User_InsertNameHere(object): - - def getclass(self, space): - return self.w__class__ - - def setclass(self, w_subtype): - # XXX sanity checks here + return unique_interplevel_subclass_cache.getorbuild(cls, _buildusercls, None) + +def _buildusercls(cls, ignored): + "NOT_RPYTHON: initialization-time only" + typedef = cls.typedef + name = 'User' + cls.__name__ + body = {} + + class User_InsertNameHere(object): + + def getclass(self, space): + return self.w__class__ + + def setclass(self, w_subtype): + # XXX sanity checks here + self.w__class__ = w_subtype + + if typedef.hasdict: + def user_setup(self, space, w_subtype): + self.space = space self.w__class__ = w_subtype - - if typedef.hasdict: - def user_setup(self, space, w_subtype): - self.space = space - self.w__class__ = w_subtype - - else: - def getdict(self): - return self.w__dict__ - - def setdict(self, w_dict): - space = self.space - if not space.is_true(space.isinstance(w_dict, space.w_dict)): - raise OperationError(space.w_TypeError, - space.wrap("setting dictionary to a non-dict")) - self.w__dict__ = w_dict - - def user_setup(self, space, w_subtype): - self.space = space - self.w__class__ = w_subtype - self.w__dict__ = space.newdict([]) - - body = dict([(key, value) - for key, value in User_InsertNameHere.__dict__.items() - if not key.startswith('_')]) - subcls = type(name, (cls,), body) - unique_interplevel_subclass_cache[cls] = subcls - return subcls + + else: + def getdict(self): + return self.w__dict__ + + def setdict(self, w_dict): + space = self.space + if not space.is_true(space.isinstance(w_dict, space.w_dict)): + raise OperationError(space.w_TypeError, + space.wrap("setting dictionary to a non-dict")) + self.w__dict__ = w_dict + + def user_setup(self, space, w_subtype): + self.space = space + self.w__class__ = w_subtype + self.w__dict__ = space.newdict([]) + + body = dict([(key, value) + for key, value in User_InsertNameHere.__dict__.items() + if not key.startswith('_')]) + subcls = type(name, (cls,), body) + return subcls def instantiate(cls): "Create an empty instance of 'cls'." @@ -69,6 +72,7 @@ class GetSetProperty(Wrappable): def __init__(self, fget, fset=None, fdel=None, doc=None): + "NOT_RPYTHON: initialization-time only" fget = getattr(fget, 'im_func', fget) fset = getattr(fset, 'im_func', fset) fdel = getattr(fdel, 'im_func', fdel) @@ -106,12 +110,14 @@ ) def attrproperty(name): + "NOT_RPYTHON: initialization-time only" def fget(space, w_obj): obj = space.unwrap_builtin(w_obj) return space.wrap(getattr(obj, name)) return GetSetProperty(fget) def attrproperty_w(name): + "NOT_RPYTHON: initialization-time only" def fget(space, w_obj): obj = space.unwrap_builtin(w_obj) w_value = getattr(obj, name) Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Sun Nov 21 20:13:08 2004 @@ -205,7 +205,7 @@ except ExitFrame: continue # restarting a dead SpamBlock try: - w_result = frame.eval(self) + w_result = self.run_frame(frame) except OperationError, e: link = Link([e.w_type, e.w_value], self.graph.exceptblock) self.crnt_block.closeblock(link) Modified: pypy/trunk/src/pypy/objspace/flow/framestate.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/framestate.py (original) +++ pypy/trunk/src/pypy/objspace/flow/framestate.py Sun Nov 21 20:13:08 2004 @@ -1,4 +1,5 @@ from pypy.interpreter.pyframe import PyFrame, ControlFlowException +from pypy.interpreter.error import OperationError from pypy.objspace.flow.model import * class FrameState: @@ -7,11 +8,16 @@ def __init__(self, state): if isinstance(state, PyFrame): data = state.getfastscope() + state.valuestack.items + if state.last_exception is None: + data.append(Constant(None)) + data.append(Constant(None)) + else: + data.append(state.last_exception.w_type) + data.append(state.last_exception.w_value) recursively_flatten(state.space, data) self.mergeable = data self.nonmergeable = ( state.blockstack.items[:], - state.last_exception, state.next_instr, state.w_locals, ) @@ -30,10 +36,14 @@ data = self.mergeable[:] recursively_unflatten(frame.space, data) frame.setfastscope(data[:fastlocals]) - frame.valuestack.items[:] = data[fastlocals:] + frame.valuestack.items[:] = data[fastlocals:-2] + if data[-2] == Constant(None): + assert data[-1] == Constant(None) + frame.last_exception = None + else: + frame.last_exception = OperationError(data[-2], data[-1]) ( frame.blockstack.items[:], - frame.last_exception, frame.next_instr, frame.w_locals, ) = self.nonmergeable Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Sun Nov 21 20:13:08 2004 @@ -171,7 +171,11 @@ items.append(w_item) i += 1 return items - elif expected_length is not None: + elif expected_length is not None: + w_len = self.len(w_iterable) + w_correct = self.eq(w_len, self.wrap(expected_length)) + if not self.is_true(w_correct): + raise OperationError(self.w_ValueError, self.w_None) return [self.do_operation('getitem', w_iterable, self.wrap(i)) for i in range(expected_length)] # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Sun Nov 21 20:13:08 2004 @@ -21,7 +21,7 @@ * raise Class - with a constant Class, it is easy to recognize. - The associated value is Class(). + But we don't normalize: the associated value is None. * raise Class(...) - when the class is instantiated in-place, we can figure that out @@ -42,8 +42,7 @@ etype = getconstclass(space, w_arg1) if etype is not None: # raise Class - w_arg2 = space.do_operation('simple_call', w_arg1) - return (w_arg1, w_arg2) + return (w_arg1, space.w_None) # raise Class(..)? We need a hack to figure out of which class it is. # Normally, Instance should have been created by the previous operation # which should be a simple_call(, ...). Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Sun Nov 21 20:13:08 2004 @@ -16,10 +16,9 @@ # real-to-wrapped exceptions def wrap_exception(space): - "NOT_RPYTHON" # XXX this needs to end up in the translated code somehow! exc, value, tb = sys.exc_info() if exc is OperationError: - raise exc, value, tb # just re-raise it + raise exc, value #, tb # just re-raise it (tb ignored: not RPython) name = exc.__name__ if hasattr(space, 'w_' + name): w_exc = getattr(space, 'w_' + name) @@ -31,7 +30,7 @@ else: w_exc = space.wrap(exc) w_value = space.wrap(value) - raise OperationError, OperationError(w_exc, w_value), tb + raise OperationError, OperationError(w_exc, w_value) #, tb not RPython def fake_type(cpy_type): assert type(cpy_type) is type @@ -96,7 +95,7 @@ unwrappedargs = self.space.unwrap(w_args) unwrappedkwds = self.space.unwrap(w_kwds) except UnwrapError, e: - raise UnwrapError('calling %s: %s' % (cpy_type, e)) + raise UnwrapError('calling %s: %s' % (fn, e)) try: result = apply(fn, unwrappedargs, unwrappedkwds) except: Modified: pypy/trunk/src/pypy/objspace/std/typeobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/typeobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/typeobject.py Sun Nov 21 20:13:08 2004 @@ -174,7 +174,7 @@ if mro_blockinglist(candidate, orderlists) is None: break # good candidate else: - mro_error(orderlists) # no candidate found + return mro_error(orderlists) # no candidate found assert candidate not in order order.append(candidate) for i in range(len(orderlists)-1, -1, -1): Modified: pypy/trunk/src/pypy/tool/cache.py ============================================================================== --- pypy/trunk/src/pypy/tool/cache.py (original) +++ pypy/trunk/src/pypy/tool/cache.py Sun Nov 21 20:13:08 2004 @@ -9,7 +9,8 @@ def __hash__(self): if not self.frozen: - raise TypeError, "cannot get hash of un-frozen cache" + #raise TypeError, "cannot get hash of un-frozen cache" + self.freeze() return id(self) def clear(self): Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Sun Nov 21 20:13:08 2004 @@ -22,11 +22,11 @@ #endif #define op_bool(r,err,what) { \ - int retval = what; \ - if (retval < 0) { \ + int _retval = what; \ + if (_retval < 0) { \ FAIL(err) \ } \ - r = PyBool_FromLong(retval); \ + r = PyBool_FromLong(_retval); \ } #define op_richcmp(x,y,r,err,dir) \ @@ -42,6 +42,13 @@ #define OP_IS_TRUE(x,r,err) op_bool(r,err,PyObject_IsTrue(x)) +#define OP_LEN(x,r,err) { \ + int _retval = PyObject_Size(x); \ + if (_retval < 0) { \ + FAIL(err) \ + } \ + r = PyInt_FromLong(_retval); \ + } #define OP_NEG(x,r,err) if (!(r=PyNumber_Negative(x))) FAIL(err) #define OP_POS(x,r,err) if (!(r=PyNumber_Positive(x))) FAIL(err) #define OP_INVERT(x,r,err) if (!(r=PyNumber_Invert(x))) FAIL(err) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sun Nov 21 20:13:08 2004 @@ -39,8 +39,10 @@ class GenC: MODNAMES = {} - def __init__(self, f, translator, modname=None): + def __init__(self, f, translator, modname=None, f2=None, f2name=None): self.f = f + self.f2 = f2 + self.f2name = f2name self.translator = translator self.modname = (modname or uniquemodulename(translator.functions[0].__name__)) @@ -69,7 +71,8 @@ else: stackentry = obj self.debugstack = (self.debugstack, stackentry) - if type(obj).__module__ != '__builtin__': + if (type(obj).__module__ != '__builtin__' and + not isinstance(obj, type)): # skip user-defined metaclasses # assume it's a user defined thingy name = self.nameof_instance(obj) else: @@ -151,10 +154,10 @@ return name def nameof_str(self, value): - chrs = [c for c in value if ('a' <= c <='z' or - 'A' <= c <='Z' or - '0' <= c <='9' or - '_' == c )] + chrs = [c for c in value[:32] if ('a' <= c <='z' or + 'A' <= c <='Z' or + '0' <= c <='9' or + '_' == c )] name = self.uniquename('gstr_' + ''.join(chrs)) if [c for c in value if not (' '<=c<='~')]: # non-printable string @@ -179,7 +182,8 @@ self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) return name - def nameof_function(self, func): + def nameof_function(self, func, progress=['-\x08', '\\\x08', + '|\x08', '/\x08']): printable_name = '(%s:%d) %s' % ( func.func_globals.get('__name__', '?'), func.func_code.co_firstlineno, @@ -193,7 +197,9 @@ func.func_doc.lstrip().startswith('NOT_RPYTHON')): print "skipped", printable_name return self.skipped_function(func) - #print "nameof", printable_name + p = progress.pop(0) + sys.stderr.write(p) + progress.append(p) name = self.uniquename('gfunc_' + func.__name__) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) @@ -313,7 +319,7 @@ for key, value in content: if key.startswith('__'): if key in ['__module__', '__doc__', '__dict__', - '__weakref__', '__repr__']: + '__weakref__', '__repr__', '__metaclass__']: continue # XXX some __NAMES__ are important... nicer solution sought #raise Exception, "unexpected name %r in class %s"%(key, cls) @@ -350,6 +356,7 @@ dict: '&PyDict_Type', str: '&PyString_Type', float: '&PyFloat_Type', + type(Exception()): '&PyInstance_Type', type: '&PyType_Type', complex:'&PyComplex_Type', unicode:'&PyUnicode_Type', @@ -458,7 +465,7 @@ # function implementations while self.pendingfunctions: - func = self.pendingfunctions.pop(0) + func = self.pendingfunctions.pop() self.gen_cfunction(func) # collect more of the latercode after each function while self.latercode: @@ -471,10 +478,10 @@ # footer print >> f, self.C_INIT_HEADER % info + if self.f2name is not None: + print >> f, '#include "%s"' % self.f2name for codeline in self.initcode: print >> f, '\t' + codeline - for name in self.globalobjects: - print >> f, '\t' + 'REGISTER_GLOBAL(%s)' % (name,) print >> f, self.C_INIT_FOOTER % info def gen_global_declarations(self): @@ -486,6 +493,14 @@ print >> f, line print >> f del g[:] + g = self.globalobjects + for name in g: + self.initcode.append('REGISTER_GLOBAL(%s)' % (name,)) + del g[:] + if self.f2 is not None: + for line in self.initcode: + print >> self.f2, line + del self.initcode[:] def gen_cfunction(self, func): ## print 'gen_cfunction (%s:%d) %s' % ( @@ -584,6 +599,11 @@ name, func.__name__, f_name) print >> f + if not self.translator.frozen: + # this is only to keep the RAM consumption under control + del self.translator.flowgraphs[func] + Variable.instances.clear() + def cfunction_body(self, func): graph = self.translator.getflowgraph(func) remove_direct_loops(graph) @@ -653,7 +673,7 @@ # exceptional return block exc_cls = expr(block.inputargs[0]) exc_value = expr(block.inputargs[1]) - yield 'PyErr_SetObject(%s, %s);' % (exc_cls, retval) + yield 'PyErr_Restore(%s, %s, NULL);' % (exc_cls, exc_value) yield 'FUNCTION_RETURN(NULL)' else: # regular return block Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Sun Nov 21 20:13:08 2004 @@ -234,6 +234,19 @@ x = 8 return x +def finally2(o, k): + try: + o[k] += 1 + finally: + o[-1] = 'done' + +def bare_raise(o, ignore): + try: + return o[5] + except: + if not ignore: + raise + def factorial(n=int): if n <= 1: return 1 Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Sun Nov 21 20:13:08 2004 @@ -140,6 +140,29 @@ self.assertEquals(call_default_and_star_args(42), (111+42+3+0, -1000-2000-3000+2)) + def test_finallys(self): + finallys = self.build_cfunc(snippet.finallys) + self.assertEquals(finallys(['hello']), 8) + self.assertEquals(finallys('X'), 8) + self.assertEquals(finallys([]), 6) + self.assertEquals(finallys('XY'), 6) + + def test_finally2(self): + finally2 = self.build_cfunc(snippet.finally2) + lst = range(10) + finally2(lst, 5) + self.assertEquals(lst, [0,1,2,3,4, 6, 6,7,8, 'done']) + dic = {} + self.assertRaises(KeyError, finally2, dic, "won't find this key") + self.assertEquals(dic, {-1: 'done'}) + + def test_bare_raise(self): + bare_raise = self.build_cfunc(snippet.bare_raise) + self.assertEquals(bare_raise(range(0, 100, 10), False), 50) + self.assertEquals(bare_raise(range(0, 100, 10), True), 50) + self.assertRaises(IndexError, bare_raise, range(0, 30, 10), False) + self.assertEquals(bare_raise(range(0, 30, 10), True), None) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sun Nov 21 20:13:08 2004 @@ -212,9 +212,7 @@ return g.globaldeclarations() def compile(self): - """Returns compiled function. - - Currently function is only compiled using Pyrex. + """Returns compiled function, compiled using Pyrex. """ from pypy.tool.udir import udir name = self.entrypoint.func_name @@ -229,7 +227,9 @@ name = uniquemodulename(self.entrypoint.func_name) cfile = udir.join('%s.c' % name) f = cfile.open('w') - GenC(f, self, name) + f2 = udir.join('%s-init.h' % name).open('w') + GenC(f, self, name, f2=f2, f2name='%s-init.h' % name) + f2.close() f.close() if not really_compile: return cfile From arigo at codespeak.net Mon Nov 22 10:03:37 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 10:03:37 +0100 (MET) Subject: [pypy-svn] r7545 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/flow/test Message-ID: <20041122090337.919BD5ACD6@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 10:03:36 2004 New Revision: 7545 Modified: pypy/trunk/src/pypy/interpreter/eval.py pypy/trunk/src/pypy/interpreter/executioncontext.py pypy/trunk/src/pypy/interpreter/generator.py pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Log: Reverted the execution contexts to the previous API (enter/leave) to avoid breaking the trace object space. Modified: pypy/trunk/src/pypy/interpreter/eval.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/eval.py (original) +++ pypy/trunk/src/pypy/interpreter/eval.py Mon Nov 22 10:03:36 2004 @@ -67,10 +67,19 @@ numlocals = len(code.getvarnames()) self.fastlocals_w = [UNDEFINED]*numlocals # flat list of wrapped locals - def run(self): - "Run the frame." + def resume(self): + "Resume the execution of the frame from its current state." executioncontext = self.space.getexecutioncontext() - return executioncontext.run_frame(self) + previous = executioncontext.enter(self) + try: + result = self.eval(executioncontext) + finally: + executioncontext.leave(previous) + return result + + # running a frame is usually the same as resuming it from its + # initial state, but not for generator frames + run = resume def eval(self, executioncontext): "Abstract method to override." Modified: pypy/trunk/src/pypy/interpreter/executioncontext.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/executioncontext.py (original) +++ pypy/trunk/src/pypy/interpreter/executioncontext.py Mon Nov 22 10:03:36 2004 @@ -9,18 +9,17 @@ self.space = space self.framestack = Stack() - def run_frame(self, frame): + def enter(self, frame): locals = getthreadlocals() previous_ec = locals.executioncontext locals.executioncontext = self self.framestack.push(frame) - try: - w_result = frame.eval(self) - finally: - self.framestack.pop() - locals = getthreadlocals() - locals.executioncontext = previous_ec - return w_result + return previous_ec + + def leave(self, previous_ec): + self.framestack.pop() + locals = getthreadlocals() + locals.executioncontext = previous_ec def get_w_builtins(self): if self.framestack.empty(): Modified: pypy/trunk/src/pypy/interpreter/generator.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/generator.py (original) +++ pypy/trunk/src/pypy/interpreter/generator.py Mon Nov 22 10:03:36 2004 @@ -53,11 +53,10 @@ space.wrap('generator already executing')) if self.frame.exhausted: raise OperationError(space.w_StopIteration, space.w_None) - executioncontext = space.getexecutioncontext() self.running = True try: try: - return executioncontext.run_frame(self.frame) + return self.frame.resume() except OperationError, e: if e.match(self.space, self.space.w_StopIteration): raise OperationError(space.w_StopIteration, space.w_None) Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/flowcontext.py (original) +++ pypy/trunk/src/pypy/objspace/flow/flowcontext.py Mon Nov 22 10:03:36 2004 @@ -205,7 +205,7 @@ except ExitFrame: continue # restarting a dead SpamBlock try: - w_result = self.run_frame(frame) + w_result = frame.resume() except OperationError, e: link = Link([e.w_type, e.w_value], self.graph.exceptblock) self.crnt_block.closeblock(link) Modified: pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/test/test_objspace.py Mon Nov 22 10:03:36 2004 @@ -231,12 +231,10 @@ def test_raise1(self): x = self.codetest(self.raise1) self.show(x) - assert len(x.startblock.operations) == 1 - assert x.startblock.operations[0].opname == 'simple_call' - assert list(x.startblock.operations[0].args) == [Constant(IndexError)] + assert len(x.startblock.operations) == 0 assert x.startblock.exits[0].args == [ Constant(IndexError), - x.startblock.operations[0].result] + Constant(None)] # no normalization assert x.startblock.exits[0].target is x.exceptblock #__________________________________________________________ From arigo at codespeak.net Mon Nov 22 10:56:42 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 10:56:42 +0100 (MET) Subject: [pypy-svn] r7546 - in pypy/trunk/src/pypy: interpreter objspace/flow objspace/std Message-ID: <20041122095642.6371C5AF30@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 10:56:41 2004 New Revision: 7546 Modified: pypy/trunk/src/pypy/interpreter/pyframe.py pypy/trunk/src/pypy/interpreter/pyopcode.py pypy/trunk/src/pypy/objspace/flow/specialcase.py pypy/trunk/src/pypy/objspace/std/fake.py Log: Re-enabled the 3rd (tb) argument of raise statements in RPython code. (the flow objspace ignores it, but no longer crashes because of it.) Modified: pypy/trunk/src/pypy/interpreter/pyframe.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyframe.py (original) +++ pypy/trunk/src/pypy/interpreter/pyframe.py Mon Nov 22 10:56:41 2004 @@ -149,8 +149,9 @@ operationerr = unroller.args[0] w_type = operationerr.w_type w_value = operationerr.w_value - w_normalized = normalize_exception(frame.space, w_type, w_value) - w_type, w_value = frame.space.unpacktuple(w_normalized, 2) + w_normalized = normalize_exception(frame.space, w_type, w_value, + frame.space.w_None) + w_type, w_value, w_tb = frame.space.unpacktuple(w_normalized, 3) # save the normalized exception back into the OperationError # -- in particular it makes sure that sys.exc_info() etc see # normalized exception. @@ -166,7 +167,7 @@ return True # stop unrolling return False -def app_normalize_exception(etype, value): +def app_normalize_exception(etype, value, tb): """Normalize an (exc_type, exc_value) pair: exc_value will be an exception instance and exc_type its class. """ @@ -202,7 +203,7 @@ if not hasattr(value, '__dict__') and not hasattr(value, '__slots__'): raise TypeError("raising built-in objects can be ambiguous, " "use 'raise type, value' instead") - return etype, value + return etype, value, tb normalize_exception = gateway.app2interp(app_normalize_exception) Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Mon Nov 22 10:56:41 2004 @@ -316,8 +316,9 @@ if nbargs >= 3: w_traceback = f.valuestack.pop() if nbargs >= 2: w_value = f.valuestack.pop() if 1: w_type = f.valuestack.pop() - w_resulttuple = pyframe.normalize_exception(f.space, w_type, w_value) - w_type, w_value = f.space.unpacktuple(w_resulttuple, 2) + w_resulttuple = pyframe.normalize_exception(f.space, w_type, w_value, + w_traceback) + w_type, w_value, w_traceback = f.space.unpacktuple(w_resulttuple, 3) tb = f.space.unwrap(w_traceback) if tb is not None: if not isinstance(tb,pytraceback.PyTraceback): Modified: pypy/trunk/src/pypy/objspace/flow/specialcase.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/specialcase.py (original) +++ pypy/trunk/src/pypy/objspace/flow/specialcase.py Mon Nov 22 10:56:41 2004 @@ -34,15 +34,24 @@ - assumes that Arg is the value you want for the exception, and that Class is exactly the exception class. No check or normalization. """ - assert len(args.args_w) == 2 and args.kwds_w == {} - w_arg1, w_arg2 = args.args_w + assert len(args.args_w) == 3 and args.kwds_w == {} + w_arg1, w_arg2, w_tb = args.args_w + + # w_arg3 (the traceback) is ignored and replaced with None + # if it is a Variable, because pyopcode.py tries to unwrap it. + # It means that we ignore the 'tb' argument of 'raise' in most cases. + if not isinstance(w_tb, Constant): + w_tb = space.w_None + if w_arg2 != space.w_None: # raise Class, Arg: no normalization - return (w_arg1, w_arg2) + return (w_arg1, w_arg2, w_tb) + etype = getconstclass(space, w_arg1) if etype is not None: # raise Class - return (w_arg1, space.w_None) + return (w_arg1, space.w_None, w_tb) + # raise Class(..)? We need a hack to figure out of which class it is. # Normally, Instance should have been created by the previous operation # which should be a simple_call(, ...). @@ -52,10 +61,11 @@ if (spaceop.opname == 'simple_call' and spaceop.result is w_arg1): w_type = spaceop.args[0] - return (w_type, w_arg1) + return (w_type, w_arg1, w_tb) + # raise Instance. Fall-back. w_type = space.do_operation('type', w_arg1) - return (w_type, w_arg1) + return (w_type, w_arg1, w_tb) # this function returns a real tuple that can be handled # by FlowObjSpace.unpacktuple() Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Mon Nov 22 10:56:41 2004 @@ -18,7 +18,7 @@ def wrap_exception(space): exc, value, tb = sys.exc_info() if exc is OperationError: - raise exc, value #, tb # just re-raise it (tb ignored: not RPython) + raise exc, value, tb # just re-raise it name = exc.__name__ if hasattr(space, 'w_' + name): w_exc = getattr(space, 'w_' + name) @@ -30,7 +30,7 @@ else: w_exc = space.wrap(exc) w_value = space.wrap(value) - raise OperationError, OperationError(w_exc, w_value) #, tb not RPython + raise OperationError, OperationError(w_exc, w_value), tb def fake_type(cpy_type): assert type(cpy_type) is type From arigo at codespeak.net Mon Nov 22 10:59:00 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 10:59:00 +0100 (MET) Subject: [pypy-svn] r7547 - pypy/trunk/src/pypy/translator Message-ID: <20041122095900.DC71B5AF31@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 10:59:00 2004 New Revision: 7547 Modified: pypy/trunk/src/pypy/translator/genc.h Log: the 'pow' space operation takes all three arguments Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 22 10:59:00 2004 @@ -60,7 +60,7 @@ #define OP_FLOORDIV(x,y,r,err) if (!(r=PyNumber_FloorDivide(x,y)))FAIL(err) #define OP_DIV(x,y,r,err) if (!(r=PyNumber_Divide(x,y))) FAIL(err) #define OP_MOD(x,y,r,err) if (!(r=PyNumber_Remainder(x,y))) FAIL(err) -#define OP_POW(x,y,r,err) if (!(r=PyNumber_Power(x,y,Py_None)))FAIL(err) +#define OP_POW(x,y,z,r,err) if (!(r=PyNumber_Power(x,y,z))) FAIL(err) #define OP_LSHIFT(x,y,r,err) if (!(r=PyNumber_Lshift(x,y))) FAIL(err) #define OP_RSHIFT(x,y,r,err) if (!(r=PyNumber_Rshift(x,y))) FAIL(err) #define OP_AND_(x,y,r,err) if (!(r=PyNumber_And(x,y))) FAIL(err) From mgedmin at codespeak.net Mon Nov 22 11:35:02 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 11:35:02 +0100 (MET) Subject: [pypy-svn] r7548 - pypy/trunk/src/goal Message-ID: <20041122103502.A487C5AF32@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 11:35:02 2004 New Revision: 7548 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Be more explicit about the block in about() -- show the type of the block, as well as the class name if the function is a method. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 22 11:35:02 2004 @@ -132,15 +132,18 @@ if isinstance(x, Block): for func, graph in t.flowgraphs.items(): if x in flatten(graph): - print x - print 'is a block in the graph of' - print func + funcname = func.func_name + cls = getattr(func, 'class_', None) + if cls: + funcname = '%s.%s' % (cls.__name__, funcname) + print '%s is a %s in the graph of %s' % (x, + x.__class__.__name__, funcname) print 'at %s:%d' % (func.func_globals.get('__name__', '?'), func.func_code.co_firstlineno) break else: - print x - print 'is a block at some unknown location' + print '%s is a %s at some unknown location' % (x, + x.__class__.__name__) print 'containing the following operations:' for op in x.operations: print op From hpk at codespeak.net Mon Nov 22 11:45:48 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 22 Nov 2004 11:45:48 +0100 (MET) Subject: [pypy-svn] r7549 - pypy/trunk/src/pypy/translator/test Message-ID: <20041122104548.B48CC5AF33@thoth.codespeak.net> Author: hpk Date: Mon Nov 22 11:45:48 2004 New Revision: 7549 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: added a (still disabled) test that checks for an upcoming feature (idea): if a SomeInstance is unified with a SomePBC then the SomeInstance should be retained and should put information about the SomePBC in the SomeInstance's classdef. Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Mon Nov 22 11:45:48 2004 @@ -600,3 +600,17 @@ def func_arg_unpack(): a,b = 3, "hello" return a + +class APBC: + def f(self): + pass + code = f.func_code + +apbc = APBC() + +def preserve_pbc_attr_on_instance(cond): + if cond: + x = APBC() + else: + x = apbc + return x.code Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Mon Nov 22 11:45:48 2004 @@ -331,6 +331,15 @@ self.assert_(isinstance(s, annmodel.SomeInteger)) self.assertEquals(s.const, 3) + def test_pbc_attr_preserved_on_instance(self): + a = RPythonAnnotator() + s = a.build_types(snippet.preserve_pbc_attr_on_instance, [bool]) + #a.simplify() + #a.translator.view() + #self.assert_(isinstance(s, annmodel.SomeInstance)) + #self.assertEquals(s.const, 3) + + def g(n): return [0,1,2,n] From mgedmin at codespeak.net Mon Nov 22 11:46:01 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 11:46:01 +0100 (MET) Subject: [pypy-svn] r7550 - in pypy/trunk/src/pypy/appspace: . test Message-ID: <20041122104601.37C445AF34@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 11:46:00 2004 New Revision: 7550 Modified: pypy/trunk/src/pypy/appspace/sio.py pypy/trunk/src/pypy/appspace/test/test_file.py Log: Fixed a failing test. Modified: pypy/trunk/src/pypy/appspace/sio.py ============================================================================== --- pypy/trunk/src/pypy/appspace/sio.py (original) +++ pypy/trunk/src/pypy/appspace/sio.py Mon Nov 22 11:46:00 2004 @@ -566,13 +566,13 @@ except KeyError: raise ValueError, "mode should be 'r', 'r+', 'w', 'w+' or 'a+'" - if hasattr(os, "O_BINARY"): - flag |= os.O_BINARY + O_BINARY = getattr(os, "O_BINARY", 0) + flag |= O_BINARY try: self.fd = os.open(filename, flag) except OSError: # Opening in mode 'a' or 'a+' and file already exists - flag = flag & (os.O_RDWR | os.O_BINARY) + flag = flag & (os.O_RDWR | O_BINARY) self.fd = os.open(filename, flag) if mode[0] == 'a': os.lseek(self.fd, 0, 2) # Move to end of file Modified: pypy/trunk/src/pypy/appspace/test/test_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_file.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_file.py Mon Nov 22 11:46:00 2004 @@ -1,10 +1,12 @@ +import os import autopath from pypy.appspace import _file import unittest class FileTestCase(unittest.TestCase): def setUp(self): - self.fd = _file.file_('test_file.py', 'r') + filename = os.path.join(autopath.this_dir, 'test_file.py') + self.fd = _file.file_(filename, 'r') def tearDown(self): self.fd.close() From mgedmin at codespeak.net Mon Nov 22 13:06:07 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 13:06:07 +0100 (MET) Subject: [pypy-svn] r7552 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041122120607.615D25AF36@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 13:06:06 2004 New Revision: 7552 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Show the label of the highlighted edge in the status bar. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Mon Nov 22 13:06:06 2004 @@ -410,6 +410,8 @@ if edge: info = '%s -> %s' % (shortlabel(edge.tail.label), shortlabel(edge.head.label)) + if edge.label: + info += '\n' + shortlabel(edge.label) self.setstatusbar(info) self.sethighlight(obj=edge) return From mgedmin at codespeak.net Mon Nov 22 13:07:33 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 13:07:33 +0100 (MET) Subject: [pypy-svn] r7553 - pypy/trunk/src/pypy/translator Message-ID: <20041122120733.B52A75AF39@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 13:07:33 2004 New Revision: 7553 Modified: pypy/trunk/src/pypy/translator/transform.py Log: Corrected the logic of transform_dead_op_vars when there are unannotated and partially annotated blocks. I should really write a test... Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Mon Nov 22 13:07:33 2004 @@ -118,7 +118,7 @@ variable_flow = {} # map {Var: list-of-Vars-it-depends-on} # compute variable_flow and an initial read_vars - for block in fully_annotated_blocks(self): + for block in self.annotated: # figure out which variables are ever read for op in block.operations: if op.opname not in CanRemove: # mark the inputs as really needed @@ -132,12 +132,17 @@ if isinstance(block.exitswitch, Variable): read_vars[block.exitswitch] = True - + if block.exits: for link in block.exits: - for arg, targetarg in zip(link.args, link.target.inputargs): - deps = variable_flow.setdefault(targetarg, []) - deps.append(arg) + if link.target not in self.annotated: + for arg, targetarg in zip(link.args, link.target.inputargs): + read_vars[arg] = True + read_vars[targetarg] = True + else: + for arg, targetarg in zip(link.args, link.target.inputargs): + deps = variable_flow.setdefault(targetarg, []) + deps.append(arg) else: # return and except blocks implicitely use their input variable(s) for arg in block.inputargs: @@ -157,8 +162,8 @@ read_vars[prevvar] = True pending.append(prevvar) - for block in fully_annotated_blocks(self): - + for block in self.annotated: + # look for removable operations whose result is never used for i in range(len(block.operations)-1, -1, -1): op = block.operations[i] @@ -181,16 +186,12 @@ # link.target.inputargs. for link in block.exits: assert len(link.args) == len(link.target.inputargs) - if not self.annotated.get(link.target, False): - # Can't remove -- link.target is not annotated, therefore - # link.target.inputargs will never be touched - continue for i in range(len(link.args)-1, -1, -1): if link.target.inputargs[i] not in read_vars: del link.args[i] # the above assert would fail here - for block in fully_annotated_blocks(self): + for block in self.annotated: # look for input variables never used # The corresponding link.args have already been all removed above for i in range(len(block.inputargs)-1, -1, -1): From arigo at codespeak.net Mon Nov 22 13:27:34 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 13:27:34 +0100 (MET) Subject: [pypy-svn] r7554 - in pypy/trunk/src/pypy/translator: . tool Message-ID: <20041122122734.4DAE25A1D3@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 13:27:33 2004 New Revision: 7554 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: genc: - OP_DELITEM() - OP_CALL() - OP_NEWDICT() - fixed string escaping And when build_module_form_c fails, it dumps the errors/warnings text to a .error file in addition of printing it to the console. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 22 13:27:33 2004 @@ -97,6 +97,8 @@ #define OP_GETITEM(x,y,r,err) if (!(r=PyObject_GetItem1(x,y))) FAIL(err) #define OP_SETITEM(x,y,z,r,err) if ((PyObject_SetItem1(x,y,z))<0) FAIL(err) \ r=Py_None; Py_INCREF(r); +#define OP_DELITEM(x,y,r,err) if ((PyObject_DelItem(x,y))<0) FAIL(err) \ + r=Py_None; Py_INCREF(r); #define OP_CONTAINS(x,y,r,err) op_bool(r,err,(PySequence_Contains(x,y))) #define OP_GETATTR(x,y,r,err) if (!(r=PyObject_GetAttr(x,y))) FAIL(err) @@ -115,6 +117,7 @@ #define OP_SIMPLE_CALL(args,r,err) if (!(r=PyObject_CallFunctionObjArgs args)) \ FAIL(err) +#define OP_CALL(x,y,z,r,err) if (!(r=PyObject_Call(x,y,z))) FAIL(err) /* Needs to act like getattr(x, '__class__', type(x)) */ #define OP_TYPE(x,r,err) { \ @@ -262,6 +265,8 @@ #define OP_NEWLIST0(r,err) if (!(r=PyList_New(0))) FAIL(err) #define OP_NEWLIST(args,r,err) if (!(r=PyList_Pack args)) FAIL(err) +#define OP_NEWDICT0(r,err) if (!(r=PyDict_New())) FAIL(err) +#define OP_NEWDICT(args,r,err) if (!(r=PyDict_Pack args)) FAIL(err) #define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) FAIL(err) #if defined(USE_CALL_TRACE) @@ -555,6 +560,30 @@ return result; } +static PyObject* PyDict_Pack(int n, ...) +{ + int i; + PyObject *key, *val; + PyObject *result; + va_list vargs; + + va_start(vargs, n); + result = PyDict_New(); + if (result == NULL) { + return NULL; + } + for (i = 0; i < n; i++) { + key = va_arg(vargs, PyObject *); + val = va_arg(vargs, PyObject *); + if (PyDict_SetItem(result, key, val) < 0) { + Py_DECREF(result); + return NULL; + } + } + va_end(vargs); + return result; +} + #if PY_VERSION_HEX < 0x02040000 /* 2.4 */ static PyObject* PyTuple_Pack(int n, ...) { Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 13:27:33 2004 @@ -159,7 +159,7 @@ '0' <= c <='9' or '_' == c )] name = self.uniquename('gstr_' + ''.join(chrs)) - if [c for c in value if not (' '<=c<='~')]: + if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\')]: # non-printable string s = 'chr_%s' % name self.globaldecl.append('static char %s[] = { %s };' % ( @@ -767,6 +767,14 @@ args.insert(0, '%d' % len(args)) return 'OP_NEWLIST((%s), %s, %s)' % (', '.join(args), r, err) + def OP_NEWDICT(self, args, r, err): + if len(args) == 0: + return 'OP_NEWDICT0(%s, %s)' % (r, err) + else: + assert len(args) % 2 == 0 + args.insert(0, '%d' % (len(args)//2)) + return 'OP_NEWDICT((%s), %s, %s)' % (', '.join(args), r, err) + def OP_NEWTUPLE(self, args, r, err): args.insert(0, '%d' % len(args)) return 'OP_NEWTUPLE((%s), %s, %s)' % (', '.join(args), r, err) Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Mon Nov 22 13:27:33 2004 @@ -70,7 +70,11 @@ finally: foutput, foutput = c.done() except: - print foutput.read() + data = foutput.read() + fdump = open("%s.errors" % modname, "w") + fdump.write(data) + fdump.close() + print data raise # XXX do we need to do some check on fout/ferr? # XXX not a nice way to import a module From arigo at codespeak.net Mon Nov 22 13:29:23 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 13:29:23 +0100 (MET) Subject: [pypy-svn] r7555 - pypy/trunk/src/pypy/translator Message-ID: <20041122122923.BA4E45AF3B@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 13:29:23 2004 New Revision: 7555 Modified: pypy/trunk/src/pypy/translator/genc.py Log: yuk! typo. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 13:29:23 2004 @@ -159,7 +159,7 @@ '0' <= c <='9' or '_' == c )] name = self.uniquename('gstr_' + ''.join(chrs)) - if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\')]: + if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']: # non-printable string s = 'chr_%s' % name self.globaldecl.append('static char %s[] = { %s };' % ( From arigo at codespeak.net Mon Nov 22 13:43:20 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 13:43:20 +0100 (MET) Subject: [pypy-svn] r7556 - pypy/trunk/src/pypy/translator Message-ID: <20041122124320.1A8275AF3A@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 13:43:19 2004 New Revision: 7556 Modified: pypy/trunk/src/pypy/translator/simplify.py Log: Detect again a case for simplification of implicit exceptions that was broken by the previous reorganization. Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Mon Nov 22 13:43:19 2004 @@ -73,8 +73,10 @@ link.prevblock.exitswitch == Constant(last_exception) and isinstance(link.exitcase, type(Exception)) and issubclass(link.exitcase, Exception) and - list(link.args) == [Constant(last_exception), - Constant(last_exc_value)]): + len(link.args) == 2 and + link.args[1] == Constant(last_exc_value) and + link.args[0] in [Constant(last_exception), + Constant(link.exitcase)]): # remove the link lst = list(link.prevblock.exits) lst.remove(link) From arigo at codespeak.net Mon Nov 22 13:44:22 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 13:44:22 +0100 (MET) Subject: [pypy-svn] r7557 - pypy/trunk/src/pypy/translator Message-ID: <20041122124422.7EC155AF3C@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 13:44:22 2004 New Revision: 7557 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Fixed nameof_staticmethod() to not generate the same function twice. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 13:44:22 2004 @@ -210,16 +210,12 @@ def nameof_staticmethod(self, sm): # XXX XXX XXXX func = sm.__get__(42.5) - if self.translator.frozen: - assert func in self.translator.flowgraphs, func - name = self.uniquename('gsm_' + func.__name__) + functionname = self.nameof(func) self.initcode.append('INITCHK(%s = PyCFunction_New(' - '&ml_%s, NULL))' % (name, name)) - self.pendingfunctions.append(func) + '&ml_%s, NULL))' % (name, functionname)) return name - def nameof_instancemethod(self, meth): if meth.im_self is None: # no error checking here From arigo at codespeak.net Mon Nov 22 14:02:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 14:02:18 +0100 (MET) Subject: [pypy-svn] r7558 - pypy/trunk/src/pypy/translator Message-ID: <20041122130218.8194B5AF3D@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 14:02:18 2004 New Revision: 7558 Modified: pypy/trunk/src/pypy/translator/genc.py Log: boooo. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 14:02:18 2004 @@ -150,7 +150,7 @@ name = ''.join(chrs) name = self.uniquename(name) self.initcode.append('INITCHK(%s = ' - 'PyFloat_FromFloat(%r))' % (name, value)) + 'PyFloat_FromDouble(%r))' % (name, value)) return name def nameof_str(self, value): From arigo at codespeak.net Mon Nov 22 14:17:21 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 14:17:21 +0100 (MET) Subject: [pypy-svn] r7561 - pypy/trunk/src/pypy/translator Message-ID: <20041122131721.20F8F5AF3E@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 14:17:20 2004 New Revision: 7561 Modified: pypy/trunk/src/pypy/translator/genc.py Log: pfff. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 14:17:20 2004 @@ -114,7 +114,7 @@ value.__file__.endswith('.pyo')), \ "%r is not a builtin module (probably :)"%value name = self.uniquename('mod%s'%value.__name__) - self.initcode.append('INITCHK(%s = PyImport_Import("%s"))'%(name, value.__name__)) + self.initcode.append('INITCHK(%s = PyImport_ImportModule("%s"))'%(name, value.__name__)) return name From arigo at codespeak.net Mon Nov 22 14:44:01 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 14:44:01 +0100 (MET) Subject: [pypy-svn] r7562 - pypy/trunk/src/pypy/translator Message-ID: <20041122134401.08E925AF3F@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 14:44:01 2004 New Revision: 7562 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: Old-style classes getting in the way, as always. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 22 14:44:01 2004 @@ -164,9 +164,10 @@ #define SETUP_INSTANCE_ATTR(t, attr, value) \ (PyObject_SetAttrString(t, attr, value) >= 0) -#define SETUP_INSTANCE(i, cls) \ - (i = PyType_GenericAlloc((PyTypeObject *)cls, 0)) - +#define SETUP_INSTANCE(i, cls) \ + (PyType_Check(cls) ? \ + (i = PyType_GenericAlloc((PyTypeObject *)cls, 0)) : \ + (i = PyInstance_NewRaw(cls, NULL))) #if defined(USE_CALL_TRACE) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 14:44:01 2004 @@ -303,9 +303,14 @@ if issubclass(cls, Exception): if cls.__module__ == 'exceptions': return 'PyExc_%s'%cls.__name__ - else: - # exceptions must be old-style classes (grr!) - metaclass = "&PyClass_Type" + #else: + # # exceptions must be old-style classes (grr!) + # metaclass = "&PyClass_Type" + # For the moment, use old-style classes exactly when the + # pypy source uses old-style classes, to avoid strange problems. + if not isinstance(cls, type): + assert type(cls) is type(Exception) + metaclass = "&PyClass_Type" name = self.uniquename('gcls_' + cls.__name__) basenames = [self.nameof(base) for base in cls.__bases__] From arigo at codespeak.net Mon Nov 22 14:50:16 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 14:50:16 +0100 (MET) Subject: [pypy-svn] r7563 - pypy/trunk/src/pypy/translator Message-ID: <20041122135016.7A47A5A2DE@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 14:50:16 2004 New Revision: 7563 Modified: pypy/trunk/src/pypy/translator/genc.h Log: TCC compatibility (the diff is large but only because a large section of code was moved). Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 22 14:50:16 2004 @@ -251,7 +251,7 @@ }; #define MODULE_INITFUNC(modname) \ - static PyMethodDef no_methods[] = { NULL, NULL }; \ + static PyMethodDef no_methods[] = { (char *)NULL, (PyCFunction)NULL }; \ void init##modname(void) #define SETUP_MODULE(modname) \ @@ -270,6 +270,162 @@ #define OP_NEWDICT(args,r,err) if (!(r=PyDict_Pack args)) FAIL(err) #define OP_NEWTUPLE(args,r,err) if (!(r=PyTuple_Pack args)) FAIL(err) +static PyObject* PyList_Pack(int n, ...) +{ + int i; + PyObject *o; + PyObject *result; + va_list vargs; + + va_start(vargs, n); + result = PyList_New(n); + if (result == NULL) { + return NULL; + } + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + PyList_SET_ITEM(result, i, o); + } + va_end(vargs); + return result; +} + +static PyObject* PyDict_Pack(int n, ...) +{ + int i; + PyObject *key, *val; + PyObject *result; + va_list vargs; + + va_start(vargs, n); + result = PyDict_New(); + if (result == NULL) { + return NULL; + } + for (i = 0; i < n; i++) { + key = va_arg(vargs, PyObject *); + val = va_arg(vargs, PyObject *); + if (PyDict_SetItem(result, key, val) < 0) { + Py_DECREF(result); + return NULL; + } + } + va_end(vargs); + return result; +} + +#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ +static PyObject* PyTuple_Pack(int n, ...) +{ + int i; + PyObject *o; + PyObject *result; + PyObject **items; + va_list vargs; + + va_start(vargs, n); + result = PyTuple_New(n); + if (result == NULL) { + return NULL; + } + items = ((PyTupleObject *)result)->ob_item; + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + items[i] = o; + } + va_end(vargs); + return result; +} +#endif + +#if PY_VERSION_HEX >= 0x02030000 /* 2.3 */ +# define PyObject_GetItem1 PyObject_GetItem +# define PyObject_SetItem1 PyObject_SetItem +#else +/* for Python 2.2 only */ +static PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index) +{ + int start, stop, step; + if (!PySlice_Check(index)) { + return PyObject_GetItem(obj, index); + } + if (((PySliceObject*) index)->start == Py_None) { + start = -INT_MAX-1; + } else { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) { + return NULL; + } + } + if (((PySliceObject*) index)->stop == Py_None) { + stop = INT_MAX; + } else { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) { + return NULL; + } + } + if (((PySliceObject*) index)->step != Py_None) { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) { + return NULL; + } + if (step != 1) { + PyErr_SetString(PyExc_ValueError, + "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_GetSlice(obj, start, stop); +} +static PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v) +{ + int start, stop, step; + if (!PySlice_Check(index)) { + return PyObject_SetItem(obj, index, v); + } + if (((PySliceObject*) index)->start == Py_None) { + start = -INT_MAX-1; + } else { + start = PyInt_AsLong(((PySliceObject*) index)->start); + if (start == -1 && PyErr_Occurred()) { + return NULL; + } + } + if (((PySliceObject*) index)->stop == Py_None) { + stop = INT_MAX; + } else { + stop = PyInt_AsLong(((PySliceObject*) index)->stop); + if (stop == -1 && PyErr_Occurred()) { + return NULL; + } + } + if (((PySliceObject*) index)->step != Py_None) { + step = PyInt_AsLong(((PySliceObject*) index)->step); + if (step == -1 && PyErr_Occurred()) { + return NULL; + } + if (step != 1) { + PyErr_SetString(PyExc_ValueError, + "obj[slice]: no step allowed"); + return NULL; + } + } + return PySequence_SetSlice(obj, start, stop, v); +} +#endif + +static PyObject* skipped(PyObject* self, PyObject* args) +{ + PyErr_Format(PyExc_AssertionError, + "calling the skipped function '%s'", + (((PyCFunctionObject *)self) -> m_ml -> ml_name)); + return NULL; +} + + #if defined(USE_CALL_TRACE) static int callstack_depth = -1; @@ -539,158 +695,3 @@ } #endif /* defined(USE_CALL_TRACE) */ - -static PyObject* PyList_Pack(int n, ...) -{ - int i; - PyObject *o; - PyObject *result; - va_list vargs; - - va_start(vargs, n); - result = PyList_New(n); - if (result == NULL) { - return NULL; - } - for (i = 0; i < n; i++) { - o = va_arg(vargs, PyObject *); - Py_INCREF(o); - PyList_SET_ITEM(result, i, o); - } - va_end(vargs); - return result; -} - -static PyObject* PyDict_Pack(int n, ...) -{ - int i; - PyObject *key, *val; - PyObject *result; - va_list vargs; - - va_start(vargs, n); - result = PyDict_New(); - if (result == NULL) { - return NULL; - } - for (i = 0; i < n; i++) { - key = va_arg(vargs, PyObject *); - val = va_arg(vargs, PyObject *); - if (PyDict_SetItem(result, key, val) < 0) { - Py_DECREF(result); - return NULL; - } - } - va_end(vargs); - return result; -} - -#if PY_VERSION_HEX < 0x02040000 /* 2.4 */ -static PyObject* PyTuple_Pack(int n, ...) -{ - int i; - PyObject *o; - PyObject *result; - PyObject **items; - va_list vargs; - - va_start(vargs, n); - result = PyTuple_New(n); - if (result == NULL) { - return NULL; - } - items = ((PyTupleObject *)result)->ob_item; - for (i = 0; i < n; i++) { - o = va_arg(vargs, PyObject *); - Py_INCREF(o); - items[i] = o; - } - va_end(vargs); - return result; -} -#endif - -#if PY_VERSION_HEX >= 0x02030000 /* 2.3 */ -# define PyObject_GetItem1 PyObject_GetItem -# define PyObject_SetItem1 PyObject_SetItem -#else -/* for Python 2.2 only */ -static PyObject* PyObject_GetItem1(PyObject* obj, PyObject* index) -{ - int start, stop, step; - if (!PySlice_Check(index)) { - return PyObject_GetItem(obj, index); - } - if (((PySliceObject*) index)->start == Py_None) { - start = -INT_MAX-1; - } else { - start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) { - return NULL; - } - } - if (((PySliceObject*) index)->stop == Py_None) { - stop = INT_MAX; - } else { - stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) { - return NULL; - } - } - if (((PySliceObject*) index)->step != Py_None) { - step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) { - return NULL; - } - if (step != 1) { - PyErr_SetString(PyExc_ValueError, - "obj[slice]: no step allowed"); - return NULL; - } - } - return PySequence_GetSlice(obj, start, stop); -} -static PyObject* PyObject_SetItem1(PyObject* obj, PyObject* index, PyObject* v) -{ - int start, stop, step; - if (!PySlice_Check(index)) { - return PyObject_SetItem(obj, index, v); - } - if (((PySliceObject*) index)->start == Py_None) { - start = -INT_MAX-1; - } else { - start = PyInt_AsLong(((PySliceObject*) index)->start); - if (start == -1 && PyErr_Occurred()) { - return NULL; - } - } - if (((PySliceObject*) index)->stop == Py_None) { - stop = INT_MAX; - } else { - stop = PyInt_AsLong(((PySliceObject*) index)->stop); - if (stop == -1 && PyErr_Occurred()) { - return NULL; - } - } - if (((PySliceObject*) index)->step != Py_None) { - step = PyInt_AsLong(((PySliceObject*) index)->step); - if (step == -1 && PyErr_Occurred()) { - return NULL; - } - if (step != 1) { - PyErr_SetString(PyExc_ValueError, - "obj[slice]: no step allowed"); - return NULL; - } - } - return PySequence_SetSlice(obj, start, stop, v); -} -#endif - -static PyObject* skipped(PyObject* self, PyObject* args) -{ - PyErr_Format(PyExc_AssertionError, - "calling the skipped function '%s'", - (((PyCFunctionObject *)self) -> m_ml -> ml_name)); - return NULL; -} From arigo at codespeak.net Mon Nov 22 14:56:26 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 14:56:26 +0100 (MET) Subject: [pypy-svn] r7564 - pypy/trunk/src/goal Message-ID: <20041122135626.BBE495AF42@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 14:56:26 2004 New Revision: 7564 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Yoohoo! translate_pypy.py -no-a works! Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 22 14:56:26 2004 @@ -224,7 +224,10 @@ os.link(*args) except OSError: shutil.copy2(*args) - c_entry_point() + w_result = c_entry_point() + print w_result + print w_result.intval + assert w_result.intval == 42 except: debug(True) else: From mgedmin at codespeak.net Mon Nov 22 15:01:00 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 15:01:00 +0100 (MET) Subject: [pypy-svn] r7565 - pypy/trunk/src/goal Message-ID: <20041122140100.7BC0D5AF44@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 15:00:59 2004 New Revision: 7565 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Ignore --mark-some-objects if we're not annotating. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 22 15:00:59 2004 @@ -47,8 +47,8 @@ a.simplify() t.frozen = True # cannot freeze if we don't have annotations - if options['--mark-some-objects']: - find_someobjects(a) + if options['--mark-some-objects']: + find_someobjects(a) def find_someobjects(annotator): From arigo at codespeak.net Mon Nov 22 15:14:27 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 15:14:27 +0100 (MET) Subject: [pypy-svn] r7566 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041122141427.220005AF45@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 15:14:26 2004 New Revision: 7566 Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: For faster running compilation tests, we can now use TCC (http://fabrice.bellard.free.fr/tcc/). It can compile and link the .so files with CPython at least on my machine. To use it (or any another compiler of your choice), set the PYPY_CC environment variable to a line where %s will be replaced by the base file name (without extension). For example: tcc -shared -o %s.so %s.c -I/usr/local/include/python2.3 Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Mon Nov 22 15:14:26 2004 @@ -25,20 +25,22 @@ #print "made module", module return module +def compiler_command(): + return os.getenv('PYPY_CC') + def enable_fast_compilation(): + if compiler_command(): + return # don't bother importing distutils from distutils import sysconfig gcv = sysconfig.get_config_vars() opt = gcv.get('OPT') # not always existent if opt: - opt = re.sub('-O.', '-O0', opt) + opt = re.sub('-O\d+', '-O0', opt) else: opt = '-O0' gcv['OPT'] = opt def make_module_from_c(cfile, include_dirs=None): - from distutils.core import setup - from distutils.extension import Extension - #try: # from distutils.log import set_threshold # set_threshold(10000) @@ -57,16 +59,25 @@ c = stdoutcapture.Capture(mixed_out_err = True) try: try: - setup( - name = "testmodules", - ext_modules=[ - Extension(modname, [str(cfile)], - include_dirs=include_dirs) - ], - script_name = 'setup.py', - script_args = ['-q', 'build_ext', '--inplace'] - #script_args = ['build_ext', '--inplace'] - ) + if compiler_command(): + # GCC-ish options only + cmd = compiler_command().replace('%s', modname) + for dir in include_dirs: + cmd += ' -I%s' % dir + cmdexec(cmd) + else: + from distutils.core import setup + from distutils.extension import Extension + setup( + name = "testmodules", + ext_modules=[ + Extension(modname, [str(cfile)], + include_dirs=include_dirs) + ], + script_name = 'setup.py', + script_args = ['-q', 'build_ext', '--inplace'] + #script_args = ['build_ext', '--inplace'] + ) finally: foutput, foutput = c.done() except: From arigo at codespeak.net Mon Nov 22 16:20:31 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 16:20:31 +0100 (MET) Subject: [pypy-svn] r7567 - in pypy/trunk/src: goal pypy/translator/tool Message-ID: <20041122152031.D6AA65AF46@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 16:20:31 2004 New Revision: 7567 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: - PYPY_CC no longer has to specify the Python include path explicitely. - added a '-tcc' option to translate_pypy.py. - provide full path names to the compiler specified as PYPY_CC, to help with tcc storing relative paths as debug information. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 22 16:20:31 2004 @@ -11,8 +11,9 @@ -o Generate and compile the C code, but don't run it --mark-some-objects Mark all functions that have SomeObject in their signature. + -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' """ -import autopath, sys, threading, pdb +import autopath, sys, threading, pdb, os from pypy.objspace.std.objspace import StdObjSpace, W_Object from pypy.objspace.std.intobject import W_IntObject from pypy.translator.translator import Translator @@ -118,6 +119,7 @@ '-o': False, '--mark-some-objects': False, '-no-a': False, + '-tcc': False, } for arg in sys.argv[1:]: if arg in ('-h', '--help'): @@ -125,6 +127,8 @@ sys.exit() assert arg in options, "unknown option %r" % (arg,) options[arg] = True + if options['-tcc']: + os.environ['PYPY_CC'] = 'tcc -shared -o "%s.so" "%s.c"' def about(x): """ interactive debugging helper """ Modified: pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Mon Nov 22 16:20:31 2004 @@ -26,11 +26,11 @@ return module def compiler_command(): + # e.g. for tcc, you might set this to + # "tcc -shared -o %s.so %s.c" return os.getenv('PYPY_CC') def enable_fast_compilation(): - if compiler_command(): - return # don't bother importing distutils from distutils import sysconfig gcv = sysconfig.get_config_vars() opt = gcv.get('OPT') # not always existent @@ -61,8 +61,11 @@ try: if compiler_command(): # GCC-ish options only - cmd = compiler_command().replace('%s', modname) - for dir in include_dirs: + from distutils import sysconfig + gcv = sysconfig.get_config_vars() + cmd = compiler_command().replace('%s', + str(dirpath.join(modname))) + for dir in [gcv['INCLUDEPY']] + list(include_dirs): cmd += ' -I%s' % dir cmdexec(cmd) else: From mwh at codespeak.net Mon Nov 22 16:42:35 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 22 Nov 2004 16:42:35 +0100 (MET) Subject: [pypy-svn] r7568 - pypy/trunk/src/pypy/translator Message-ID: <20041122154235.551425AF4C@thoth.codespeak.net> Author: mwh Date: Mon Nov 22 16:42:34 2004 New Revision: 7568 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: This code got commented out in May, at the latest. Bye bye! Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Mon Nov 22 16:42:34 2004 @@ -402,202 +402,6 @@ factory = self.bookkeeper.getfactory(DictFactory) return factory.create() -## def decode_simple_call(self, s_varargs, s_varkwds): -## # XXX replace all uses of this with direct calls into annmodel -## return annmodel.decode_simple_call(s_varargs, s_varkwds) - -## def consider_op_call(self, s_func, s_varargs, s_kwargs): -## if not s_func.is_constant(): -## return annmodel.SomeObject() -## func = s_func.const - -## # XXX: generalize this later -## if func is range: -## factory = self.getfactory(ListFactory) -## factory.generalize(annmodel.SomeInteger()) # XXX nonneg=... -## return factory.create() -## elif func is pow: -## args = self.decode_simple_call(s_varargs, s_kwargs) -## if args is not None and len(args) == 2: -## if (issubclass(args[0].knowntype, int) and -## issubclass(args[1].knowntype, int)): -## return annmodel.SomeInteger() -## elif isinstance(func, FunctionType) and self.translator: -## args = self.decode_simple_call(s_varargs, s_kwargs) -## return self.translator.consider_call(self, func, args) -## elif (isinstance(func, (type, ClassType)) and -## func.__module__ != '__builtin__'): -## # XXX flow into __init__/__new__ -## factory = self.getfactory(InstanceFactory, func, self.userclasses) -## return factory.create() -## elif isinstance(func,type): -## return annmodel.valueoftype(func) -## return annmodel.SomeObject() - - -## def consider_op_setattr(self,obj,attr,newval): -## objtype = self.heap.get(ANN.type,obj) -## if objtype in self.userclasses: -## attr = self.heap.get(ANN.const,attr) -## if isinstance(attr, str): -## # do we already know about this attribute? -## attrdict = self.userclasses[objtype] -## clscell = self.constant(objtype) -## if attr not in attrdict: -## # no -> create it -## attrdict[attr] = True -## self.heap.set(ANN.instanceattr[attr], clscell, newval) -## else: -## # yes -> update it -## self.heap.generalize(ANN.instanceattr[attr], clscell, newval) -## return SomeValue() - -## def consider_op_getattr(self,obj,attr): -## result = SomeValue() -## objtype = self.heap.get(ANN.type,obj) -## if objtype in self.userclasses: -## attr = self.heap.get(ANN.const,attr) -## if isinstance(attr, str): -## # do we know something about this attribute? -## attrdict = self.userclasses[objtype] -## if attr in attrdict: -## # yes -> return the current annotation -## clscell = self.constant(objtype) -## return self.heap.get(ANN.instanceattr[attr], clscell) -## return result - - -## def consider_op_add(self, arg1, arg2): -## result = SomeValue() -## tp = self.heap.checktype -## if tp(arg1, int) and tp(arg2, int): -## self.heap.settype(result, int) -## elif tp(arg1, (int, long)) and tp(arg2, (int, long)): -## self.heap.settype(result, long) -## if tp(arg1, str) and tp(arg2, str): -## self.heap.settype(result, str) -## if tp(arg1, list) and tp(arg2, list): -## self.heap.settype(result, list) -## # XXX propagate information about the type of the elements -## return result - -## def consider_op_mul(self, arg1, arg2): -## result = SomeValue() -## tp = self.heap.checktype -## if tp(arg1, int) and tp(arg2, int): -## self.heap.settype(result, int) -## elif tp(arg1, (int, long)) and tp(arg2, (int, long)): -## self.heap.settype(result, long) -## return result - -## def consider_op_inplace_add(self, arg1, arg2): -## tp = self.heap.checktype -## if tp(arg1, list) and tp(arg2, list): -## # Annotations about the items of arg2 are merged with the ones about -## # the items of arg1. arg2 is not modified during this operation. -## # result is arg1. -## self.heap.kill(ANN.len, arg1) -## item2 = self.heap.get(ANN.listitems, arg2) -## self.heap.generalize(ANN.listitems, arg1, item2) -## return arg1 -## else: -## return self.consider_op_add(arg1, arg2) - -## def consider_op_sub(self, arg1, arg2): -## result = SomeValue() -## tp = self.heap.checktype -## if tp(arg1, int) and tp(arg2, int): -## self.heap.settype(result, int) -## elif tp(arg1, (int, long)) and tp(arg2, (int, long)): -## self.heap.settype(result, long) -## return result - -## consider_op_and_ = consider_op_sub # trailing underline -## consider_op_mod = consider_op_sub -## consider_op_inplace_lshift = consider_op_sub - -## def consider_op_is_true(self, arg): -## return boolvalue - -## consider_op_not_ = consider_op_is_true - -## def consider_op_lt(self, arg1, arg2): -## return boolvalue - -## consider_op_le = consider_op_lt -## consider_op_eq = consider_op_lt -## consider_op_ne = consider_op_lt -## consider_op_gt = consider_op_lt -## consider_op_ge = consider_op_lt - -## def consider_op_newslice(self, *args): -## result = SomeValue() -## self.heap.settype(result, slice) -## return result - -## def consider_op_newdict(self, *args): -## result = SomeValue() -## self.heap.settype(result, dict) -## if not args: -## self.heap.set(ANN.len, result, 0) -## return result - -## def consider_op_getitem(self, arg1, arg2): -## tp = self.heap.checktype -## if tp(arg2, int): -## if tp(arg1, tuple): -## index = self.heap.get(ANN.const, arg2) -## if index is not mostgeneralvalue: -## return self.heap.get(ANN.tupleitem[index], arg1) -## if tp(arg1, list): -## return self.heap.get(ANN.listitems, arg1) -## result = SomeValue() -## if tp(arg2, slice): -## self.heap.copytype(arg1, result) -## # XXX copy some information about the items -## return result - -## def decode_simple_call(self, varargs_cell, varkwds_cell): -## nbargs = self.heap.get(ANN.len, varargs_cell) -## if nbargs is mostgeneralvalue: -## return None -## arg_cells = [self.heap.get(ANN.tupleitem[j], varargs_cell) -## for j in range(nbargs)] -## nbkwds = self.heap.get(ANN.len, varkwds_cell) -## if nbkwds != 0: -## return None # XXX deal with dictionaries with constant keys -## return arg_cells - -## def consider_op_call(self, func, varargs, kwargs): -## result = SomeValue() -## tp = self.heap.checktype -## func = self.heap.get(ANN.const, func) -## # XXX: generalize this later -## if func is range: -## self.heap.settype(result, list) -## elif func is pow: -## args = self.decode_simple_call(varargs, kwargs) -## if args is not None and len(args) == 2: -## if tp(args[0], int) and tp(args[1], int): -## self.heap.settype(result, int) -## elif isinstance(func, FunctionType) and self.translator: -## args = self.decode_simple_call(varargs, kwargs) -## return self.translator.consider_call(self, func, args) -## elif isinstance(func,type): -## # XXX flow into __init__/__new__ -## self.heap.settype(result,func) -## if func.__module__ != '__builtin__': -## self.userclasses.setdefault(func, {}) -## return result - -## def consider_const(self, constvalue): -## result = SomeValue() -## self.heap.set(ANN.const, result, constvalue) -## self.heap.settype(result, type(constvalue)) -## if isinstance(constvalue, tuple): -## pass # XXX say something about the elements -## return result - class CannotSimplify(Exception): pass From tismer at codespeak.net Mon Nov 22 16:49:21 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Mon, 22 Nov 2004 16:49:21 +0100 (MET) Subject: [pypy-svn] r7569 - pypy/trunk/src/pypy/translator Message-ID: <20041122154921.CCA0B5AF4F@thoth.codespeak.net> Author: tismer Date: Mon Nov 22 16:49:21 2004 New Revision: 7569 Modified: pypy/trunk/src/pypy/translator/translator.py Log: added an rpython switch which determines whether the translator is used for rpythonic stuff or regular Python. This is now just a defaulted true parameter. No idea yet if this makes sense (and if it should go into the class as an option)? Armin? Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Mon Nov 22 16:49:21 2004 @@ -111,14 +111,14 @@ from pypy.translator.tool.pygame.flowviewer import FlowGraphLayout FlowGraphLayout(self).display() - def simplify(self, func=None): + def simplify(self, func=None, rpython=True): """Simplifies the control flow graph (default: for all functions).""" if func is None: for func in self.flowgraphs.keys(): - self.simplify(func) + self.simplify(func, rpython) else: graph = self.getflowgraph(func) - simplify_graph(graph) + simplify_graph(graph, rpython) def annotate(self, input_args_types, func=None): """annotate(self, input_arg_types[, func]) -> Annotator From bob at codespeak.net Mon Nov 22 17:34:54 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Mon, 22 Nov 2004 17:34:54 +0100 (MET) Subject: [pypy-svn] r7570 - pypy/trunk/src/pypy/translator Message-ID: <20041122163454.CE1065AF51@thoth.codespeak.net> Author: bob Date: Mon Nov 22 17:34:54 2004 New Revision: 7570 Modified: pypy/trunk/src/pypy/translator/genc.h pypy/trunk/src/pypy/translator/genc.py Log: Change code generator to emit two functions per function in the graph: f_foo: Python interface (arg tuple parser) fastf_foo: C interface (function body), all args are passed in C style. Default args must be passed as well (the arg parser fills these in). Also cleaned up a couple warnings.. Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Mon Nov 22 17:34:54 2004 @@ -14,8 +14,10 @@ static PyObject *this_module_globals; -/* Turn this off if you don't want the call trace frames to be built */ +/* Set this if you want call trace frames to be built */ +#if 0 #define USE_CALL_TRACE +#endif #if 0 #define OBNOXIOUS_PRINT_STATEMENTS @@ -193,6 +195,7 @@ #define FUNCTION_HEAD(signature, self, args, names, file, line) #define ERR_DECREF(arg) { Py_DECREF(arg); } + #define FUNCTION_CHECK() #define FUNCTION_RETURN(rval) return rval; @@ -507,9 +510,9 @@ PyObject *nulltuple = NULL; PyObject *filename = NULL; PyCodeObject *tb_code = NULL; +#if defined(OBNOXIOUS_PRINT_STATEMENTS) int i; -#if defined(OBNOXIOUS_PRINT_STATEMENTS) printf("%5d: ", lineno); assert(callstack_depth >= 0); if (callstack_depth) { @@ -519,6 +522,7 @@ } printf("%s\n", func_name); #endif /* !defined(OBNOXIOUS_PRINT_STATEMENTS) */ + code = PyString_FromString(""); if (code == NULL) goto failed; @@ -568,8 +572,6 @@ PyObject *locals_signature; PyObject *locals_lineno; PyObject *locals_filename; - int i; - int max_locals; assert(function && args && tstate); @@ -596,6 +598,7 @@ Py_DECREF(locals_filename); if (extra_local_names != NULL) { int max_locals = MIN(PyList_Size(extra_local_names), PyTuple_Size(args)); + int i; for (i = 0; i < max_locals; ++i) { PyDict_SetItem(locals, PyList_GET_ITEM(extra_local_names, i), PyTuple_GET_ITEM(args, i)); } @@ -656,7 +659,6 @@ static PyObject* PyList_CrazyStringPack(char *begin, ...) { - int i; PyObject *o; PyObject *result; va_list vargs; Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Mon Nov 22 17:34:54 2004 @@ -38,6 +38,8 @@ class GenC: MODNAMES = {} + # XXX - I don't know how to make a macro do this.. so.. + USE_CALL_TRACE = True def __init__(self, f, translator, modname=None, f2=None, f2name=None): self.f = f @@ -462,6 +464,8 @@ 'entrypoint': self.nameof(self.translator.functions[0]), } # header + if self.USE_CALL_TRACE: + print >> f, '#define USE_CALL_TRACE' print >> f, self.C_HEADER # function implementations @@ -508,6 +512,7 @@ ## func.func_globals.get('__name__', '?'), ## func.func_code.co_firstlineno, ## func.__name__) + f = self.f body = list(self.cfunction_body(func)) name_of_defaults = [self.nameof(x, debug=('Default argument of', func)) @@ -518,16 +523,8 @@ name = self.nameof(func) assert name.startswith('gfunc_') f_name = 'f_' + name[6:] - print >> f, 'static PyObject*' - print >> f, '%s(PyObject* self, PyObject* args)' % (f_name,) - print >> f, '{' - print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( - c_string('%s(%s)' % (name, ', '.join(name_of_defaults))), - name, - '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), - ) - # collect and print all the local variables + # collect all the local variables graph = self.translator.getflowgraph(func) localslst = [] def visit(node): @@ -535,23 +532,56 @@ localslst.extend(node.getvariables()) traverse(visit, graph) localnames = [a.name for a in uniqueitems(localslst)] - print >> f, '\tPyObject *%s;' % (', *'.join(localnames),) - print >> f - - print >> f, '\tFUNCTION_CHECK()' - # argument unpacking + # collect all the arguments if func.func_code.co_flags & CO_VARARGS: vararg = graph.getargs()[-1] positional_args = graph.getargs()[:-1] + else: + vararg = None + positional_args = graph.getargs() + min_number_of_args = len(positional_args) - len(name_of_defaults) + + fast_args = [a.name for a in positional_args] + if vararg is not None: + fast_args.append(str(vararg)) + fast_name = 'fast' + f_name + + fast_set = dict(zip(fast_args, fast_args)) + + declare_fast_args = [('PyObject *' + a) for a in fast_args] + if self.USE_CALL_TRACE: + declare_fast_args[:0] = ['PyFrameObject *__f', 'PyThreadState *__tstate'] + + print >> f, 'static PyObject *' + print >> f, '%s(%s);' % (fast_name, ', '.join(declare_fast_args)) + print >> f + + print >> f, 'static PyObject *' + print >> f, '%s(PyObject* self, PyObject* args)' % (f_name,) + print >> f, '{' + print >> f, '\tFUNCTION_HEAD(%s, %s, args, %s, __FILE__, __LINE__ - 2)' % ( + c_string('%s(%s)' % (name, ', '.join(name_of_defaults))), + name, + '(%s)' % (', '.join(map(c_string, name_of_defaults) + ['NULL']),), + ) + + if fast_args: + print >> f, '\tPyObject *%s;' % (', *'.join(fast_args)) + print >> f + + print >> f, '\tFUNCTION_CHECK()' + + # argument unpacking + if vararg is not None: print >> f, '\t%s = PyTuple_GetSlice(args, %d, INT_MAX);' % ( vararg, len(positional_args)) - print >> f, '\tif (%s == NULL)' % vararg + print >> f, '\tif (%s == NULL)' % (vararg,) print >> f, '\t\tFUNCTION_RETURN(NULL)' print >> f, '\targs = PyTuple_GetSlice(args, 0, %d);' % ( len(positional_args),) print >> f, '\tif (args == NULL) {' - print >> f, '\t\tERR_DECREF(%s)' % vararg + print >> f, '\t\tERR_DECREF(%s)' % (vararg,) print >> f, '\t\tFUNCTION_RETURN(NULL)' print >> f, '\t}' tail = """{ @@ -561,9 +591,7 @@ \t} \tPy_DECREF(args);""" % vararg else: - positional_args = graph.getargs() tail = '\n\t\tFUNCTION_RETURN(NULL)' - min_number_of_args = len(positional_args) - len(name_of_defaults) for i in range(len(name_of_defaults)): print >> f, '\t%s = %s;' % ( positional_args[min_number_of_args+i], @@ -577,6 +605,22 @@ print >> f, '\tif (!PyArg_UnpackTuple(%s))' % ', '.join(lst), print >> f, tail + call_fast_args = list(fast_args) + if self.USE_CALL_TRACE: + call_fast_args[:0] = ['__f', '__tstate'] + print >> f, '\treturn %s(%s);' % (fast_name, ', '.join(call_fast_args)) + print >> f, '}' + print >> f + + print >> f, 'static PyObject *' + print >> f, '%s(%s)' % (fast_name, ', '.join(declare_fast_args)) + print >> f, '{' + + fast_locals = [arg for arg in localnames if arg not in fast_set] + if fast_locals: + print >> f, '\tPyObject *%s;' % (', *'.join(fast_locals),) + print >> f + # generate an incref for each input argument for v in positional_args: print >> f, '\tPy_INCREF(%s);' % v.name From mwh at codespeak.net Mon Nov 22 17:39:00 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 22 Nov 2004 17:39:00 +0100 (MET) Subject: [pypy-svn] r7571 - pypy/trunk/src/pypy/objspace Message-ID: <20041122163900.4E9CE5AF9D@thoth.codespeak.net> Author: mwh Date: Mon Nov 22 17:38:59 2004 New Revision: 7571 Modified: pypy/trunk/src/pypy/objspace/descroperation.py Log: kill more months dead code. Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Mon Nov 22 17:38:59 2004 @@ -82,14 +82,6 @@ def unwrap_builtin(self, w_obj): return w_obj # hook for hack by TrivialObjSpace -## def call(space, w_obj, w_args, w_kwargs): -## #print "call %r, %r, %r" %(w_obj, w_args, w_kwargs) -## w_descr = space.lookup(w_obj, '__call__') -## if w_descr is None: -## raise OperationError(space.w_TypeError, -## space.wrap('object %r is not callable' % (w_obj,))) -## return space.get_and_call(w_descr, w_obj, w_args, w_kwargs) - def call_args(space, w_obj, args): if type(w_obj) is Function and isinstance(w_obj.code, BuiltinCode): # this special case is ONLY for performance reasons From mwh at codespeak.net Mon Nov 22 17:57:56 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 22 Nov 2004 17:57:56 +0100 (MET) Subject: [pypy-svn] r7572 - pypy/trunk/src/pypy/annotation Message-ID: <20041122165756.02FD65AF9E@thoth.codespeak.net> Author: mwh Date: Mon Nov 22 17:57:56 2004 New Revision: 7572 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: I think all I have done today is delete code! Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon Nov 22 17:57:56 2004 @@ -301,18 +301,3 @@ def union((pbc1, pbc2)): return SomePrebuiltConstant(setunion(pbc1.prebuiltinstances, pbc2.prebuiltinstances)) - -class __extend__(pairtype(SomePrebuiltConstant, SomeObject)): - def getitem((pbc1, obj2)): - # special case for SomePrebuiltConstants that are dictionaries - # (actually frozendicts) - possibleresults = [] - for inst in pbc1.prebuiltinstances: - if isinstance(inst, dict): - possibleresults += inst.values() - #elif isinstance(inst, list): - # possibleresults += inst # maybe - else: - raise TypeError, "cannot getitem() from %r" % (inst,) - possibleresults = [immutablevalue(x) for x in possibleresults] - return unionof(*possibleresults) From arigo at codespeak.net Mon Nov 22 17:59:10 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 17:59:10 +0100 (MET) Subject: [pypy-svn] r7573 - pypy/trunk/src/pypy/tool/test Message-ID: <20041122165910.59CED5AFA5@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 17:59:09 2004 New Revision: 7573 Modified: pypy/trunk/src/pypy/tool/test/test_cache.py Log: Can no longer test for hash(cache) raising TypeError. Modified: pypy/trunk/src/pypy/tool/test/test_cache.py ============================================================================== --- pypy/trunk/src/pypy/tool/test/test_cache.py (original) +++ pypy/trunk/src/pypy/tool/test/test_cache.py Mon Nov 22 17:59:09 2004 @@ -7,7 +7,9 @@ cache = Cache() assert cache.getorbuild(1, lambda k,s: 42, None) == 42 assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 42 - self.assertRaises(TypeError, hash, cache) + # XXX cannot test that any longer: + # XXX hash(cache) now freezes the cache "just-in-time". + # XXX --disabled-- self.assertRaises(TypeError, hash, cache) cache.clear() assert cache.getorbuild(1, lambda k,s: 44, None) == 44 assert cache.getorbuild(1, lambda k,s: self.fail(), None) == 44 From mwh at codespeak.net Mon Nov 22 18:05:59 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 22 Nov 2004 18:05:59 +0100 (MET) Subject: [pypy-svn] r7574 - pypy/trunk/src/pypy/annotation Message-ID: <20041122170559.0EA865AFA3@thoth.codespeak.net> Author: mwh Date: Mon Nov 22 18:05:58 2004 New Revision: 7574 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py Log: SomePBC is now referred to as SomePBC (and not SomePrebuiltConstant) everywhere. Having more than one name for something is officially Just Annoying. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon Nov 22 18:05:58 2004 @@ -8,7 +8,7 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeCallable from pypy.annotation.model import SomeBuiltin, SomeIterator -from pypy.annotation.model import SomePrebuiltConstant, immutablevalue +from pypy.annotation.model import SomePBC, immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize, isclassdef, getbookkeeper from pypy.objspace.flow.model import Constant @@ -297,7 +297,7 @@ return obj1 -class __extend__(pairtype(SomePrebuiltConstant, SomePrebuiltConstant)): +class __extend__(pairtype(SomePBC, SomePBC)): def union((pbc1, pbc2)): - return SomePrebuiltConstant(setunion(pbc1.prebuiltinstances, - pbc2.prebuiltinstances)) + return SomePBC(setunion(pbc1.prebuiltinstances, + pbc2.prebuiltinstances)) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Mon Nov 22 18:05:58 2004 @@ -188,8 +188,6 @@ self.prebuiltinstances = prebuiltinstances self.knowntype = reduce(commonbase, [x.__class__ for x in prebuiltinstances]) -SomePrebuiltConstant = SomePBC - class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that @@ -250,7 +248,7 @@ elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': if isinstance(x, Cache) and not x.frozen: x.freeze() - result = SomePrebuiltConstant({x: True}) # pre-built inst: + result = SomePBC({x: True}) # pre-built inst: elif x is None: result = SomeNone() else: Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Mon Nov 22 18:05:58 2004 @@ -9,7 +9,7 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin from pypy.annotation.model import SomeCallable, SomeIterator -from pypy.annotation.model import SomePrebuiltConstant +from pypy.annotation.model import SomePBC from pypy.annotation.model import immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -193,7 +193,7 @@ # return unionof(*results) -class __extend__(SomePrebuiltConstant): +class __extend__(SomePBC): def getattr(pbc, s_attr): assert s_attr.is_constant() From arigo at codespeak.net Mon Nov 22 18:07:39 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 18:07:39 +0100 (MET) Subject: [pypy-svn] r7575 - pypy/trunk/src/pypy/translator Message-ID: <20041122170739.994C65AFCF@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 18:07:39 2004 New Revision: 7575 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: Provide SomeObject() bindings for last_exception and last_exc_value. A more precise SomeInstance(classdef(XxxError)) would be nice, but we don't have a factory handy on which to attribute the SomeInstance creation :-( Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Mon Nov 22 18:07:39 2004 @@ -7,6 +7,7 @@ from pypy.annotation.factory import BlockedInference, Bookkeeper from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation, FunctionGraph +from pypy.objspace.flow.model import last_exception, last_exc_value from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS @@ -135,13 +136,18 @@ raise AnnotatorError('%d blocks are still blocked' % self.annotated.values().count(False)) - def binding(self, arg): + def binding(self, arg, in_link=None): "Gives the SomeValue corresponding to the given Variable or Constant." if isinstance(arg, Variable): return self.bindings[arg] elif isinstance(arg, UndefinedConstant): # undefined local variables return annmodel.SomeImpossibleValue() elif isinstance(arg, Constant): + if arg.value is last_exception or arg.value is last_exc_value: + assert in_link + assert isinstance(in_link.exitcase, type(Exception)) + assert issubclass(in_link.exitcase, Exception) + return annmodel.SomeObject() # XXX return annmodel.immutablevalue(arg.value) else: raise TypeError, 'Variable or Constant expected, got %r' % (arg,) @@ -340,11 +346,10 @@ self.links_followed[link] = True cells = [] for a in link.args: + cell = self.binding(a, in_link=link) if link.exitcase is True and a is knownvar \ - and not knownvarvalue.contains(self.binding(a)): + and not knownvarvalue.contains(cell): cell = knownvarvalue - else: - cell = self.binding(a) cells.append(cell) self.addpendingblock(fn, link.target, cells) if block in self.notify: From jacob at codespeak.net Mon Nov 22 18:26:24 2004 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 22 Nov 2004 18:26:24 +0100 (MET) Subject: [pypy-svn] r7576 - in pypy/trunk/src/pypy: appspace appspace/test module/test Message-ID: <20041122172624.C244A5AFD1@thoth.codespeak.net> Author: jacob Date: Mon Nov 22 18:26:24 2004 New Revision: 7576 Added: pypy/trunk/src/pypy/module/test/emptyfile.py Modified: pypy/trunk/src/pypy/appspace/_file.py pypy/trunk/src/pypy/appspace/sio.py pypy/trunk/src/pypy/appspace/test/test_sio.py Log: Added buffered read/write and made the interface to file objects more complete. Modified: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_file.py (original) +++ pypy/trunk/src/pypy/appspace/_file.py Mon Nov 22 18:26:24 2004 @@ -26,7 +26,11 @@ self.reading = self.writing = True except IndexError: pass - + + self.mode = mode + self.name = filename + self.closed = False + self.softspace = 0 # Required according to file object docs self.fd = sio.DiskFile(filename, mode) if mode in ['U', 'rU']: # Wants universal newlines @@ -43,9 +47,15 @@ return self.fd def __getattr__(self, name): + if name == 'close': + self.closed = True """ Delegate all other methods to the underlying file object. """ return getattr(self.fd, name) - + def __setattr__(self, name): + "Make some attributes readonly." + if name in ['mode', 'name', 'closed']: + raise TypeError('readonly attribute') + return setattr(self, name) Modified: pypy/trunk/src/pypy/appspace/sio.py ============================================================================== --- pypy/trunk/src/pypy/appspace/sio.py (original) +++ pypy/trunk/src/pypy/appspace/sio.py Mon Nov 22 18:26:24 2004 @@ -34,8 +34,14 @@ import os import mmap +class Stream(object): + def __getattr__(self, name): + """ + Delegate all other methods to the underlying file object. + """ + return getattr(self.base, name) -class BufferingInputStream(object): +class BufferingInputStream(Stream): """Standard buffering input stream. @@ -249,7 +255,7 @@ def readlines(self, sizehint=0): return list(self) -class BufferingOutputStream(object): +class BufferingOutputStream(Stream): """Standard buffering output stream. @@ -266,6 +272,7 @@ self.do_seek = getattr(base, "seek", None) # None, or seek to a byte offset self.do_close = base.close # Close file + self.do_truncate = base.truncate # Truncate file if bufsize is None: # Get default from the class bufsize = self.bufsize @@ -281,11 +288,14 @@ return self.pos def seek(self, offset, whence=0): - self.do_write(self.buf) - self.buf = '' + self.flush() self.do_seek(offset, whence) self.pos = self.do_tell() + def flush(self): + self.do_write(self.buf) + self.buf = '' + def write(self, data): buflen = len(self.buf) datalen = len(data) @@ -305,6 +315,10 @@ if self.do_close(): self.do_close() + def truncate(self, size=None): + self.flush() + self.do_truncate(size) + class LineBufferingOutputStream(BufferingOutputStream): """Line buffering output stream. @@ -319,24 +333,12 @@ self.do_seek = getattr(base, "seek", None) # None, or seek to a byte offset self.do_close = base.close # Close file + self.do_truncate = base.truncate # Truncate file self.linesep = os.linesep self.buf = "" # raw data (may contain "\n") self.tell() - def tell(self): - assert self.do_tell is not None - if not hasattr(self, 'pos'): - self.pos = self.do_tell() - - return self.pos - - def seek(self, offset, whence=0): - self.do_write(self.buf) - self.buf = '' - self.do_seek(offset, whence) - self.pos = self.do_tell() - def write(self, data): all_lines = data.split(self.linesep) full_lines = all_lines[:-1] @@ -373,13 +375,61 @@ self.buf = '' self.write(line[self.bufsize-buflen:]) - def close(self): - self.do_write(self.buf) - self.buf = '' - if self.do_close(): - self.do_close() +class BufferingInputOutputStream(Stream): + """To handle buffered input and output at the same time, we are + switching back and forth between using BuffereingInputStream + and BufferingOutputStream as reads and writes are done. + A more optimal solution would be to read and write on the same + buffer, but it would take a fair bit of time to implement. + """ + + def __init__(self, base, bufsize=None): + self.base = base + self.bufsize = bufsize + self.reader = None + self.writer = None + + def read(self, n=-1): + if not self.reader: + if self.writer: + self.writer.flush() + self.writer = None + self.reader = BufferingInputStream(self.base, self.bufsize) + return self.reader.read(n) + + def write(self, data): + if not self.writer: + if self.reader: + # Make sure the underlying file has the correct current + # position + self.reader.seek(self.reader.tell()) + self.reader = None + self.writer = BufferingOutputStream(self.base, self.bufsize) + return self.writer.write(data) + + def truncate(self, size=None): + if not self.writer: + if self.reader: + # Make sure the underlying file has the correct current + # position + self.reader.seek(self.reader.tell()) + self.reader = None + self.writer = BufferingOutputStream(self.base, self.bufsize) + return self.writer.truncate(size) + + def __getattr__(self, name): + """ + Delegate all other methods to the underlying file object. + """ + if not self.reader and not self.writer: + self.reader = BufferingInputStream(self.base, self.bufsize) + + if self.reader: + return getattr(self.reader, name) -class CRLFFilter(object): + return getattr(self.writer, name) + +class CRLFFilter(Stream): """Filtering stream for universal newlines. @@ -597,13 +647,24 @@ self.fd = None os.close(fd) + def truncate(self, size=None): + if size is None: + size = self.tell() + if os.name == 'posix': + os.ftruncate(self.fd, size) + else: + raise NotImplementedError + + def fileno(): + return self.fd + def __del__(self): try: self.close() except: pass -class TextInputFilter(object): +class TextInputFilter(Stream): """Filtering input stream for universal newline translation.""" @@ -711,7 +772,7 @@ self.buf = "" return pos - len(self.buf) -class TextOutputFilter(object): +class TextOutputFilter(Stream): """Filtering output stream for universal newline translation.""" @@ -732,7 +793,7 @@ def tell(self): return self.base.tell() -class DecodingInputFilter(object): +class DecodingInputFilter(Stream): """Filtering input stream that decodes an encoded file.""" @@ -772,7 +833,7 @@ pass raise -class EncodingOutputFilter(object): +class EncodingOutputFilter(Stream): """Filtering output stream that writes to an encoded file.""" Modified: pypy/trunk/src/pypy/appspace/test/test_sio.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_sio.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_sio.py Mon Nov 22 18:26:24 2004 @@ -93,8 +93,8 @@ class TestWriter(object): - def __init__(self): - self.buf = "" + def __init__(self, data=''): + self.buf = data self.pos = 0 def write(self, data): @@ -124,6 +124,27 @@ def close(self): pass + + def truncate(self, size=None): + if size is None: + size = self.pos + if size <= len(self.buf): + self.buf = self.buf[:size] + else: + self.buf += '\0' * (size - len(self.buf)) + +class TestReaderWriter(TestWriter): + + def read(self, n=-1): + if n < 1: + result = self.buf[self.pos: ] + self.pos = len(self.buf) + else: + if self.pos + n > len(self.buf): + n = len(self.buf) - self.pos + result = self.buf[self.pos: self.pos+n] + self.pos += n + return result class BufferingInputStreamTests(unittest.TestCase): @@ -357,6 +378,35 @@ filter.close() self.assertEqual(base.buf, "x"*3 + "y"*2 + "x"*1) + def test_write_seek_beyond_end(self): + "Linux behaviour. May be different on other platforms." + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.seek(3) + filter.write("y"*2) + filter.close() + self.assertEqual(base.buf, "\0"*3 + "y"*2) + + def test_truncate(self): + "Linux behaviour. May be different on other platforms." + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.write('x') + filter.truncate(4) + filter.write('y') + filter.close() + self.assertEqual(base.buf, 'xy' + '\0' * 2) + + def test_truncate2(self): + "Linux behaviour. May be different on other platforms." + base = TestWriter() + filter = sio.BufferingOutputStream(base, 4) + filter.write('12345678') + filter.truncate(4) + filter.write('y') + filter.close() + self.assertEqual(base.buf, '1234' + '\0' * 4 + 'y') + class LineBufferingOutputStreamTests(unittest.TestCase): def test_write(self): @@ -385,6 +435,33 @@ filter.close() self.assertEqual(base.buf, "x"*3 + "y"*2 + "x"*1) +class BufferingInputOutputStreamTests(unittest.TestCase): + + def test_write(self): + base = TestReaderWriter() + filter = sio.BufferingInputOutputStream(base, 4) + filter.write("123456789") + self.assertEqual(base.buf, "12345678") + s = filter.read() + self.assertEqual(base.buf, "123456789") + filter.write("01234") + self.assertEqual(base.buf, "1234567890123") + filter.seek(4,0) + self.assertEqual(base.buf, "12345678901234") + self.assertEqual(filter.read(3), "567") + filter.write('x') + filter.flush() + self.assertEqual(base.buf, "1234567x901234") + + def test_write_seek_beyond_end(self): + "Linux behaviour. May be different on other platforms." + base = TestReaderWriter() + filter = sio.BufferingInputOutputStream(base, 4) + filter.seek(3) + filter.write("y"*2) + filter.close() + self.assertEqual(base.buf, "\0"*3 + "y"*2) + class CRLFFilterTests(unittest.TestCase): def test_filter(self): @@ -660,6 +737,7 @@ suite.addTest(unittest.makeSuite(BufferingInputStreamTests)) suite.addTest(unittest.makeSuite(BufferingOutputStreamTests)) suite.addTest(unittest.makeSuite(LineBufferingOutputStreamTests)) + suite.addTest(unittest.makeSuite(BufferingInputOutputStreamTests)) suite.addTest(unittest.makeSuite(CRLFFilterTests)) suite.addTest(unittest.makeSuite(MMapFileTests)) suite.addTest(unittest.makeSuite(TextInputFilterTests)) Added: pypy/trunk/src/pypy/module/test/emptyfile.py ============================================================================== From jacob at codespeak.net Mon Nov 22 18:28:24 2004 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 22 Nov 2004 18:28:24 +0100 (MET) Subject: [pypy-svn] r7577 - pypy/trunk/src/pypy/module/test Message-ID: <20041122172824.50FC45B000@thoth.codespeak.net> Author: jacob Date: Mon Nov 22 18:28:23 2004 New Revision: 7577 Removed: pypy/trunk/src/pypy/module/test/emptyfile.py Log: Removed spurious file. Deleted: /pypy/trunk/src/pypy/module/test/emptyfile.py ============================================================================== From mwh at codespeak.net Mon Nov 22 18:50:49 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Mon, 22 Nov 2004 18:50:49 +0100 (MET) Subject: [pypy-svn] r7578 - pypy/trunk/src/pypy/objspace Message-ID: <20041122175049.E57165AFF4@thoth.codespeak.net> Author: mwh Date: Mon Nov 22 18:50:49 2004 New Revision: 7578 Modified: pypy/trunk/src/pypy/objspace/descroperation.py Log: this is as least as correct as what went before, and removes the only call to wrap(SomeObject())! Modified: pypy/trunk/src/pypy/objspace/descroperation.py ============================================================================== --- pypy/trunk/src/pypy/objspace/descroperation.py (original) +++ pypy/trunk/src/pypy/objspace/descroperation.py Mon Nov 22 18:50:49 2004 @@ -90,8 +90,10 @@ return w_result w_descr = space.lookup(w_obj, '__call__') if w_descr is None: - raise OperationError(space.w_TypeError, - space.wrap('object %r is not callable' % (w_obj,))) + raise OperationError( + space.w_TypeError, + space.mod(space.wrap('object %r is not callable'), + space.newtuple([w_obj]))) return space.get_and_call_args(w_descr, w_obj, args) def get(space, w_descr, w_obj, w_type=None): From arigo at codespeak.net Mon Nov 22 18:57:10 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 22 Nov 2004 18:57:10 +0100 (MET) Subject: [pypy-svn] r7579 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041122175710.061695B001@thoth.codespeak.net> Author: arigo Date: Mon Nov 22 18:57:10 2004 New Revision: 7579 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py Log: removed *call Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Mon Nov 22 18:57:10 2004 @@ -469,7 +469,11 @@ return self.perform_call(args) except FailedToImplement, e: if e.args: - raise OperationError(*e.args) + if len(e.args) == 1: + w_value = self.space.w_None + else: + w_value = e.args[1] + raise OperationError(e.args[0], w_value) else: # raise a TypeError for a FailedToImplement initialtypes = [a.__class__ From jacob at codespeak.net Mon Nov 22 19:46:12 2004 From: jacob at codespeak.net (jacob at codespeak.net) Date: Mon, 22 Nov 2004 19:46:12 +0100 (MET) Subject: [pypy-svn] r7580 - pypy/trunk/src/pypy/appspace Message-ID: <20041122184612.6C8F45AFF9@thoth.codespeak.net> Author: jacob Date: Mon Nov 22 19:46:10 2004 New Revision: 7580 Modified: pypy/trunk/src/pypy/appspace/_file.py pypy/trunk/src/pypy/appspace/sio.py Log: Fixing readonly. Modified: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_file.py (original) +++ pypy/trunk/src/pypy/appspace/_file.py Mon Nov 22 19:46:10 2004 @@ -38,12 +38,18 @@ if bufsize < 0: bufsize = None if not self.writing and (bufsize is None or bufsize > 0): + "Read only buffered stream." self.fd = sio.BufferingInputStream(self.fd, bufsize) if not self.reading: if bufsize is None or bufsize > 1: + "Write only buffered stream." self.fd = sio.BufferingOutputStream(self.fd, bufsize) elif bufsize == 1: self.fd = sio.LineBufferingOutputStream(self.fd) + if self.reading and self.writing: + if bufsize > 2: + "Read and write buffered stream." + self.fd = sio.BufferingInputOutputStream(self.fd, bufsize) return self.fd def __getattr__(self, name): @@ -54,8 +60,8 @@ """ return getattr(self.fd, name) - def __setattr__(self, name): + def __setattr__(self, attr, val): "Make some attributes readonly." - if name in ['mode', 'name', 'closed']: - raise TypeError('readonly attribute') - return setattr(self, name) + if attr in ['mode', 'name', 'closed', 'encoding']: + raise TypeError('readonly attribute: %s' % attr) + self.__dict__[attr] = val Modified: pypy/trunk/src/pypy/appspace/sio.py ============================================================================== --- pypy/trunk/src/pypy/appspace/sio.py (original) +++ pypy/trunk/src/pypy/appspace/sio.py Mon Nov 22 19:46:10 2004 @@ -34,7 +34,9 @@ import os import mmap + class Stream(object): + "All streams except the base ones need to inherit from this class." def __getattr__(self, name): """ Delegate all other methods to the underlying file object. @@ -309,6 +311,10 @@ self.buf = '' self.write(data[self.bufsize-buflen:]) + def writelines(self, sequence): + for s in sequence: + self.write(s) + def close(self): self.do_write(self.buf) self.buf = '' @@ -589,6 +595,10 @@ class DiskFile(object): """Standard I/O basis stream using os.open/close/read/write/lseek""" + + # This is not quite correct, since more letters are allowed after + # these. However, the following are the only starting strings allowed + # in the mode parameter. modes = { 'r' : os.O_RDONLY, 'rb' : os.O_RDONLY, @@ -655,6 +665,12 @@ else: raise NotImplementedError + def isatty(self): + if os.name == 'posix': + return os.isatty(self.fd) + else: + raise NotImplementedError + def fileno(): return self.fd From mgedmin at codespeak.net Mon Nov 22 20:00:06 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Mon, 22 Nov 2004 20:00:06 +0100 (MET) Subject: [pypy-svn] r7582 - pypy/trunk/src/pypy/annotation Message-ID: <20041122190006.D6D115B002@thoth.codespeak.net> Author: mgedmin Date: Mon Nov 22 20:00:06 2004 New Revision: 7582 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: 'string' % SomeObject always returns a string. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon Nov 22 20:00:06 2004 @@ -162,6 +162,12 @@ return SomeString() +class __extend__(pairtype(SomeString, SomeObject)): + + def mod((str, args)): + return SomeString() + + class __extend__(pairtype(SomeList, SomeList)): def union((lst1, lst2)): From hpk at codespeak.net Tue Nov 23 11:16:49 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 11:16:49 +0100 (MET) Subject: [pypy-svn] r7597 - pypy/trunk/src/goal Message-ID: <20041123101649.ED7715A8B2@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 11:16:49 2004 New Revision: 7597 Modified: pypy/trunk/src/goal/translate_pypy.py Log: - rewrote the "update .../usession code" to be more general and use the py lib's path implementation - make --mark-some-objects the DEFAULT so you have to say --not-mark-some-objects to turn it off. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 23 11:16:49 2004 @@ -9,7 +9,7 @@ -no-c Don't generate the C code -c Generate the C code, but don't compile it -o Generate and compile the C code, but don't run it - --mark-some-objects + --not-mark-some-objects Mark all functions that have SomeObject in their signature. -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' """ @@ -20,6 +20,7 @@ from pypy.annotation import model as annmodel from pypy.tool.cache import Cache from pypy.annotation.model import SomeObject +from pypy.tool.udir import udir # XXX this tries to make compiling faster from pypy.translator.tool import buildpyxmodule @@ -48,7 +49,7 @@ a.simplify() t.frozen = True # cannot freeze if we don't have annotations - if options['--mark-some-objects']: + if not options['--not-mark-some-objects']: find_someobjects(a) @@ -104,6 +105,23 @@ someobjnum, num) print "=" * 70 +def update_usession_dir(stabledir = udir.dirpath('usession')): + from py import path + try: + if stabledir.check(dir=1): + for x in udir.visit(path.checker(file=1)): + target = stabledir.join(x.relto(udir)) + if target.check(): + target.remove() + else: + target.dirpath().ensure(dir=1) + try: + target.mklinkto(x) + except path.Invalid: + x.copy(target) + except path.Invalid: + print "ignored: couldn't link or copy to %s" % stabledir + def run_in_thread(fn, args, cleanup=None, cleanup_args=()): def _run_in_thread(): fn(*args) @@ -117,7 +135,7 @@ '-no-c': False, '-c': False, '-o': False, - '--mark-some-objects': False, + '--not-mark-some-objects': False, '-no-a': False, '-tcc': False, } @@ -202,32 +220,14 @@ elif options['-c']: print 'Generating C code without compiling it...' filename = t.ccompile(really_compile=False) + update_usession_dir() print 'Written %s.' % (filename,) else: print 'Generating and compiling C code...' c_entry_point = t.ccompile() + update_usession_dir() if not options['-o']: print 'Running!' - import os, shutil - from pypy.tool.udir import udir - d = str(udir) - linkdir = os.path.join(os.path.dirname(d), 'usession') - if os.path.exists(linkdir): - def globexps(dirname, *exps): - import glob - rval = [] - for exp in exps: - rval.extend(glob.glob(os.path.join(dirname, exp))) - return rval - exts = ('*.c', '*.so') - for fn in globexps(linkdir, *exts): - os.remove(fn) - for fn in globexps(d, *exts): - args = fn, os.path.join(linkdir, os.path.basename(fn)) - try: - os.link(*args) - except OSError: - shutil.copy2(*args) w_result = c_entry_point() print w_result print w_result.intval From hpk at codespeak.net Tue Nov 23 12:12:10 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 12:12:10 +0100 (MET) Subject: [pypy-svn] r7598 - pypy/trunk/src/pypy/translator/test Message-ID: <20041123111210.432C45A9FE@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 12:12:09 2004 New Revision: 7598 Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: a failing test (let's see if the current SomePBC/SomeInstance refactoring will fix this) Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 12:12:09 2004 @@ -336,7 +336,7 @@ s = a.build_types(snippet.preserve_pbc_attr_on_instance, [bool]) #a.simplify() #a.translator.view() - #self.assert_(isinstance(s, annmodel.SomeInstance)) + self.assert_(not s.__class__ is annmodel.SomeObject) #self.assertEquals(s.const, 3) From hpk at codespeak.net Tue Nov 23 12:43:19 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 12:43:19 +0100 (MET) Subject: [pypy-svn] r7604 - in pypy/trunk/src/pypy/annotation: . test Message-ID: <20041123114319.11E1A5AA9C@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 12:43:18 2004 New Revision: 7604 Added: pypy/trunk/src/pypy/annotation/test/test_pairtype.py Modified: pypy/trunk/src/pypy/annotation/pairtype.py Log: move tests for pairtypes to its own files (and fixed them to run at least with py.test) Modified: pypy/trunk/src/pypy/annotation/pairtype.py ============================================================================== --- pypy/trunk/src/pypy/annotation/pairtype.py (original) +++ pypy/trunk/src/pypy/annotation/pairtype.py Tue Nov 23 12:43:18 2004 @@ -33,98 +33,3 @@ bases = tuple(bases1 + bases2) or (tuple,) # 'tuple': ultimate base pair = pairtypecache[cls1, cls2] = extendabletype(name, bases, {}) return pair - - -# ____________________________________________________________ - -if __name__ == '__main__': - from unittest2 import check - - ### Binary operation example - class __extend__(pairtype(int, int)): - def add((x, y)): - return 'integer: %s+%s' % (x, y) - def sub((x, y)): - return 'integer: %s-%s' % (x, y) - - class __extend__(pairtype(bool, bool)): - def add((x, y)): - return 'bool: %s+%s' % (x, y) - - check.equal(pair(3,4).add(), 'integer: 3+4') - check.equal(pair(3,4).sub(), 'integer: 3-4') - check.equal(pair(3,True).add(), 'integer: 3+True') - check.equal(pair(3,True).sub(), 'integer: 3-True') - check.equal(pair(False,4).add(), 'integer: False+4') - check.equal(pair(False,4).sub(), 'integer: False-4') - check.equal(pair(False,True).add(), 'bool: False+True') - check.equal(pair(False,True).sub(), 'integer: False-True') - - ### Operation on built-in types - class MiniPickler: - def __init__(self): - self.data = [] - def emit(self, datum): - self.data.append(datum) - - class __extend__(pairtype(MiniPickler, int)): - def write((pickler, x)): - pickler.emit('I%d' % x) - - class __extend__(pairtype(MiniPickler, str)): - def write((pickler, x)): - pickler.emit('S%s' % x) - - class __extend__(pairtype(MiniPickler, list)): - def write((pickler, x)): - for item in x: - pair(pickler, item).write() - pickler.emit('L%d' % len(x)) - - p = MiniPickler() - pair(p, [1, 2, ['hello', 3]]).write() - check.equal(p.data, ['I1', 'I2', 'Shello', 'I3', 'L2', 'L3']) - - ### Another multimethod example - class Block: - def __init__(self, exit): - self.exit = exit - class Jump: - pass - class Switch: - pass - - class C_Generator: - def __init__(self): - self.lines = [] - - class __extend__(pairtype(C_Generator, Block)): - def emit((gen, block), inputvars): - gen.lines.append("C code for block") - outputvars = inputvars + ['v4', 'v5'] - pair(gen, block.exit).emit(outputvars) - - class __extend__(pairtype(C_Generator, Jump)): - def emit((gen, jump), inputvars): - gen.lines.append("goto xyz") - - class __extend__(pairtype(C_Generator, Switch)): - def emit((gen, jump), inputvars): - gen.lines.append("switch (%s) { ... }" % inputvars[-1]) - - g = C_Generator() - pair(g, Block(Switch())).emit(['v1', 'v2']) - check.equal(g.lines, ["C code for block", - "switch (v5) { ... }"]) - - class Lisp_Generator: - def __init__(self): - self.progn = [] - - class __extend__(pairtype(Lisp_Generator, Block)): - def emit((gen, block), inputvars): - gen.progn.append("(do 'something)") - - g = Lisp_Generator() - pair(g, Block(Switch())).emit(['v1', 'v2']) - check.equal(g.progn, ["(do 'something)"]) Added: pypy/trunk/src/pypy/annotation/test/test_pairtype.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/annotation/test/test_pairtype.py Tue Nov 23 12:43:18 2004 @@ -0,0 +1,93 @@ + +from pypy.annotation.pairtype import pairtype, pair + +def test_binop(): + ### Binary operation example + class __extend__(pairtype(int, int)): + def add((x, y)): + return 'integer: %s+%s' % (x, y) + def sub((x, y)): + return 'integer: %s-%s' % (x, y) + + class __extend__(pairtype(bool, bool)): + def add((x, y)): + return 'bool: %s+%s' % (x, y) + + assert pair(3,4).add() == 'integer: 3+4' + assert pair(3,4).sub() == 'integer: 3-4' + assert pair(3,True).add() == 'integer: 3+True' + assert pair(3,True).sub() == 'integer: 3-True' + assert pair(False,4).add() == 'integer: False+4' + assert pair(False,4).sub() == 'integer: False-4' + assert pair(False,True).add() == 'bool: False+True' + assert pair(False,True).sub() == 'integer: False-True' + +def test_somebuiltin(): + ### Operation on built-in types + class MiniPickler: + def __init__(self): + self.data = [] + def emit(self, datum): + self.data.append(datum) + + class __extend__(pairtype(MiniPickler, int)): + def write((pickler, x)): + pickler.emit('I%d' % x) + + class __extend__(pairtype(MiniPickler, str)): + def write((pickler, x)): + pickler.emit('S%s' % x) + + class __extend__(pairtype(MiniPickler, list)): + def write((pickler, x)): + for item in x: + pair(pickler, item).write() + pickler.emit('L%d' % len(x)) + + p = MiniPickler() + pair(p, [1, 2, ['hello', 3]]).write() + assert p.data == ['I1', 'I2', 'Shello', 'I3', 'L2', 'L3'] + +def test_some_multimethod(): + ### Another multimethod example + class Block: + def __init__(self, exit): + self.exit = exit + class Jump: + pass + class Switch: + pass + + class C_Generator: + def __init__(self): + self.lines = [] + + class __extend__(pairtype(C_Generator, Block)): + def emit((gen, block), inputvars): + gen.lines.append("C code for block") + outputvars = inputvars + ['v4', 'v5'] + pair(gen, block.exit).emit(outputvars) + + class __extend__(pairtype(C_Generator, Jump)): + def emit((gen, jump), inputvars): + gen.lines.append("goto xyz") + + class __extend__(pairtype(C_Generator, Switch)): + def emit((gen, jump), inputvars): + gen.lines.append("switch (%s) { ... }" % inputvars[-1]) + + g = C_Generator() + pair(g, Block(Switch())).emit(['v1', 'v2']) + assert g.lines == ["C code for block", "switch (v5) { ... }"] + + class Lisp_Generator: + def __init__(self): + self.progn = [] + + class __extend__(pairtype(Lisp_Generator, Block)): + def emit((gen, block), inputvars): + gen.progn.append("(do 'something)") + + g = Lisp_Generator() + pair(g, Block(Switch())).emit(['v1', 'v2']) + assert g.progn == ["(do 'something)"] From hpk at codespeak.net Tue Nov 23 12:54:49 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 12:54:49 +0100 (MET) Subject: [pypy-svn] r7605 - pypy/trunk/src/pypy/translator/test Message-ID: <20041123115449.918AD5ACCB@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 12:54:49 2004 New Revision: 7605 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: don't check for code objects because immutablevalue(code) returns a SomeObject ... Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 23 12:54:49 2004 @@ -602,15 +602,15 @@ return a class APBC: - def f(self): - pass - code = f.func_code + def __init__(self): + self.answer = 42 apbc = APBC() +apbc.answer = 7 def preserve_pbc_attr_on_instance(cond): if cond: x = APBC() else: x = apbc - return x.code + return x.answer Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 12:54:49 2004 @@ -336,9 +336,8 @@ s = a.build_types(snippet.preserve_pbc_attr_on_instance, [bool]) #a.simplify() #a.translator.view() - self.assert_(not s.__class__ is annmodel.SomeObject) - #self.assertEquals(s.const, 3) - + self.assertEquals(s, annmodel.SomeInteger(nonneg=True)) + #self.assertEquals(s.__class__, annmodel.SomeInteger) def g(n): return [0,1,2,n] From mwh at codespeak.net Tue Nov 23 13:11:50 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 13:11:50 +0100 (MET) Subject: [pypy-svn] r7606 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20041123121150.4B5105AEAF@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 13:11:49 2004 New Revision: 7606 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Integrate the annotation of instances and pbcs, which ended up involving refactoring quite a lot of the annotation of instances and classes. In particular: - there is now an Attribute class containing potential 'sources' for an attribute. - immutablevalue and valueoftype are now methods of the Bookkeeper class. - .bookkeeper attributes are now more common and bookkeeper arguments somewhat less so. - I accidentally ran delete-trailing-whitespace on all of factory.py instead of the region I was aiming for which bulks out the diff a bit. Sorry about that. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 13:11:49 2004 @@ -8,11 +8,14 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeCallable from pypy.annotation.model import SomeBuiltin, SomeIterator -from pypy.annotation.model import SomePBC, immutablevalue +from pypy.annotation.model import SomePBC from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize, isclassdef, getbookkeeper from pypy.objspace.flow.model import Constant +# convenience only! +def immutablevalue(x): + return getbookkeeper().immutablevalue(x) # XXX unify this with ObjSpace.MethodTable BINARY_OPERATIONS = set(['add', 'sub', 'mul', 'div', 'mod', @@ -307,3 +310,15 @@ def union((pbc1, pbc2)): return SomePBC(setunion(pbc1.prebuiltinstances, pbc2.prebuiltinstances)) + +class __extend__(pairtype(SomeInstance, SomePBC)): + def union((ins, pbc)): + classdef = ins.currentdef().superdef_containing(pbc.knowntype) + if classdef is None: + # print warning? + return SomeObject() + return SomeInstance(classdef) + +class __extend__(pairtype(SomePBC, SomeInstance)): + def union((pbc, ins)): + return pair(ins, pbc).union() Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Tue Nov 23 13:11:49 2004 @@ -4,11 +4,13 @@ from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool from pypy.annotation.model import SomeList, SomeString, SomeTuple -from pypy.annotation.model import immutablevalue, valueoftype from pypy.annotation.factory import ListFactory, getbookkeeper from pypy.objspace.flow.model import Constant import pypy.objspace.std.restricted_int +# convenience only! +def immutablevalue(x): + return getbookkeeper().immutablevalue(x) def builtin_len(s_obj): return s_obj.len() @@ -64,7 +66,7 @@ assert op.args[0] == Constant(isinstance) assert annotator.binding(op.args[1]) is s_obj r = SomeBool() - r.knowntypedata = (op.args[1], valueoftype(typ, bk)) + r.knowntypedata = (op.args[1], bk.valueoftype(typ)) return r return SomeBool() Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 13:11:49 2004 @@ -9,13 +9,18 @@ from __future__ import generators import new from types import FunctionType, ClassType, MethodType -from pypy.annotation.model import SomeImpossibleValue, SomeList, SomeDict -from pypy.annotation.model import SomeObject, SomeInstance -from pypy.annotation.model import unionof, immutablevalue +from pypy.annotation.model import * from pypy.interpreter.miscutils import getthreadlocals from pypy.interpreter.pycode import CO_VARARGS from pypy.tool.hack import func_with_new_name +def ishashable(x): + try: + hash(x) + except TypeError: + return False + else: + return True class BlockedInference(Exception): """This exception signals the type inference engine that the situation @@ -44,7 +49,6 @@ self.creationpoints = {} # map position-in-a-block to its Factory self.userclasses = {} # map classes to ClassDefs self.userclasseslist = []# userclasses.keys() in creation order - self.attrs_read_from_constants = {} self.cachespecializations = {} def enter(self, position_key): @@ -87,6 +91,85 @@ return self.userclasses[cls] + def immutablevalue(self, x): + """The most precise SomeValue instance that contains the + immutable value x.""" + tp = type(x) + if tp is bool: + result = SomeBool() + elif tp is int: + result = SomeInteger(nonneg = x>=0) + elif tp is str: + result = SomeString() + elif tp is tuple: + result = SomeTuple(items = [self.immutablevalue(e) for e in x]) + elif tp is list: + items_s = [self.immutablevalue(e) for e in x] + result = SomeList({}, unionof(*items_s)) + elif tp is dict: # exactly a dict + items = {} + for key, value in x.items(): + items[key] = self.immutablevalue(value) + result = SomeDict({}, items) + elif ishashable(x) and x in BUILTIN_ANALYZERS: + result = SomeBuiltin(BUILTIN_ANALYZERS[x]) + elif callable(x) or isinstance(x, staticmethod): # XXX + # maybe 'x' is a method bound to a not-yet-frozen cache? + # fun fun fun. + if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) + and not x.im_self.frozen): + x.im_self.freeze() + if hasattr(x, '__self__') and x.__self__ is not None: + s_self = self.immutablevalue(x.__self__) + # stop infinite recursion getattr<->immutablevalue + del s_self.const + s_name = self.immutablevalue(x.__name__) + result = s_self.getattr(s_name) + else: + result = SomeCallable({x : True}) + elif hasattr(x, '__class__') \ + and x.__class__.__module__ != '__builtin__': + if isinstance(x, Cache) and not x.frozen: + x.freeze() + result = SomePBC({x: True}) # pre-built inst + clsdef = self.getclassdef(x.__class__) + for attr in x.__dict__: + clsdef.add_source_for_attribute(attr, x) + elif x is None: + result = SomeNone() + else: + result = SomeObject() + result.const = x + return result + + def valueoftype(self, t): + """The most precise SomeValue instance that contains all + objects of type t.""" + if t is bool: + return SomeBool() + elif t is int: + return SomeInteger() + elif t is str: + return SomeString() + elif t is list: + return SomeList(factories={}) + # can't do dict, tuple + elif isinstance(t, (type, ClassType)) and \ + t.__module__ != '__builtin__': + classdef = self.getclassdef(t) + if self.is_in_an_operation(): + # woha! instantiating a "mutable" SomeXxx like SomeInstance + # is always dangerous, because we need to record this fact + # in a factory, to allow reflowing from the current operation + # if/when the classdef later changes. + factory = self.getfactory(CallableFactory) + classdef.instancefactories[factory] = True + return SomeInstance(classdef) + else: + o = SomeObject() + o.knowntype = t + return o + def getbookkeeper(): """Get the current Bookkeeper. Only works during the analysis of an operation.""" @@ -105,14 +188,14 @@ raise BlockedInference # reflow now def isclassdef(x): - return isinstance(x, ClassDef) + return isinstance(x, ClassDef) class ListFactory: s_item = SomeImpossibleValue() def __repr__(self): return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) - + def create(self): return SomeList(factories = {self: True}, s_item = self.s_item) @@ -145,11 +228,11 @@ return False -class CallableFactory: +class CallableFactory: def pycall(self, func, *args): if isinstance(func, (type, ClassType)) and \ func.__module__ != '__builtin__': - cls = func + cls = func x = getattr(cls, "_specialize_", False) if x: if x == "location": @@ -157,7 +240,7 @@ else: raise Exception, \ "unsupported specialization type '%s'"%(x,) - + classdef = self.bookkeeper.getclassdef(cls) classdef.instancefactories[self] = True s_instance = SomeInstance(classdef) @@ -169,17 +252,17 @@ assert not args, "no __init__ found in %r" % (cls,) return s_instance if hasattr(func, '__call__') and \ - isinstance(func.__call__, MethodType): + isinstance(func.__call__, MethodType): func = func.__call__ if hasattr(func, 'im_func'): if func.im_self is not None: - s_self = immutablevalue(func.im_self) + s_self = self.bookkeeper.immutablevalue(func.im_self) args = [s_self] + list(args) try: func.im_func.class_ = func.im_class except AttributeError: # probably a builtin function, we don't care to preserve - # class information then + # class information then pass func = func.im_func assert isinstance(func, FunctionType), "expected function, got %r"%func @@ -187,15 +270,15 @@ x = getattr(func, '_specialize_', False) if x: if x == 'argtypes': - key = short_type_name(args) - func = self.specialize_by_key(func, key, - func.__name__+'__'+key) + key = short_type_name(args) + func = self.specialize_by_key(func, key, + func.__name__+'__'+key) elif x == "location": # fully specialize: create one version per call position func = self.specialize_by_key(func, self.position_key) else: raise Exception, "unsupported specialization type '%s'"%(x,) - + elif func.func_code.co_flags & CO_VARARGS: # calls to *arg functions: create one version per number of args func = self.specialize_by_key(func, len(args), @@ -222,20 +305,51 @@ def short_type_name(args): l = [] - for x in args: + for x in args: if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'): - name = "SI_" + x.knowntype.__name__ + name = "SI_" + x.knowntype.__name__ else: name = x.__class__.__name__ - l.append(name) - return "__".join(l) + l.append(name) + return "__".join(l) + + +class Attribute: + # readonly-ness + # SomeThing-ness + # more potential sources (pbcs or classes) of information + + def __init__(self, name, bookkeeper): + self.name = name + self.bookkeeper = bookkeeper + self.sources = {} # source -> None or ClassDef + # XXX a SomeImpossibleValue() constant? later!! + self.s_value = SomeImpossibleValue() + self.readonly = True + + def getvalue(self): + while self.sources: + source, classdef = self.sources.popitem() + s_value = self.bookkeeper.immutablevalue( + source.__dict__[self.name]) + if classdef: + s_value = s_value.bindcallables(classdef) + self.s_value = unionof(self.s_value, s_value) + return self.s_value + + def merge(self, other): + assert self.name == other.name + self.sources.update(other.sources) + self.s_value = unionof(self.s_value, other.s_value) + self.readonly = self.readonly and other.readonly + class ClassDef: "Wraps a user class." def __init__(self, cls, bookkeeper): - self.attrs = {} # attrs is updated with new information - self.readonly = {} # {attr: True-or-False} + self.bookkeeper = bookkeeper + self.attrs = {} # {name: Attribute} self.revision = 0 # which increases the revision number self.instancefactories = {} self.cls = cls @@ -250,6 +364,7 @@ self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self + # collect the (supposed constant) class attributes for name, value in cls.__dict__.items(): # ignore some special attributes @@ -257,13 +372,21 @@ continue if isinstance(value, FunctionType): value.class_ = cls # remember that this is really a method - # although self.getallfactories() is currently empty, - # the following might still invalidate some blocks if it - # generalizes existing values in parent classes - s_value = immutablevalue(value) - s_value = s_value.bindcallables(self) - self.generalize_attr(name, s_value, bookkeeper) + self.add_source_for_attribute(name, cls, self) + + def add_source_for_attribute(self, attr, source, clsdef=None): + self.find_attribute(attr).sources[source] = clsdef + def locate_attribute(self, attr): + for cdef in self.getmro(): + if attr in cdef.attrs: + return cdef + self.generalize_attr(attr) + return self + + def find_attribute(self, attr): + return self.locate_attribute(attr).attrs[attr] + def __repr__(self): return "" % (self.cls.__module__, self.cls.__name__) @@ -272,6 +395,12 @@ other = other.basedef return other + def superdef_containing(self, cls): + clsdef = self + while clsdef is not None and not issubclass(cls, clsdef.cls): + clsdef = clsdef.basedef + return clsdef + def getmro(self): while self is not None: yield self @@ -293,41 +422,43 @@ factories.update(clsdef.instancefactories) return factories - def _generalize_attr(self, attr, s_value, bookkeeper, readonly): + def _generalize_attr(self, attr, s_value): # first remove the attribute from subclasses -- including us! - subclass_values = [] + subclass_attrs = [] for subdef in self.getallsubdefs(): if attr in subdef.attrs: - subclass_values.append(subdef.attrs[attr]) - readonly = readonly and subdef.readonly[attr] + subclass_attrs.append(subdef.attrs[attr]) del subdef.attrs[attr] - del subdef.readonly[attr] # bump the revision number of this class and all subclasses subdef.revision += 1 # do the generalization - self.attrs[attr] = unionof(s_value, *subclass_values) - self.readonly[attr] = readonly - - # reflow from all factories - if bookkeeper: - for factory in self.getallfactories(): - bookkeeper.annotator.reflowfromposition(factory.position_key) + newattr = Attribute(attr, self.bookkeeper) + if s_value: + newattr.s_value = s_value + + for subattr in subclass_attrs: + newattr.merge(subattr) + self.attrs[attr] = newattr + # reflow from all factories + for factory in self.getallfactories(): + self.bookkeeper.annotator.reflowfromposition(factory.position_key) - def generalize_attr(self, attr, s_value, bookkeeper=None, readonly=True): + def generalize_attr(self, attr, s_value=None): # if the attribute exists in a superclass, generalize there. for clsdef in self.getmro(): if attr in clsdef.attrs: - clsdef._generalize_attr(attr, s_value, bookkeeper, readonly) - return + clsdef._generalize_attr(attr, s_value) else: - self._generalize_attr(attr, s_value, bookkeeper, readonly) + self._generalize_attr(attr, s_value) def about_attribute(self, name): for cdef in self.getmro(): if name in cdef.attrs: - return cdef.attrs[name] - return SomeImpossibleValue() + return cdef.attrs[name].getvalue() + return None + + -from pypy.annotation.builtin import BUILTIN_ANALYZERS +from pypy.annotation.builtin import BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue Nov 23 13:11:49 2004 @@ -204,99 +204,6 @@ s1.caused_by_merge = somevalues return s1 -def ishashable(x): - try: - hash(x) - except TypeError: - return False - else: - return True - -def immutablevalue(x): - "The most precise SomeValue instance that contains the immutable value x." - tp = type(x) - if tp is bool: - result = SomeBool() - elif tp is int: - result = SomeInteger(nonneg = x>=0) - elif tp is str: - result = SomeString() - elif tp is tuple: - result = SomeTuple(items = [immutablevalue(e) for e in x]) - elif tp is list: - items_s = [immutablevalue(e) for e in x] - result = SomeList({}, unionof(*items_s)) - elif tp is dict: # exactly a dict, not a subclass like Cache - items = {} - for key, value in x.items(): - items[key] = immutablevalue(value) - result = SomeDict({}, items) - elif ishashable(x) and x in BUILTIN_ANALYZERS: - result = SomeBuiltin(BUILTIN_ANALYZERS[x]) - elif callable(x) or isinstance(x, staticmethod): # XXX - # maybe 'x' is a method bound to a not-yet-frozen cache? fun fun fun. - if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) - and not x.im_self.frozen): - x.im_self.freeze() - if hasattr(x, '__self__') and x.__self__ is not None: - s_self = immutablevalue(x.__self__) - del s_self.const # stop infinite recursion getattr<->immutablevalue - s_name = immutablevalue(x.__name__) - result = s_self.getattr(s_name) - else: - result = SomeCallable({x : True}) - elif hasattr(x, '__class__') and x.__class__.__module__ != '__builtin__': - if isinstance(x, Cache) and not x.frozen: - x.freeze() - result = SomePBC({x: True}) # pre-built inst: - elif x is None: - result = SomeNone() - else: - result = SomeObject() - result.const = x - return result - -def valueoftype(t, bookkeeper=None): - "The most precise SomeValue instance that contains all objects of type t." - if t is bool: - return SomeBool() - elif t is int: - return SomeInteger() - elif t is str: - return SomeString() - elif t is list: - return SomeList(factories={}) - # can't do dict, tuple - elif isinstance(t, (type, ClassType)) and \ - t.__module__ != '__builtin__' and bookkeeper is not None: - classdef = bookkeeper.getclassdef(t) - if bookkeeper.is_in_an_operation(): - # woha! instantiating a "mutable" SomeXxx like SomeInstance - # is always dangerous, because we need to record this fact - # in a factory, to allow reflowing from the current operation - # if/when the classdef later changes. - from pypy.annotation.factory import CallableFactory - factory = bookkeeper.getfactory(CallableFactory) - classdef.instancefactories[factory] = True - return SomeInstance(classdef) - else: - o = SomeObject() - o.knowntype = t - return o - -##def decode_simple_call(s_args, s_kwds): -## s_nbargs = s_args.len() -## if not s_nbargs.is_constant(): -## return None -## nbargs = s_nbargs.const -## arglist = [pair(s_args, immutablevalue(j)).getitem() -## for j in range(nbargs)] -## s_nbkwds = s_kwds.len() -## if not s_nbkwds.is_constant() or s_nbkwds.const != 0: -## return None # XXX deal with dictionaries with keywords -## return arglist - - # ____________________________________________________________ # internal Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 23 13:11:49 2004 @@ -10,11 +10,13 @@ from pypy.annotation.model import SomeInstance, SomeBuiltin from pypy.annotation.model import SomeCallable, SomeIterator from pypy.annotation.model import SomePBC -from pypy.annotation.model import immutablevalue from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper from pypy.annotation.factory import CallableFactory, isclassdef +# convenience only! +def immutablevalue(x): + return getbookkeeper().immutablevalue(x) UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'simple_call', 'iter', 'next']) @@ -120,34 +122,27 @@ if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const #print 'getattr:', ins, attr, ins.classdef.revision - # look for the attribute in the MRO order - for clsdef in ins.currentdef().getmro(): - if attr in clsdef.attrs: - return clsdef.attrs[attr] - # maybe the attribute exists in some subclass? if so, lift it - clsdef = ins.classdef - clsdef.generalize_attr(attr, SomeImpossibleValue(), getbookkeeper()) - raise BlockedInference + s_result = ins.currentdef().find_attribute(attr).getvalue() + # we call this because it might raise BlockedInference if + # the above line caused generalization. + ins.currentdef() + return s_result return SomeObject() def setattr(ins, s_attr, s_value): if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - for clsdef in ins.currentdef().getmro(): - if attr in clsdef.attrs: - # look for the attribute in ins.classdef or a parent class - s_existing = clsdef.attrs[attr] - if s_existing.contains(s_value): - clsdef.readonly[attr] = False - return # already general enough, nothing to do - break - else: - # if the attribute doesn't exist yet, create it here - clsdef = ins.classdef + clsdef = ins.currentdef().locate_attribute(attr) + attrdef = clsdef.attrs[attr] + attrdef.readonly = False + + # if the attrdef is new, this must fail + if attrdef.getvalue().contains(s_value): + return # create or update the attribute in clsdef - clsdef.generalize_attr(attr, s_value, getbookkeeper(), readonly=False) + clsdef.generalize_attr(attr, s_value) raise BlockedInference - return SomeObject() + return class __extend__(SomeBuiltin): def simple_call(bltn, *args): @@ -198,10 +193,9 @@ def getattr(pbc, s_attr): assert s_attr.is_constant() attr = s_attr.const - bookkeeper = getbookkeeper() actuals = [] + for c in pbc.prebuiltinstances: - bookkeeper.attrs_read_from_constants.setdefault(c, {})[attr] = True if hasattr(c, attr): actuals.append(immutablevalue(getattr(c, attr))) return unionof(*actuals) Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 23 13:11:49 2004 @@ -60,7 +60,7 @@ inputcells = [] for t in input_arg_types: if not isinstance(t, annmodel.SomeObject): - t = annmodel.valueoftype(t, self.bookkeeper) + t = self.bookkeeper.valueoftype(t) inputcells.append(t) # register the entry point @@ -101,9 +101,6 @@ self.binding_caused_by[v] = None yield v - def getpbcattrs(self, pbc): - return self.bookkeeper.attrs_read_from_constants.get(pbc, {}) - #___ medium-level interface ____________________________ def addpendingblock(self, fn, block, cells, called_from=None): @@ -148,7 +145,7 @@ assert isinstance(in_link.exitcase, type(Exception)) assert issubclass(in_link.exitcase, Exception) return annmodel.SomeObject() # XXX - return annmodel.immutablevalue(arg.value) + return self.bookkeeper.immutablevalue(arg.value) else: raise TypeError, 'Variable or Constant expected, got %r' % (arg,) @@ -210,7 +207,7 @@ "got %d inputcells in call to %r; expected %s" % ( len(inputcells), func, msg)) for extra in func.func_defaults[-missingargs:]: - inputcells.append(annmodel.immutablevalue(extra)) + inputcells.append(self.bookkeeper.immutablevalue(extra)) inputcells.extend(extracells) self.addpendingblock(func, block, inputcells, factory) Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 13:11:49 2004 @@ -7,7 +7,7 @@ from pypy.translator.translator import Translator from pypy.objspace.flow.model import * -from pypy.annotation.model import immutablevalue, SomeCallable +from pypy.annotation.model import SomeCallable from pypy.translator.test import snippet @@ -161,7 +161,7 @@ s = a.build_types(snippet.inheritance1, []) # result should be exactly: self.assertEquals(s, annmodel.SomeTuple([ - annmodel.immutablevalue(()), + a.bookkeeper.immutablevalue(()), annmodel.SomeInteger() ])) @@ -198,8 +198,10 @@ classes = a.bookkeeper.userclasses self.assertEquals(classes[snippet.F].attrs.keys(), ['m']) self.assertEquals(classes[snippet.G].attrs.keys(), ['m2']) - self.assertEquals(classes[snippet.H].attrs, - {'attr': annmodel.immutablevalue(1)}) + self.assertEquals(classes[snippet.H].attrs.keys(), ['attr']) + self.assertEquals(classes[snippet.H].about_attribute('attr'), + a.bookkeeper.immutablevalue(1)) + def test_knownkeysdict(self): a = RPythonAnnotator() @@ -227,9 +229,9 @@ # XXX on which class should the attribute 'a' appear? We only # ever flow WithInit.__init__ with a self which is an instance # of WithMoreInit, so currently it appears on WithMoreInit. - self.assertEquals(classes[snippet.WithMoreInit].attrs.get('a'), + self.assertEquals(classes[snippet.WithMoreInit].about_attribute('a'), annmodel.SomeInteger()) - self.assertEquals(classes[snippet.WithMoreInit].attrs.get('b'), + self.assertEquals(classes[snippet.WithMoreInit].about_attribute('b'), annmodel.SomeBool()) def test_global_instance(self): @@ -237,14 +239,14 @@ s = a.build_types(snippet.global_instance, []) # currently this returns the constant 42. # XXX not sure this is the best behavior... - self.assertEquals(s, annmodel.immutablevalue(42)) + self.assertEquals(s, a.bookkeeper.immutablevalue(42)) def test_call_five(self): a = RPythonAnnotator() s = a.build_types(snippet.call_five, []) # returns should be a list of constants (= 5) self.assert_(isinstance(s, annmodel.SomeList)) - self.assertEquals(s.s_item, annmodel.immutablevalue(5)) + self.assertEquals(s.s_item, a.bookkeeper.immutablevalue(5)) def test_call_five_six(self): a = RPythonAnnotator() @@ -258,7 +260,7 @@ s = a.build_types(snippet.constant_result, []) #a.translator.simplify() # must return "yadda" - self.assertEquals(s, annmodel.immutablevalue("yadda")) + self.assertEquals(s, a.bookkeeper.immutablevalue("yadda")) keys = a.translator.flowgraphs.keys() keys.sort() expected = [snippet.constant_result, @@ -273,7 +275,7 @@ def test_call_pbc(self): a = RPythonAnnotator() s = a.build_types(snippet.call_cpbc, []) - self.assertEquals(s, annmodel.immutablevalue(42)) + self.assertEquals(s, a.bookkeeper.immutablevalue(42)) def test_flow_type_info(self): a = RPythonAnnotator() @@ -309,7 +311,7 @@ a.translator.simplify() a.simplify() #a.translator.view() - self.assertEquals(s, immutablevalue((None, None))) + self.assertEquals(s, a.bookkeeper.immutablevalue((None, None))) def test_mergefunctions(self): a = RPythonAnnotator() From mwh at codespeak.net Tue Nov 23 13:15:52 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 13:15:52 +0100 (MET) Subject: [pypy-svn] r7607 - pypy/trunk/src/pypy/translator Message-ID: <20041123121552.4E8D45B010@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 13:15:51 2004 New Revision: 7607 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Oops! Should have been part of the last checkin. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Tue Nov 23 13:15:51 2004 @@ -240,11 +240,9 @@ return False else: return "probably" # True - if attr in ann.getpbcattrs(pbc): - return True classdef = ann.getuserclasses().get(pbc.__class__) if (classdef and - classdef.about_attribute(attr) != annmodel.SomeImpossibleValue()): + classdef.about_attribute(attr) not in [None, SomeImpossibleValue()]): return True return False From arigo at codespeak.net Tue Nov 23 13:16:53 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 13:16:53 +0100 (MET) Subject: [pypy-svn] r7608 - pypy/trunk/src/pypy/translator Message-ID: <20041123121653.0CC935B013@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 13:16:52 2004 New Revision: 7608 Modified: pypy/trunk/src/pypy/translator/genpyrex.py Log: fixed genpyrex.py for the previous refactoring. Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Tue Nov 23 13:16:52 2004 @@ -415,7 +415,8 @@ self.putline("cdef class %s%s:" % (self.getclassname(cls.cls),bdef)) self.indent += 1 empty = True - for attr,s_value in cls.attrs.items(): + for attr, attrdef in cls.attrs.items(): + s_value = attrdef.s_value if isinstance(s_value, SomeCallable): for py_fun,fun_class in s_value.callables.items(): assert isclassdef(fun_class), ( From hpk at codespeak.net Tue Nov 23 13:21:05 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 13:21:05 +0100 (MET) Subject: [pypy-svn] r7609 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041123122105.7C4AD5B00F@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 13:21:04 2004 New Revision: 7609 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: comment the obnoxious warnings about "cannot unpack ... assuming 7" we need some tracing facility! Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Tue Nov 23 13:21:04 2004 @@ -153,9 +153,9 @@ def unpackiterable(self, w_iterable, expected_length=None): if isinstance(w_iterable, Variable) and expected_length is None: # XXX TEMPORARY HACK XXX TEMPORARY HACK XXX TEMPORARY HACK - print ("*** cannot unpack a Variable iterable " - "without knowing its length,") - print " assuming a list or tuple with up to 7 items" + #print ("*** cannot unpack a Variable iterable " + # "without knowing its length,") + #print " assuming a list or tuple with up to 7 items" items = [] w_len = self.len(w_iterable) i = 0 From mgedmin at codespeak.net Tue Nov 23 13:24:03 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 13:24:03 +0100 (MET) Subject: [pypy-svn] r7610 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041123122403.7A6435B014@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 13:24:02 2004 New Revision: 7610 Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py pypy/trunk/src/pypy/objspace/std/stdtypedef.py Log: FailedToImplement is always raised with either zero or two arguments, and the annotator dislikes raise Something(*e.args). Modified: pypy/trunk/src/pypy/objspace/std/multimethod.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/multimethod.py (original) +++ pypy/trunk/src/pypy/objspace/std/multimethod.py Tue Nov 23 13:24:02 2004 @@ -469,11 +469,7 @@ return self.perform_call(args) except FailedToImplement, e: if e.args: - if len(e.args) == 1: - w_value = self.space.w_None - else: - w_value = e.args[1] - raise OperationError(e.args[0], w_value) + raise OperationError(e.args[0], e.args[1]) else: # raise a TypeError for a FailedToImplement initialtypes = [a.__class__ Modified: pypy/trunk/src/pypy/objspace/std/stdtypedef.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stdtypedef.py (original) +++ pypy/trunk/src/pypy/objspace/std/stdtypedef.py Tue Nov 23 13:24:02 2004 @@ -179,7 +179,7 @@ return self.code.mm.perform_call(args) except FailedToImplement, e: if e.args: - raise OperationError(*e.args) + raise OperationError(e.args[0], e.args[1]) else: return self.space.w_NotImplemented From mgedmin at codespeak.net Tue Nov 23 13:31:39 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 13:31:39 +0100 (MET) Subject: [pypy-svn] r7611 - pypy/trunk/src/pypy/translator Message-ID: <20041123123139.722335B015@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 13:31:38 2004 New Revision: 7611 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Small fix: SomeImpossibleValue is not imported. Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Tue Nov 23 13:31:38 2004 @@ -241,8 +241,8 @@ else: return "probably" # True classdef = ann.getuserclasses().get(pbc.__class__) - if (classdef and - classdef.about_attribute(attr) not in [None, SomeImpossibleValue()]): + if (classdef and classdef.about_attribute(attr) not in [ + None, annmodel.SomeImpossibleValue()]): return True return False From arigo at codespeak.net Tue Nov 23 13:39:32 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 13:39:32 +0100 (MET) Subject: [pypy-svn] r7612 - pypy/trunk/src/pypy/translator/test Message-ID: <20041123123932.0D6A25B017@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 13:39:32 2004 New Revision: 7612 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_ctrans.py Log: Three new tests, two of them purposefully failing currently. Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 23 13:39:32 2004 @@ -63,6 +63,15 @@ array[2] = array[0] + array[1] return array[2] +def get_set_del_slice(l=list): + del l[:1] + del l[-1:] + del l[2:4] + l[:1] = [3] + l[-1:] = [9] + l[2:4] = [8,11] + return l[:2], l[5:], l[3:5] + def sieve_of_eratosthenes(): """Sieve of Eratosthenes Modified: pypy/trunk/src/pypy/translator/test/test_ctrans.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_ctrans.py (original) +++ pypy/trunk/src/pypy/translator/test/test_ctrans.py Tue Nov 23 13:39:32 2004 @@ -163,20 +163,26 @@ self.assertRaises(IndexError, bare_raise, range(0, 30, 10), False) self.assertEquals(bare_raise(range(0, 30, 10), True), None) + def test_get_set_del_slice(self): + fn = self.build_cfunc(snippet.get_set_del_slice) + l = list('abcdefghij') + result = fn(l) + self.assertEquals(l, [3, 'c', 8, 11, 'h', 9]) + self.assertEquals(result, ([3, 'c'], [9], [11, 'h'])) + class TypedTestCase(testit.IntTestCase): def getcompiled(self, func): - t = Translator(func) - t.simplify() -## # builds starting-types from func_defs -## argstypelist = [] -## if func.func_defaults: -## for spec in func.func_defaults: -## if isinstance(spec, tuple): -## spec = spec[0] # use the first type only for the tests -## argstypelist.append(spec) -## a = t.annotate(argstypelist) -## a.simplify() + t = Translator(func, simplifying=True) + # builds starting-types from func_defs + argstypelist = [] + if func.func_defaults: + for spec in func.func_defaults: + if isinstance(spec, tuple): + spec = spec[0] # use the first type only for the tests + argstypelist.append(spec) + a = t.annotate(argstypelist) + a.simplify() return t.ccompile() def test_set_attr(self): @@ -247,5 +253,12 @@ self.assertEquals(fn(4), 789) self.assertEquals(fn(5), 101112) + def test_get_set_del_slice(self): + fn = self.getcompiled(snippet.get_set_del_slice) + l = list('abcdefghij') + result = fn(l) + self.assertEquals(l, [3, 'c', 8, 11, 'h', 9]) + self.assertEquals(result, ([3, 'c'], [9], [11, 'h'])) + if __name__ == '__main__': testit.main() From arigo at codespeak.net Tue Nov 23 13:40:02 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 13:40:02 +0100 (MET) Subject: [pypy-svn] r7613 - pypy/trunk/src/pypy/translator Message-ID: <20041123124002.556E35B018@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 13:40:01 2004 New Revision: 7613 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: It is an important invariant that annotations should only ever be generalized, and not made more specialized for any given variable. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 23 13:40:01 2004 @@ -151,6 +151,7 @@ def setbinding(self, arg, s_value, called_from=None): if arg in self.bindings: + assert s_value.contains(self.bindings[arg]) # for debugging purposes, record the history of bindings that # have been given to this variable history = self.bindingshistory.setdefault(arg, []) From mgedmin at codespeak.net Tue Nov 23 13:40:55 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 13:40:55 +0100 (MET) Subject: [pypy-svn] r7614 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041123124055.9CC8F5B01B@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 13:40:55 2004 New Revision: 7614 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Show attribute values once again in class graphs. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Tue Nov 23 13:40:55 2004 @@ -136,7 +136,8 @@ label=repr(cdef.cls)) attrs = cdef.attrs.items() attrs.sort() - for name, s_value in attrs: + for name, attrdef in attrs: + s_value = attrdef.getvalue() dotgen.emit_node(name, shape="box", label=nottoowide(s_value)) dotgen.emit_edge(nameof(cdef), name, label=name) From tismer at codespeak.net Tue Nov 23 13:41:48 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 13:41:48 +0100 (MET) Subject: [pypy-svn] r7615 - pypy/trunk/src/pypy/translator Message-ID: <20041123124148.074EE5B01E@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 13:41:47 2004 New Revision: 7615 Added: pypy/trunk/src/pypy/translator/genrpy.py Log: initial rough version of a Python to RPython code generator. A lot more has to be done. But at least it creates almost correct looking code. TODO: subclass translator and flow space for the unrpythonic case Added: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 23 13:41:47 2004 @@ -0,0 +1,256 @@ +from pypy.objspace.flow.model import traverse +from pypy.objspace.flow import FlowObjSpace +from pypy.objspace.flow.model import FunctionGraph, Block, Link, Variable, Constant +from pypy.objspace.flow.model import last_exception, last_exc_value +from pypy.translator.simplify import simplify_graph +from pypy.interpreter.error import OperationError + +from pypy.translator.translator import Translator + +import sys + +def somefunc(arg): + pass + +def f(a,b): + print "start" + a = [] + a.append(3) + for i in range(3): + print i + if a > b: + try: + if b == 123: + raise ValueError + elif b == 321: + raise IndexError + return 123 + except ValueError: + raise TypeError + else: + dummy = somefunc(23) + return 42 + +def ff(a, b): + try: + raise SystemError, 42 + return a+b + finally: + a = 7 + +glob = 100 +def fff(): + global glob + return 42+glob + +def app_str_decode__String_ANY_ANY(str, encoding=None, errors=None): + if encoding is None and errors is None: + return unicode(str) + elif errors is None: + return unicode(str, encoding) + else: + return unicode(str, encoding, errors) + + +def ordered_blocks(graph): + # collect all blocks + allblocks = [] + def visit(block): + if isinstance(block, Block): + # first we order by offset in the code string + if block.operations: + ofs = block.operations[0].offset + else: + ofs = sys.maxint + # then we order by input variable name or value + if block.inputargs: + txt = str(block.inputargs[0]) + else: + txt = "dummy" + allblocks.append((ofs, txt, block)) + traverse(visit, graph) + allblocks.sort() + #for ofs, txt, block in allblocks: + # print ofs, txt, block + return [block for ofs, txt, block in allblocks] + + +class GenRpy: + def __init__(self, f, translator): + self.f = f + self.translator = translator + self.rpynames = {} + + # special constructors: + self.has_listarg = {} + for name in "newtuple newlist newdict newstring".split(): + self.has_listarg[name] = name + + def nameof(self, obj): + key = Constant(obj).key + try: + return self.rpynames[key] + except KeyError: + name = "w(%s)" % str(obj) + self.rpynames[key] = name + return name + + def gen_rpyfunction(self, func): + + local_names = {} + + def expr(v, wrapped = True): + if isinstance(v, Variable): + n = v.name + if n.startswith("v") and n[1:].isdigit(): + ret = local_names.get(v.name) + if not ret: + if wrapped: + local_names[v.name] = ret = "w_%d" % len(local_names) + else: + local_names[v.name] = ret = "v%d" % len(local_names) + return ret + return v.name + elif isinstance(v, Constant): + return self.nameof(v.value) + else: + #raise TypeError, "expr(%r)" % (v,) + # XXX how do I resolve these? + return "space.%s" % str(v) + + def arglist(args): + res = [expr(arg) for arg in args] + return ", ".join(res) + + def oper(op): + # specialcase is_true + if op.opname in self.has_listarg: + fmt = "%s = %s([%s])" + else: + fmt = "%s = %s(%s)" + if op.opname == "is_true": + return fmt % (expr(op.result, False), expr(op.opname), arglist(op.args)) + return fmt % (expr(op.result), expr(op.opname), arglist(op.args)) + + def gen_link(link, linklocalvars=None): + "Generate the code to jump across the given Link." + linklocalvars = linklocalvars or {} + left, right = [], [] + for a1, a2 in zip(link.args, link.target.inputargs): + if a1 in linklocalvars: + src = linklocalvars[a1] + else: + src = expr(a1) + left.append(expr(a2)) + right.append(src) + yield "%s = %s" % (", ".join(left), ", ".join(right)) + goto = blocknum[link.target] + yield 'goto = %d' % goto + if goto <= blocknum[block]: + yield 'continue' + + f = self.f + t = self.translator + t.simplify(func, rpython=False) + graph = t.getflowgraph(func) + + start = graph.startblock + blocks = ordered_blocks(graph) + nblocks = len(blocks) + assert blocks[0] is start + + blocknum = {} + for block in blocks: + blocknum[block] = len(blocknum)+1 + + # create function declaration + name = func.__name__ # change this + args = [expr(var) for var in start.inputargs] + argstr = ", ".join(args) + print >> f, "def %s(space, %s):" % (name, argstr) + print >> f, " w = space.wrap" + print >> f, " goto = 1 # startblock" + print >> f, " while True:" + + def render_block(block): + catch_exception = block.exitswitch == Constant(last_exception) + regular_op = len(block.operations) - catch_exception + # render all but maybe the last op + for op in block.operations[:regular_op]: + yield "%s" % oper(op) + # render the last op if it is exception handled + for op in block.operations[regular_op:]: + yield "try:" + yield " %s" % oper(op) + + if len(block.exits) == 0: + if len(block.inputargs) == 2: # exc_cls, exc_value + # exceptional return block + exc_cls = expr(block.inputargs[0]) + exc_val = expr(block.inputargs[1]) + yield "raise OperationError(%s, %s)" % (exc_cls, exc_val) + else: + # regular return block + retval = expr(block.inputargs[0]) + yield"return %s" % retval + return + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for op in gen_link(block.exits[0]): + yield " %s" % op + elif catch_exception: + # block catching the exceptions raised by its last operation + # we handle the non-exceptional case first + link = block.exits[0] + assert link.exitcase is None + for op in gen_link(link): + yield " %s" % op + # we must catch the exception raised by the last operation, + # which goes to the last err%d_%d label written above. + yield "except OperationError, e:" + for link in block.exits[1:]: + assert issubclass(link.exitcase, Exception) + for op in gen_link(link, { + Constant(last_exception): 'e.w_type', + Constant(last_exc_value): 'e.w_value'}): + yield " %s" % op + else: + # block ending in a switch on a value + exits = list(block.exits) + if len(exits) == 2 and ( + exits[0].exitcase is False and exits[1].exitcase is True): + # order these guys like Python does + exits.reverse() + q = "if" + for link in exits[:-1]: + yield "%s %s == %s:" % (q, expr(block.exitswitch), + link.exitcase) + for op in gen_link(link): + yield " %s" % op + q = "elif" + link = exits[-1] + yield "else:" + yield " assert %s == %s" % (expr(block.exitswitch), + link.exitcase) + for op in gen_link(exits[-1]): + yield " %s" % op + + for block in blocks: + blockno = blocknum[block] + print >> f + print " if goto == %d:" % blockno + for line in render_block(block): + print " %s" % line + +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [0] + +t = Translator(entry_point, verbose=False, simplifying=False) +#t.simplify(rpython=False) +#t.view() +gen = GenRpy(sys.stdout, t) +gen.gen_rpyfunction(t.functions[0]) +# debugging +graph = t.getflowgraph() +ab = ordered_blocks(graph) # use ctrl-b in PyWin with ab + From tismer at codespeak.net Tue Nov 23 15:19:53 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 15:19:53 +0100 (MET) Subject: [pypy-svn] r7617 - pypy/trunk/src/pypy/translator Message-ID: <20041123141953.4ED1B5B01F@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 15:19:52 2004 New Revision: 7617 Modified: pypy/trunk/src/pypy/translator/genrpy.py Log: added a few lines of more or less useless docs Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 23 15:19:52 2004 @@ -1,3 +1,18 @@ +""" +Implementation of a translator from Python to interpreter level RPython. + +The idea is that we can automatically transform app-space implementations +of methods into some equivalent representation at interpreter level. +Then, the RPython to C translation might hopefully spit out some +more efficient code than always interpreting these methods. + +This module is very much under construction and not yet usable but +for testing. + +XXX to do: Subclass parts of the flow space and translator and teach +them that this is not to be treated as RPython. +""" + from pypy.objspace.flow.model import traverse from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import FunctionGraph, Block, Link, Variable, Constant From mwh at codespeak.net Tue Nov 23 15:43:51 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 15:43:51 +0100 (MET) Subject: [pypy-svn] r7618 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041123144351.A8E495B011@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 15:43:51 2004 New Revision: 7618 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: I don't *think* we really want to call getvalue() here. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Tue Nov 23 15:43:51 2004 @@ -137,7 +137,7 @@ attrs = cdef.attrs.items() attrs.sort() for name, attrdef in attrs: - s_value = attrdef.getvalue() + s_value = attrdef.s_value dotgen.emit_node(name, shape="box", label=nottoowide(s_value)) dotgen.emit_edge(nameof(cdef), name, label=name) From bob at codespeak.net Tue Nov 23 15:52:22 2004 From: bob at codespeak.net (bob at codespeak.net) Date: Tue, 23 Nov 2004 15:52:22 +0100 (MET) Subject: [pypy-svn] r7620 - pypy/trunk/src/pypy/translator Message-ID: <20041123145222.B8C725B024@thoth.codespeak.net> Author: bob Date: Tue Nov 23 15:52:22 2004 New Revision: 7620 Modified: pypy/trunk/src/pypy/translator/genc.h Log: implement OP_GETSLICE and OP_ALLOC_AND_SET, hopefully correctly :) Modified: pypy/trunk/src/pypy/translator/genc.h ============================================================================== --- pypy/trunk/src/pypy/translator/genc.h (original) +++ pypy/trunk/src/pypy/translator/genc.h Tue Nov 23 15:52:22 2004 @@ -111,6 +111,31 @@ #define OP_NEWSLICE(x,y,z,r,err) if (!(r=PySlice_New(x,y,z))) FAIL(err) +#define AS_LONG(x) PyInt_AsLong(x) + +#define FAIL_IF_ERR(r,err) \ + if (PyErr_Occurred()) { \ + r = NULL; \ + FAIL(err) \ + } + +#define OP_GETSLICE(x,y,z,r,err) { \ + int __y = (y == Py_None) ? 0 : AS_LONG(y); \ + int __z = (z == Py_None) ? PyInt_GetMax() : AS_LONG(z); \ + FAIL_IF_ERR(r,err) \ + if (!(r=PySequence_GetSlice(x, __y, __z))) FAIL(err) \ + } + +#define OP_ALLOC_AND_SET(x,y,r,err) { \ + int __i, __x = AS_LONG(x); \ + FAIL_IF_ERR(r,err) \ + if (!(r = PyList_New(__x))) FAIL(err) \ + for (__i=0; __i<__x; __i++) { \ + Py_INCREF(y); \ + PyList_SET_ITEM(r, __i, y); \ + } \ + } + #define OP_ITER(x,r,err) if (!(r=PyObject_GetIter(x))) FAIL(err) #define OP_NEXT(x,r,err) if (!(r=PyIter_Next(x))) { \ if (!PyErr_Occurred()) PyErr_SetNone(PyExc_StopIteration); \ From mwh at codespeak.net Tue Nov 23 16:01:29 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 16:01:29 +0100 (MET) Subject: [pypy-svn] r7622 - pypy/trunk/src/pypy/annotation Message-ID: <20041123150129.692305B02A@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 16:01:28 2004 New Revision: 7622 Modified: pypy/trunk/src/pypy/annotation/model.py Log: Kill some dead code, be a bit more anal about whitespace. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue Nov 23 16:01:28 2004 @@ -36,6 +36,7 @@ from pypy.tool.cache import Cache import inspect + class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" @@ -75,11 +76,13 @@ caused_by_merge = property(caused_by_merge, set_caused_by_merge) del set_caused_by_merge + class SomeNone(SomeObject): "Stands for None." knowntype = type(None) const = None + class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." knowntype = int @@ -87,6 +90,7 @@ self.nonneg = nonneg self.unsigned = unsigned # pypy.objspace.std.restricted_int.r_uint + class SomeBool(SomeInteger): "Stands for true or false." knowntype = bool @@ -95,13 +99,16 @@ def __init__(self): pass + class SomeString(SomeObject): "Stands for an object which is known to be a string." knowntype = str + class SomeChar(SomeString): "Stands for an object known to be a string of length 1." + class SomeList(SomeObject): "Stands for a homogenous list of any length." knowntype = list @@ -109,6 +116,7 @@ self.factories = factories self.s_item = s_item # general enough for any element + class SomeTuple(SomeObject): "Stands for a tuple of known length." knowntype = tuple @@ -120,6 +128,7 @@ else: self.const = tuple([i.const for i in items]) + class SomeDict(SomeObject): "Stands for a dict with known keys." knowntype = dict @@ -127,18 +136,13 @@ self.factories = factories self.items = items # dict {realkey: s_value} + class SomeIterator(SomeObject): "Stands for an iterator returning objects of a known type." knowntype = type(iter([])) # arbitrarily chose seqiter as the type def __init__(self, s_item=SomeObject()): self.s_item = s_item -#class SomeClass(SomeObject): -# "Stands for a user-defined class object." -# # only used when the class object is loaded in a variable -# knowntype = ClassType -# def __init__(self, cls): -# self.cls = cls class SomeInstance(SomeObject): "Stands for an instance of a (user-defined) class." @@ -147,6 +151,7 @@ self.knowntype = classdef.cls self.revision = classdef.revision + class SomeCallable(SomeObject): """Stands for a (callable) function, method, prebuiltconstant or class""" @@ -158,6 +163,7 @@ if len(callables) == 1: self.const, = callables + class SomeBuiltin(SomeCallable): "Stands for a built-in function or method with special-cased analysis." knowntype = BuiltinFunctionType # == BuiltinMethodType @@ -165,30 +171,16 @@ self.analyser = analyser self.s_self = s_self -#class SomeFunction(SomeObject): -# """Stands for a Python function (or some function out of a list). -# Alternatively, it can be a constant bound or unbound method.""" -# knowntype = FunctionType -# def __init__(self, funcs): -# self.funcs = funcs # set of functions that this one may be -# if len(funcs) == 1: -# self.const, = funcs - -#class SomeMethod(SomeObject): -# "Stands for a bound Python method (or some method out of a list)." -# knowntype = MethodType -# def __init__(self, meths): -# self.meths = meths # map {python_function: classdef} - class SomePBC(SomeObject): """Stands for a global user instance, built prior to the analysis, or a set of such instances.""" def __init__(self, prebuiltinstances): self.prebuiltinstances = prebuiltinstances - self.knowntype = reduce(commonbase, + self.knowntype = reduce(commonbase, [x.__class__ for x in prebuiltinstances]) + class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that will never show up at run-time, e.g. elements of an empty list.""" @@ -221,7 +213,7 @@ return d def commonbase(cls1, cls2): # XXX single inheritance only XXX hum - l1 = inspect.getmro(cls1) + l1 = inspect.getmro(cls1) l2 = inspect.getmro(cls2) if l1[-1] != object: l1 = l1 + (object,) From tismer at codespeak.net Tue Nov 23 16:08:40 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 16:08:40 +0100 (MET) Subject: [pypy-svn] r7623 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20041123150840.89A7A5B036@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 16:08:40 2004 New Revision: 7623 Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py Log: added a flag to the class to behave different in appflow. Modified: pypy/trunk/src/pypy/objspace/flow/objspace.py ============================================================================== --- pypy/trunk/src/pypy/objspace/flow/objspace.py (original) +++ pypy/trunk/src/pypy/objspace/flow/objspace.py Tue Nov 23 16:08:40 2004 @@ -20,6 +20,8 @@ """ full_exceptions = False + + resolve_constants = True # used by the appflowspace def initialize(self): import __builtin__ @@ -302,7 +304,7 @@ def generic_operator(self, *args_w): assert len(args_w) == arity, name+" got the wrong number of arguments" - if op: + if op and (self.resolve_constants or self.concrete_mode): args = [] for w_arg in args_w: try: From hpk at codespeak.net Tue Nov 23 16:45:44 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 16:45:44 +0100 (MET) Subject: [pypy-svn] r7624 - pypy/trunk/src/pypy/translator Message-ID: <20041123154544.82EE95B037@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 16:45:44 2004 New Revision: 7624 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: continue even if blocks are blocked (but warn as if anyone would notice any warnings anyway) Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 23 16:45:44 2004 @@ -130,8 +130,12 @@ traceback.print_exception(*self.why_not_annotated[block]) print '-+' * 30 print - raise AnnotatorError('%d blocks are still blocked' % + print "++-" * 20 + print ('%d blocks are still blocked' % self.annotated.values().count(False)) + print "continuing anyway ...." + print "++-" * 20 + def binding(self, arg, in_link=None): "Gives the SomeValue corresponding to the given Variable or Constant." From hpk at codespeak.net Tue Nov 23 16:50:03 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 16:50:03 +0100 (MET) Subject: [pypy-svn] r7625 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20041123155003.A390B5B038@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 16:50:03 2004 New Revision: 7625 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: made "isinstance" and "is" more "clever" about preserving knowntypedata. added a couple of tests which illustrate that e.g. if x is None: # in this branch the annotator will know # that x is really None Accordingly made generalizitation of SomeBool()s a bit more smarter so that they preserve knowntypedata across generalization and even receive it for constant cases (because a SomeBool(const=True) could be generalized after a reflow so the knowntypedata information is still useful even thought it doesn't appear to be) Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 16:50:03 2004 @@ -98,40 +98,24 @@ return SomeBool() def is_((obj1, obj2)): - const = None - vararg = None - if obj1.is_constant(): - const = obj1 - var = obj2 - vararg = 1 + # XXX assumption: for "X is Y" we for simplification + # assume that X is possibly variable and Y constant + # (and not the other way round) + r = SomeBool() if obj2.is_constant(): - if const is not None: - return immutablevalue(obj1.const is obj2.const) - # we are in the case "SomeXXX is None" here - if obj2.const is None and obj1.__class__ != SomeObject: - return immutablevalue(False) - const = obj2 - var = obj1 - vararg = 0 - if const is not None: - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - fn, block, i = getbookkeeper().position_key - annotator = getbookkeeper().annotator - op = block.operations[i] - assert op.opname == "is_" - assert len(op.args) == 2 - assert annotator.binding(op.args[vararg]) is var - assert annotator.binding(op.args[1-vararg]).const is const.const - r = SomeBool() - r.knowntypedata = (op.args[vararg], const) - return r - - return SomeBool() - + if obj1.is_constant(): + r.const = obj1.const is obj2.const + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + fn, block, i = getbookkeeper().position_key + annotator = getbookkeeper().annotator + op = block.operations[i] + assert op.opname == "is_" + assert len(op.args) == 2 + assert annotator.binding(op.args[0]) == obj1 + r.knowntypedata = (op.args[0], obj2) + return r class __extend__(pairtype(SomeInteger, SomeInteger)): # unsignedness is considered a rare and contagious disease @@ -153,8 +137,16 @@ class __extend__(pairtype(SomeBool, SomeBool)): def union((boo1, boo2)): - return SomeBool() - + s = SomeBool() + if getattr(boo1, 'const', -1) == getattr(boo2, 'const', -2): + s.const = boo1.const + if hasattr(boo1, 'knowntypedata') and \ + hasattr(boo2, 'knowntypedata') and \ + boo1.knowntypedata[0] == boo2.knowntypedata[0]: + s.knowntypedata = ( + boo1.knowntypedata[0], + unionof(boo1.knowntypedata[1], boo2.knowntypedata[1])) + return s class __extend__(pairtype(SomeString, SomeString)): Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Tue Nov 23 16:50:03 2004 @@ -40,35 +40,31 @@ return cls2 is object or issubclass(cls1, cls2) def builtin_isinstance(s_obj, s_type): + s = SomeBool() if s_type.is_constant(): typ = s_type.const # XXX bit of a hack: if issubclass(typ, (int, long)): typ = int if s_obj.is_constant(): - return immutablevalue(isinstance(s_obj.const, typ)) + s.const = isinstance(s_obj.const, typ) elif our_issubclass(s_obj.knowntype, typ): - return immutablevalue(True) + s.const = True elif not our_issubclass(typ, s_obj.knowntype): - return immutablevalue(False) - else: - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - # XXX HACK HACK HACK - bk = getbookkeeper() - fn, block, i = bk.position_key - annotator = bk.annotator - op = block.operations[i] - assert op.opname == "simple_call" - assert len(op.args) == 3 - assert op.args[0] == Constant(isinstance) - assert annotator.binding(op.args[1]) is s_obj - r = SomeBool() - r.knowntypedata = (op.args[1], bk.valueoftype(typ)) - return r - return SomeBool() + s.const = False + # XXX HACK HACK HACK + # XXX HACK HACK HACK + # XXX HACK HACK HACK + bk = getbookkeeper() + fn, block, i = bk.position_key + annotator = bk.annotator + op = block.operations[i] + assert op.opname == "simple_call" + assert len(op.args) == 3 + assert op.args[0] == Constant(isinstance) + assert annotator.binding(op.args[1]) is s_obj + s.knowntypedata = (op.args[1], bk.valueoftype(typ)) + return s def builtin_issubclass(s_cls1, s_cls2): if s_cls1.is_constant() and s_cls2.is_constant(): Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 16:50:03 2004 @@ -268,6 +268,8 @@ assert isinstance(func, FunctionType), "expected function, got %r"%func # do we need to specialize this function in several versions? x = getattr(func, '_specialize_', False) + #if not x: + # x = 'argtypes' if x: if x == 'argtypes': key = short_type_name(args) Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 23 16:50:03 2004 @@ -492,7 +492,7 @@ def flow_identity_info(x=object, y=object): if x is None: - if None is y: + if y is None: return (x, y) else: return (x, None) @@ -623,3 +623,16 @@ else: x = apbc return x.answer + + +def is_and_knowntype(x): + if x is None: + return x + else: + return None + +def isinstance_and_knowntype(x): + if isinstance(x, APBC): + return x + else: + return apbc Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 16:50:03 2004 @@ -341,6 +341,21 @@ self.assertEquals(s, annmodel.SomeInteger(nonneg=True)) #self.assertEquals(s.__class__, annmodel.SomeInteger) + def test_is_and_knowntype_data(self): + a = RPythonAnnotator() + s = a.build_types(snippet.is_and_knowntype, [bool]) + #a.simplify() + #a.translator.view() + self.assert_(isinstance(s, annmodel.SomeNone)) + + def test_isinstance_and_knowntype_data(self): + a = RPythonAnnotator() + x = annmodel.SomePBC({snippet.apbc: True}) + s = a.build_types(snippet.isinstance_and_knowntype, [x]) + #a.simplify() + #a.translator.view() + self.assertEquals(s, x) + def g(n): return [0,1,2,n] From arigo at codespeak.net Tue Nov 23 16:51:14 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 16:51:14 +0100 (MET) Subject: [pypy-svn] r7626 - pypy/trunk/src/goal Message-ID: <20041123155114.7698E5B039@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 16:51:13 2004 New Revision: 7626 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Added the url of TCC. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 23 16:51:13 2004 @@ -12,6 +12,7 @@ --not-mark-some-objects Mark all functions that have SomeObject in their signature. -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' + -- http://fabrice.bellard.free.fr/tcc/ """ import autopath, sys, threading, pdb, os from pypy.objspace.std.objspace import StdObjSpace, W_Object From tismer at codespeak.net Tue Nov 23 17:19:31 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 17:19:31 +0100 (MET) Subject: [pypy-svn] r7627 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041123161931.5D0AA5B027@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 17:19:30 2004 New Revision: 7627 Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py Log: had to escape some more attributes. Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Tue Nov 23 17:19:30 2004 @@ -54,7 +54,7 @@ weight="5", ): d = locals() - attrs = [('%s="%s"' % (x, d[x])) + attrs = [('%s="%s"' % (x, d[x].replace('"', '\\"'))) for x in ['label', 'style', 'color', 'dir', 'weight']] self.emit('edge [%s];' % ", ".join(attrs)) self.emit('%s -> %s' % (name1, name2)) @@ -67,7 +67,7 @@ style="filled", ): d = locals() - attrs = [('%s="%s"' % (x, d[x])) + attrs = [('%s="%s"' % (x, d[x].replace('"', '\\"'))) for x in ['shape', 'label', 'color', 'fillcolor', 'style']] self.emit('%s [%s];' % (name, ", ".join(attrs))) From mwh at codespeak.net Tue Nov 23 18:02:39 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 18:02:39 +0100 (MET) Subject: [pypy-svn] r7628 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20041123170239.664935B03A@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 18:02:38 2004 New Revision: 7628 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Right code, wrong place: bye bye CallableFactory, SomeCallable. We're well on the way to svn mv factory.py bookkeeper.py as the functionality of CallableFactory is now contained in the Bookkeeper class. SomeCallable is borged with SomePBC. There's a lot of fairly mindless refactoring associated with this. genpyrex is currently broken. Probably shallow. Add assertions that SomeBuiltins are never merged. Teach annotator about list.pop, list.insert. This possibly should be a separate commit, but I'm too lazy for that. diff gets rather the wrong idea about unaryop.py and factory.py. What can you do? Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 18:02:38 2004 @@ -6,8 +6,7 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance, SomeCallable -from pypy.annotation.model import SomeBuiltin, SomeIterator +from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeIterator from pypy.annotation.model import SomePBC from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import generalize, isclassdef, getbookkeeper @@ -269,25 +268,27 @@ def union((bltn1, bltn2)): if bltn1.analyser != bltn2.analyser: + assert False, "merging incompatible builtins == BAD!" return SomeObject() else: s_self = unionof(bltn1.s_self, bltn2.s_self) return SomeBuiltin(bltn1.analyser, s_self) -class __extend__(pairtype(SomeCallable, SomeCallable)): - - def union((cal1, cal2)): - d = cal1.callables.copy() - for cal, classdef in cal2.callables.items(): - if cal in d: - if bool(isclassdef(classdef)) ^ bool(isclassdef(d[cal])): +class __extend__(pairtype(SomePBC, SomePBC)): + def union((pbc1, pbc2)): + if isinstance(pbc1, SomeBuiltin) or isinstance(pbc2, SomeBuiltin): + assert False, "merging builtin & PBC == BAD!" + d = pbc1.prebuiltinstances.copy() + for x, classdef in pbc2.prebuiltinstances.items(): + if x in d: + if bool(isclassdef(classdef)) ^ bool(isclassdef(d[x])): raise Exception( "union failed for %r with classdefs %r and %r" % - (cal, classdef, d[cal])) + (x, classdef, d[x])) if isclassdef(classdef): - classdef = classdef.commonbase(d[cal]) - d[cal] = classdef - return SomeCallable(d) + classdef = classdef.commonbase(d[x]) + d[x] = classdef + return SomePBC(d) class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): @@ -297,12 +298,6 @@ def union((obj1, imp2)): return obj1 - -class __extend__(pairtype(SomePBC, SomePBC)): - def union((pbc1, pbc2)): - return SomePBC(setunion(pbc1.prebuiltinstances, - pbc2.prebuiltinstances)) - class __extend__(pairtype(SomeInstance, SomePBC)): def union((ins, pbc)): classdef = ins.currentdef().superdef_containing(pbc.knowntype) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 18:02:38 2004 @@ -126,7 +126,7 @@ s_name = self.immutablevalue(x.__name__) result = s_self.getattr(s_name) else: - result = SomeCallable({x : True}) + result = SomePBC({x : True}) elif hasattr(x, '__class__') \ and x.__class__.__module__ != '__builtin__': if isinstance(x, Cache) and not x.frozen: @@ -158,77 +158,17 @@ t.__module__ != '__builtin__': classdef = self.getclassdef(t) if self.is_in_an_operation(): - # woha! instantiating a "mutable" SomeXxx like SomeInstance - # is always dangerous, because we need to record this fact - # in a factory, to allow reflowing from the current operation - # if/when the classdef later changes. - factory = self.getfactory(CallableFactory) - classdef.instancefactories[factory] = True + # woha! instantiating a "mutable" SomeXxx like + # SomeInstance is always dangerous, because we need to + # allow reflowing from the current operation if/when + # the classdef later changes. + classdef.instantiation_locations[self.position_key] = True return SomeInstance(classdef) else: o = SomeObject() o.knowntype = t return o -def getbookkeeper(): - """Get the current Bookkeeper. - Only works during the analysis of an operation.""" - return getthreadlocals().bookkeeper - - -# -# Factories -# - -def generalize(factories, *args): - modified = [factory for factory in factories if factory.generalize(*args)] - if modified: - for factory in modified: - factory.bookkeeper.annotator.reflowfromposition(factory.position_key) - raise BlockedInference # reflow now - -def isclassdef(x): - return isinstance(x, ClassDef) - -class ListFactory: - s_item = SomeImpossibleValue() - - def __repr__(self): - return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) - - def create(self): - return SomeList(factories = {self: True}, s_item = self.s_item) - - def generalize(self, s_new_item): - if not self.s_item.contains(s_new_item): - self.s_item = unionof(self.s_item, s_new_item) - return True - else: - return False - - -class DictFactory: - items = {} - - def __repr__(self): - return '%s(items=%r)' % (self.__class__.__name__, self.items) - - def create(self): - return SomeDict(factories = {self: True}, items = self.items) - - def generalize(self, key, s_new_value): - self.items = self.items.copy() - if key not in self.items: - self.items[key] = s_new_value - return True - elif not self.items[key].contains(s_new_value): - self.items[key] = unionof(self.items[key], s_new_value) - return True - else: - return False - - -class CallableFactory: def pycall(self, func, *args): if isinstance(func, (type, ClassType)) and \ func.__module__ != '__builtin__': @@ -241,12 +181,14 @@ raise Exception, \ "unsupported specialization type '%s'"%(x,) - classdef = self.bookkeeper.getclassdef(cls) - classdef.instancefactories[self] = True + classdef = self.getclassdef(cls) + classdef.instantiation_locations[self.position_key] = True s_instance = SomeInstance(classdef) # flow into __init__() if the class has got one init = getattr(cls, '__init__', None) if init is not None and init != object.__init__: + attrdef = classdef.find_attribute('__init__') + attrdef.getvalue() self.pycall(init, s_instance, *args) else: assert not args, "no __init__ found in %r" % (cls,) @@ -256,7 +198,7 @@ func = func.__call__ if hasattr(func, 'im_func'): if func.im_self is not None: - s_self = self.bookkeeper.immutablevalue(func.im_self) + s_self = self.immutablevalue(func.im_self) args = [s_self] + list(args) try: func.im_func.class_ = func.im_class @@ -286,24 +228,82 @@ func = self.specialize_by_key(func, len(args), name='%s__%d' % (func.func_name, len(args))) - return self.bookkeeper.annotator.recursivecall(func, self, *args) + return self.annotator.recursivecall(func, self.position_key, *args) def specialize_by_key(self, thing, key, name=None): key = thing, key try: - thing = self.bookkeeper.cachespecializations[key] + thing = self.cachespecializations[key] except KeyError: if isinstance(thing, FunctionType): # XXX XXX XXX HAAAAAAAAAAAACK - self.bookkeeper.annotator.translator.getflowgraph(thing) + self.annotator.translator.getflowgraph(thing) thing = func_with_new_name(thing, name or thing.func_name) elif isinstance(thing, (type, ClassType)): assert not "not working yet" thing = type(thing)(name or thing.__name__, (thing,)) else: raise Exception, "specializing %r?? why??"%thing - self.bookkeeper.cachespecializations[key] = thing + self.cachespecializations[key] = thing return thing + + +def getbookkeeper(): + """Get the current Bookkeeper. + Only works during the analysis of an operation.""" + return getthreadlocals().bookkeeper + + +# +# Factories +# + +def generalize(factories, *args): + modified = [factory for factory in factories if factory.generalize(*args)] + if modified: + for factory in modified: + factory.bookkeeper.annotator.reflowfromposition(factory.position_key) + raise BlockedInference # reflow now + +def isclassdef(x): + return isinstance(x, ClassDef) + +class ListFactory: + s_item = SomeImpossibleValue() + + def __repr__(self): + return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) + + def create(self): + return SomeList(factories = {self: True}, s_item = self.s_item) + + def generalize(self, s_new_item): + if not self.s_item.contains(s_new_item): + self.s_item = unionof(self.s_item, s_new_item) + return True + else: + return False + + +class DictFactory: + items = {} + + def __repr__(self): + return '%s(items=%r)' % (self.__class__.__name__, self.items) + + def create(self): + return SomeDict(factories = {self: True}, items = self.items) + + def generalize(self, key, s_new_value): + self.items = self.items.copy() + if key not in self.items: + self.items[key] = s_new_value + return True + elif not self.items[key].contains(s_new_value): + self.items[key] = unionof(self.items[key], s_new_value) + return True + else: + return False def short_type_name(args): l = [] @@ -353,7 +353,7 @@ self.bookkeeper = bookkeeper self.attrs = {} # {name: Attribute} self.revision = 0 # which increases the revision number - self.instancefactories = {} + self.instantiation_locations = {} self.cls = cls self.subdefs = {} assert (len(cls.__bases__) <= 1 or @@ -418,11 +418,11 @@ pending.append(sub) seen[sub] = True - def getallfactories(self): - factories = {} + def getallinstantiations(self): + locations = {} for clsdef in self.getallsubdefs(): - factories.update(clsdef.instancefactories) - return factories + locations.update(clsdef.instantiation_locations) + return locations def _generalize_attr(self, attr, s_value): # first remove the attribute from subclasses -- including us! @@ -444,8 +444,8 @@ self.attrs[attr] = newattr # reflow from all factories - for factory in self.getallfactories(): - self.bookkeeper.annotator.reflowfromposition(factory.position_key) + for position in self.getallinstantiations(): + self.bookkeeper.annotator.reflowfromposition(position) def generalize_attr(self, attr, s_value=None): # if the attribute exists in a superclass, generalize there. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue Nov 23 18:02:38 2004 @@ -151,20 +151,28 @@ self.knowntype = classdef.cls self.revision = classdef.revision +def new_or_old_class(c): + if hasattr(c, '__class__'): + return c.__class__ + else: + return type(c) -class SomeCallable(SomeObject): - """Stands for a (callable) function, method, - prebuiltconstant or class""" - def __init__(self, callables): - # callables is a dictionary containing concrete python - # callable objects as keys and - in the case of a method - - # the value contains the classdef (see SomeMethod below) - self.callables = callables - if len(callables) == 1: - self.const, = callables +class SomePBC(SomeObject): + """Stands for a global user instance, built prior to the analysis, + or a set of such instances.""" + def __init__(self, prebuiltinstances): + # prebuiltinstances is a dictionary containing concrete python + # objects as keys. + # if the key is a function, the value can be a classdef to + # indicate that it is really a method. + self.prebuiltinstances = prebuiltinstances + self.knowntype = reduce(commonbase, + [new_or_old_class(x) for x in prebuiltinstances]) + if len(prebuiltinstances) == 1: + self.const, = prebuiltinstances -class SomeBuiltin(SomeCallable): +class SomeBuiltin(SomePBC): "Stands for a built-in function or method with special-cased analysis." knowntype = BuiltinFunctionType # == BuiltinMethodType def __init__(self, analyser, s_self=None): @@ -172,15 +180,6 @@ self.s_self = s_self -class SomePBC(SomeObject): - """Stands for a global user instance, built prior to the analysis, - or a set of such instances.""" - def __init__(self, prebuiltinstances): - self.prebuiltinstances = prebuiltinstances - self.knowntype = reduce(commonbase, - [x.__class__ for x in prebuiltinstances]) - - class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that will never show up at run-time, e.g. elements of an empty list.""" Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 23 18:02:38 2004 @@ -8,11 +8,10 @@ from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin -from pypy.annotation.model import SomeCallable, SomeIterator -from pypy.annotation.model import SomePBC +from pypy.annotation.model import SomeIterator, SomePBC from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper -from pypy.annotation.factory import CallableFactory, isclassdef +from pypy.annotation.factory import isclassdef # convenience only! def immutablevalue(x): @@ -82,12 +81,18 @@ class __extend__(SomeList): - def method_append(lst, s_item): - pair(lst, SomeInteger()).setitem(s_item) + def method_append(lst, s_value): + pair(lst, SomeInteger()).setitem(s_value) def method_reverse(lst): pass + def method_insert(lst, s_index, s_value): + pair(lst, SomeInteger()).setitem(s_value) + + def method_pop(lst, s_index=None): + return lst.s_item + def iter(lst): return SomeIterator(lst.s_item) @@ -144,6 +149,7 @@ raise BlockedInference return + class __extend__(SomeBuiltin): def simple_call(bltn, *args): if bltn.s_self is not None: @@ -151,26 +157,44 @@ else: return bltn.analyser(*args) -class __extend__(SomeCallable): - def simple_call(cal, *args): - factory = getbookkeeper().getfactory(CallableFactory) + +class __extend__(SomePBC): + + def getattr(pbc, s_attr): + assert s_attr.is_constant() + attr = s_attr.const + actuals = [] + + for c in pbc.prebuiltinstances: + if hasattr(c, attr): + actuals.append(immutablevalue(getattr(c, attr))) + return unionof(*actuals) + + def setattr(pbc, s_attr, s_value): + #raise Exception, "oops!" + print "*** WARNING: setattr not wanted on %r" % pbc + pass + + def simple_call(pbc, *args): + bookkeeper = getbookkeeper() results = [] - for func, classdef in cal.callables.items(): + for func, classdef in pbc.prebuiltinstances.items(): if isclassdef(classdef): # create s_self and record the creation in the factory s_self = SomeInstance(classdef) - classdef.instancefactories[factory] = True - results.append(factory.pycall(func, s_self, *args)) + classdef.instantiation_locations[ + bookkeeper.position_key] = True + results.append(bookkeeper.pycall(func, s_self, *args)) else: - results.append(factory.pycall(func, *args)) + results.append(bookkeeper.pycall(func, *args)) return unionof(*results) - def bindcallables(cal, classdef): + def bindcallables(pbc, classdef): """ turn the callables in the given SomeCallable 'cal' into bound versions. """ - d = cal.callables.copy() - for func, value in cal.callables.items(): + d = {} + for func, value in pbc.prebuiltinstances.items(): if isinstance(func, FunctionType): if isclassdef(value): print ("!!! rebinding an already bound" @@ -180,27 +204,5 @@ d[func.__get__(43)] = value else: d[func] = value - return SomeCallable(d) - - #def simple_call(fun, *args): - # factory = getbookkeeper().getfactory(CallableFactory) - # results = [factory.pycall(func, *args) for func in fun.funcs] - # return unionof(*results) - - -class __extend__(SomePBC): + return SomePBC(d) - def getattr(pbc, s_attr): - assert s_attr.is_constant() - attr = s_attr.const - actuals = [] - - for c in pbc.prebuiltinstances: - if hasattr(c, attr): - actuals.append(immutablevalue(getattr(c, attr))) - return unionof(*actuals) - - def setattr(pbc, s_attr, s_value): - #raise Exception, "oops!" - print "*** WARNING: setattr not wanted on %r" % pbc - pass Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 23 18:02:38 2004 @@ -29,7 +29,7 @@ # records the location of BlockedInference # exceptions that blocked some blocks. self.blocked_functions = {} # set of functions that have blocked blocks - self.notify = {} # {block: {factory-to-invalidate-when-done}} + self.notify = {} # {block: {positions-to-reflow-from-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues self.binding_caused_by = {} # map Variables to Factories # records the FuncCallFactory that caused bindings of inputargs @@ -168,15 +168,15 @@ #___ interface for annotator.factory _______ - def recursivecall(self, func, factory, *args): - parent_fn, parent_block, parent_index = factory.position_key + def recursivecall(self, func, position_key, *args): + parent_fn, parent_block, parent_index = position_key graph = self.translator.getflowgraph(func, parent_fn, - factory.position_key) - # self.notify[graph.returnblock] is a dictionary of - # FuncCallFactories (call points to this func) which triggers a - # reflow whenever the return block of this graph has been analysed. - callfactories = self.notify.setdefault(graph.returnblock, {}) - callfactories[factory] = True + position_key) + # self.notify[graph.returnblock] is a dictionary of call + # points to this func which triggers a reflow whenever the + # return block of this graph has been analysed. + callpositions = self.notify.setdefault(graph.returnblock, {}) + callpositions[position_key] = True # generalize the function's input arguments block = graph.startblock inputcells = list(args) @@ -214,7 +214,7 @@ for extra in func.func_defaults[-missingargs:]: inputcells.append(self.bookkeeper.immutablevalue(extra)) inputcells.extend(extracells) - self.addpendingblock(func, block, inputcells, factory) + self.addpendingblock(func, block, inputcells, position_key) # get the (current) return value v = graph.getreturnvar() @@ -355,9 +355,9 @@ cells.append(cell) self.addpendingblock(fn, link.target, cells) if block in self.notify: - # invalidate some factories when this block is done - for factory in self.notify[block]: - self.reflowfromposition(factory.position_key) + # reflow from certain positions when this block is done + for position_key in self.notify[block]: + self.reflowfromposition(position_key) #___ creating the annotations based on operations ______ Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Tue Nov 23 18:02:38 2004 @@ -6,7 +6,7 @@ from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import mkentrymap, last_exception from pypy.translator.annrpython import RPythonAnnotator -from pypy.annotation.model import SomeCallable +#from pypy.annotation.model import SomeCallable from pypy.annotation.factory import isclassdef import inspect Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 18:02:38 2004 @@ -7,8 +7,6 @@ from pypy.translator.translator import Translator from pypy.objspace.flow.model import * -from pypy.annotation.model import SomeCallable - from pypy.translator.test import snippet class AnnonateTestCase(testit.IntTestCase): @@ -318,7 +316,7 @@ s = a.build_types(snippet.mergefunctions, [int]) # the test is mostly that the above line hasn't blown up # but let's at least check *something* - self.assert_(isinstance(s, SomeCallable)) + self.assert_(isinstance(s, annmodel.SomePBC)) def test_func_calls_func_which_just_raises(self): a = RPythonAnnotator() From hpk at codespeak.net Tue Nov 23 18:13:02 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 18:13:02 +0100 (MET) Subject: [pypy-svn] r7630 - pypy/trunk/src/pypy/annotation Message-ID: <20041123171302.73EF15B03E@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 18:13:01 2004 New Revision: 7630 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: release a restriction ... Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Tue Nov 23 18:13:01 2004 @@ -62,7 +62,7 @@ assert op.opname == "simple_call" assert len(op.args) == 3 assert op.args[0] == Constant(isinstance) - assert annotator.binding(op.args[1]) is s_obj + assert annotator.binding(op.args[1]) == s_obj s.knowntypedata = (op.args[1], bk.valueoftype(typ)) return s From hpk at codespeak.net Tue Nov 23 18:13:34 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 18:13:34 +0100 (MET) Subject: [pypy-svn] r7631 - pypy/trunk/src/pypy/annotation Message-ID: <20041123171334.7B3B85B045@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 18:13:34 2004 New Revision: 7631 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: union(SomeInstance, SomeInstance) return the newer revision in case they are talking about the same classdef Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 18:13:34 2004 @@ -254,10 +254,14 @@ class __extend__(pairtype(SomeInstance, SomeInstance)): def union((ins1, ins2)): + if ins1.classdef == ins2.classdef: + if ins1.revision > ins2.revision: + return ins1 + else: + return ins2 basedef = ins1.classdef.commonbase(ins2.classdef) return SomeInstance(basedef) - class __extend__(pairtype(SomeIterator, SomeIterator)): def union((iter1, iter2)): From arigo at codespeak.net Tue Nov 23 18:17:55 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 18:17:55 +0100 (MET) Subject: [pypy-svn] r7632 - pypy/trunk/src/pypy/translator Message-ID: <20041123171755.6C8DC5B042@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 18:17:54 2004 New Revision: 7632 Modified: pypy/trunk/src/pypy/translator/genpyrex.py Log: Adapted genpyrex.py to the lack of SomeCallables. Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Tue Nov 23 18:17:54 2004 @@ -6,7 +6,7 @@ from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import mkentrymap, last_exception from pypy.translator.annrpython import RPythonAnnotator -#from pypy.annotation.model import SomeCallable +from pypy.annotation.model import SomePBC from pypy.annotation.factory import isclassdef import inspect @@ -417,11 +417,11 @@ empty = True for attr, attrdef in cls.attrs.items(): s_value = attrdef.s_value - if isinstance(s_value, SomeCallable): - for py_fun,fun_class in s_value.callables.items(): - assert isclassdef(fun_class), ( - "%r must have a classdef" % py_fun) - delay_methods.setdefault(fun_class,[]).append(py_fun) + if isinstance(s_value, SomePBC): + for py_fun,fun_class in s_value.prebuiltinstances.items(): + assert isclassdef(fun_class), ("don't support " + "prebuilt constants like %r" % py_fun) + delay_methods.setdefault(fun_class,[]).append(py_fun) else: vartype=self._gettypename(s_value.knowntype) self.putline("cdef public %s %s" % (vartype, attr)) From hpk at codespeak.net Tue Nov 23 18:19:01 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 18:19:01 +0100 (MET) Subject: [pypy-svn] r7633 - pypy/trunk/src/pypy/translator Message-ID: <20041123171901.F159F5B019@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 18:19:01 2004 New Revision: 7633 Modified: pypy/trunk/src/pypy/translator/annrpython.py Log: yet another Exception becomes a warning Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue Nov 23 18:19:01 2004 @@ -208,9 +208,10 @@ expectedargs) else: msg = "%d" % expectedargs - raise AnnotatorError, ( + print ("!!! AnnotatorError, (ignored!!!)" "got %d inputcells in call to %r; expected %s" % ( len(inputcells), func, msg)) + return annmodel.SomeImpossibleValue() for extra in func.func_defaults[-missingargs:]: inputcells.append(self.bookkeeper.immutablevalue(extra)) inputcells.extend(extracells) From hpk at codespeak.net Tue Nov 23 18:26:39 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 23 Nov 2004 18:26:39 +0100 (MET) Subject: [pypy-svn] r7634 - pypy/trunk/src/pypy/annotation Message-ID: <20041123172639.75A605B04D@thoth.codespeak.net> Author: hpk Date: Tue Nov 23 18:26:38 2004 New Revision: 7634 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: added full support for longs, unicode and floats! Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Tue Nov 23 18:26:38 2004 @@ -35,6 +35,15 @@ def builtin_chr(s_int): return SomeChar() +def builtin_unicode(s_obj): + return SomeString() + +def builtin_float(s_obj): + return SomeObject() + +def builtin_long(s_str): + return SomeObject() + def our_issubclass(cls1, cls2): """ we're going to try to be less silly in the face of old-style classes""" return cls2 is object or issubclass(cls1, cls2) From mgedmin at codespeak.net Tue Nov 23 18:27:29 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 18:27:29 +0100 (MET) Subject: [pypy-svn] r7635 - pypy/trunk/src/goal Message-ID: <20041123172729.52CA15B06B@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 18:27:28 2004 New Revision: 7635 Modified: pypy/trunk/src/goal/translate_pypy.py Log: s/--not-mark-some-objects/-no-mark-some-objects/ for consistency with other arguments. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 23 18:27:28 2004 @@ -9,8 +9,8 @@ -no-c Don't generate the C code -c Generate the C code, but don't compile it -o Generate and compile the C code, but don't run it - --not-mark-some-objects - Mark all functions that have SomeObject in their signature. + -no-mark-some-objects + Do not mark functions that have SomeObject in their signature. -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' -- http://fabrice.bellard.free.fr/tcc/ """ @@ -50,7 +50,7 @@ a.simplify() t.frozen = True # cannot freeze if we don't have annotations - if not options['--not-mark-some-objects']: + if not options['-no-mark-some-objects']: find_someobjects(a) @@ -136,7 +136,7 @@ '-no-c': False, '-c': False, '-o': False, - '--not-mark-some-objects': False, + '-no-mark-some-objects': False, '-no-a': False, '-tcc': False, } From tismer at codespeak.net Tue Nov 23 18:30:08 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 18:30:08 +0100 (MET) Subject: [pypy-svn] r7636 - pypy/trunk/src/pypy/translator Message-ID: <20041123173008.4A8DE5B06C@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 18:30:07 2004 New Revision: 7636 Modified: pypy/trunk/src/pypy/translator/genrpy.py pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/translator.py Log: reverted my additions for an app-specific flow space. The current idea is: application level code is translated like RPython, in the sense that globals are constants, constants are evaluated at compile time, and the special exception provisions also apply. The difference with genrpy is this: genrpy code is generated when the space is NOT a constant. In a second step, genc generates C code from that, and the space IS a constant. Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 23 18:30:07 2004 @@ -6,11 +6,11 @@ Then, the RPython to C translation might hopefully spit out some more efficient code than always interpreting these methods. +Note that the appspace things are treated as RPythonic, in a sense +that globals are constant,for instance. + This module is very much under construction and not yet usable but for testing. - -XXX to do: Subclass parts of the flow space and translator and teach -them that this is not to be treated as RPython. """ from pypy.objspace.flow.model import traverse @@ -95,6 +95,7 @@ self.f = f self.translator = translator self.rpynames = {} + self.seennames = {} # special constructors: self.has_listarg = {} @@ -106,10 +107,355 @@ try: return self.rpynames[key] except KeyError: - name = "w(%s)" % str(obj) + #name = "w(%s)" % str(obj) + #self.rpynames[key] = name + #return name + if (type(obj).__module__ != '__builtin__' and + not isinstance(obj, type)): # skip user-defined metaclasses + # assume it's a user defined thingy + name = self.nameof_instance(obj) + else: + for cls in type(obj).__mro__: + meth = getattr(self, + 'nameof_' + cls.__name__.replace(' ', ''), + None) + if meth: + break + else: + raise Exception, "nameof(%r)" % (obj,) + name = meth(obj) self.rpynames[key] = name return name + def uniquename(self, basename): + n = self.seennames.get(basename, 0) + self.seennames[basename] = n+1 + if n == 0: + self.globalobjects.append(basename) + self.globaldecl.append('static PyObject *%s;' % (basename,)) + return basename + else: + return self.uniquename('%s_%d' % (basename, n)) + + def nameof_object(self, value): + if type(value) is not object: + raise Exception, "nameof(%r)" % (value,) + name = self.uniquename('g_object') + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) + return name + + def nameof_module(self, value): + assert value is os or not hasattr(value, "__file__") or \ + not (value.__file__.endswith('.pyc') or + value.__file__.endswith('.py') or + value.__file__.endswith('.pyo')), \ + "%r is not a builtin module (probably :)"%value + name = self.uniquename('mod%s'%value.__name__) + self.initcode.append('INITCHK(%s = PyImport_ImportModule("%s"))'%(name, value.__name__)) + return name + + + def nameof_int(self, value): + if value >= 0: + name = 'gint_%d' % value + else: + name = 'gint_minus%d' % abs(value) + name = self.uniquename(name) + self.initcode.append('INITCHK(%s = ' + 'PyInt_FromLong(%d))' % (name, value)) + return name + + def nameof_long(self, value): + assert type(int(value)) is int, "your literal long is too long" + if value >= 0: + name = 'glong%d' % value + else: + name = 'glong_minus%d' % abs(value) + name = self.uniquename(name) + self.initcode.append('INITCHK(%s = ' + 'PyLong_FromLong(%d))' % (name, value)) + return name + + def nameof_float(self, value): + name = 'gfloat_%s' % value + name = (name.replace('-', 'minus') + .replace('.', 'dot')) + chrs = [c for c in name if ('a' <= c <='z' or + 'A' <= c <='Z' or + '0' <= c <='9' or + '_' == c )] + name = ''.join(chrs) + name = self.uniquename(name) + self.initcode.append('INITCHK(%s = ' + 'PyFloat_FromDouble(%r))' % (name, value)) + return name + + def nameof_str(self, value): + chrs = [c for c in value[:32] if ('a' <= c <='z' or + 'A' <= c <='Z' or + '0' <= c <='9' or + '_' == c )] + name = self.uniquename('gstr_' + ''.join(chrs)) + if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']: + # non-printable string + s = 'chr_%s' % name + self.globaldecl.append('static char %s[] = { %s };' % ( + s, ', '.join(['%d' % ord(c) for c in value]))) + else: + # printable string + s = '"%s"' % value + self.initcode.append('INITCHK(%s = PyString_FromStringAndSize(' + '%s, %d))' % (name, s, len(value))) + return name + + def skipped_function(self, func): + # debugging only! Generates a placeholder for missing functions + # that raises an exception when called. + name = self.uniquename('gskippedfunc_' + func.__name__) + self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\tPy_INCREF(%s);' % name) + self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) + return name + + def nameof_function(self, func, progress=['-\x08', '\\\x08', + '|\x08', '/\x08']): + printable_name = '(%s:%d) %s' % ( + func.func_globals.get('__name__', '?'), + func.func_code.co_firstlineno, + func.__name__) + if self.translator.frozen: + if func not in self.translator.flowgraphs: + print "NOT GENERATING", printable_name + return self.skipped_function(func) + else: + if (func.func_doc and + func.func_doc.lstrip().startswith('NOT_RPYTHON')): + print "skipped", printable_name + return self.skipped_function(func) + p = progress.pop(0) + sys.stderr.write(p) + progress.append(p) + name = self.uniquename('gfunc_' + func.__name__) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) + self.pendingfunctions.append(func) + return name + + def nameof_staticmethod(self, sm): + # XXX XXX XXXX + func = sm.__get__(42.5) + name = self.uniquename('gsm_' + func.__name__) + functionname = self.nameof(func) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, functionname)) + return name + + def nameof_instancemethod(self, meth): + if meth.im_self is None: + # no error checking here + return self.nameof(meth.im_func) + else: + ob = self.nameof(meth.im_self) + func = self.nameof(meth.im_func) + typ = self.nameof(meth.im_class) + name = self.uniquename('gmeth_'+meth.im_func.__name__) + self.initcode.append( + 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( + name, func, ob, typ)) + return name + + def should_translate_attr(self, pbc, attr): + ann = self.translator.annotator + if ann is None: + ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', []) + if attr in ignore: + return False + else: + return "probably" # True + if attr in ann.getpbcattrs(pbc): + return True + classdef = ann.getuserclasses().get(pbc.__class__) + if (classdef and + classdef.about_attribute(attr) != annmodel.SomeImpossibleValue()): + return True + return False + + def later(self, gen): + self.latercode.append((gen, self.debugstack)) + + def nameof_instance(self, instance): + name = self.uniquename('ginst_' + instance.__class__.__name__) + cls = self.nameof(instance.__class__) + def initinstance(): + content = instance.__dict__.items() + content.sort() + for key, value in content: + if self.should_translate_attr(instance, key): + yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) + self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( + name, cls)) + self.later(initinstance()) + return name + + def nameof_builtin_function_or_method(self, func): + if func.__self__ is None: + # builtin function + # where does it come from? Python2.2 doesn't have func.__module__ + for modname, module in sys.modules.items(): + if hasattr(module, '__file__'): + if (module.__file__.endswith('.py') or + module.__file__.endswith('.pyc') or + module.__file__.endswith('.pyo')): + continue # skip non-builtin modules + if func is getattr(module, func.__name__, None): + break + else: + raise Exception, '%r not found in any built-in module' % (func,) + name = self.uniquename('gbltin_' + func.__name__) + if modname == '__builtin__': + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s"))' % ( + name, func.__name__)) + else: + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(module), func.__name__)) + else: + # builtin (bound) method + name = self.uniquename('gbltinmethod_' + func.__name__) + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(func.__self__), func.__name__)) + return name + + def nameof_classobj(self, cls): + if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): + raise Exception, "%r should never be reached" % (cls,) + + metaclass = "&PyType_Type" + if issubclass(cls, Exception): + if cls.__module__ == 'exceptions': + return 'PyExc_%s'%cls.__name__ + #else: + # # exceptions must be old-style classes (grr!) + # metaclass = "&PyClass_Type" + # For the moment, use old-style classes exactly when the + # pypy source uses old-style classes, to avoid strange problems. + if not isinstance(cls, type): + assert type(cls) is type(Exception) + metaclass = "&PyClass_Type" + + name = self.uniquename('gcls_' + cls.__name__) + basenames = [self.nameof(base) for base in cls.__bases__] + def initclassobj(): + content = cls.__dict__.items() + content.sort() + for key, value in content: + if key.startswith('__'): + if key in ['__module__', '__doc__', '__dict__', + '__weakref__', '__repr__', '__metaclass__']: + continue + # XXX some __NAMES__ are important... nicer solution sought + #raise Exception, "unexpected name %r in class %s"%(key, cls) + if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen: + print value + continue + if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: + print value + continue + + yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) + + baseargs = ", ".join(basenames) + if baseargs: + baseargs = ', '+baseargs + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) %s,' + %(name, metaclass)) + self.initcode.append('\t\t"s(%s){}", "%s"%s))' + %("O"*len(basenames), cls.__name__, baseargs)) + + self.later(initclassobj()) + return name + + nameof_class = nameof_classobj # for Python 2.2 + + + def nameof_type(self, cls): + if cls in self.typename_mapping: + return '(PyObject*) %s' % self.typename_mapping[cls] + assert cls.__module__ != '__builtin__', \ + "built-in class %r not found in typename_mapping" % (cls,) + return self.nameof_classobj(cls) + + def nameof_tuple(self, tup): + name = self.uniquename('g%dtuple' % len(tup)) + args = [self.nameof(x) for x in tup] + args.insert(0, '%d' % len(tup)) + args = ', '.join(args) + self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) + return name + + def nameof_list(self, lis): + name = self.uniquename('g%dlist' % len(lis)) + def initlist(): + for i in range(len(lis)): + item = self.nameof(lis[i]) + yield '\tPy_INCREF(%s);' % item + yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) + self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) + self.later(initlist()) + return name + + def nameof_dict(self, dic): + assert dic is not __builtins__ + assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( + dic.get('__name__', '?'),) + name = self.uniquename('g%ddict' % len(dic)) + def initdict(): + for k in dic: + if type(k) is str: + yield ('\tINITCHK(PyDict_SetItemString' + '(%s, "%s", %s) >= 0)'%( + name, k, self.nameof(dic[k]))) + else: + yield ('\tINITCHK(PyDict_SetItem' + '(%s, %s, %s) >= 0)'%( + name, self.nameof(k), self.nameof(dic[k]))) + self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) + self.later(initdict()) + return name + + # strange prebuilt instances below, don't look too closely + # XXX oh well. + def nameof_member_descriptor(self, md): + name = self.uniquename('gdescriptor_%s_%s' % ( + md.__objclass__.__name__, md.__name__)) + cls = self.nameof(md.__objclass__) + self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % + cls) + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + '((PyTypeObject*) %s)->tp_dict, "%s"))' % + (name, cls, md.__name__)) + return name + nameof_getset_descriptor = nameof_member_descriptor + nameof_method_descriptor = nameof_member_descriptor + nameof_wrapper_descriptor = nameof_member_descriptor + + def nameof_file(self, fil): + if fil is sys.stdin: + return 'PySys_GetObject("stdin")' + if fil is sys.stdout: + return 'PySys_GetObject("stdout")' + if fil is sys.stderr: + return 'PySys_GetObject("stderr")' + raise Exception, 'Cannot translate an already-open file: %r' % (fil,) + + def gen_rpyfunction(self, func): local_names = {} @@ -258,9 +604,11 @@ for line in render_block(block): print " %s" % line -entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [0] +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [2] t = Translator(entry_point, verbose=False, simplifying=False) +# hack: replace class + #t.simplify(rpython=False) #t.view() gen = GenRpy(sys.stdout, t) Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Tue Nov 23 18:30:07 2004 @@ -83,12 +83,11 @@ link.prevblock.exits = tuple(lst) traverse(visit, graph) -def simplify_graph(graph, rpython=True): +def simplify_graph(graph): """inplace-apply all the existing optimisations to the graph.""" checkgraph(graph) eliminate_empty_blocks(graph) - if rpython: - remove_implicit_exceptions(graph) + remove_implicit_exceptions(graph) join_blocks(graph) checkgraph(graph) Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Tue Nov 23 18:30:07 2004 @@ -111,14 +111,14 @@ from pypy.translator.tool.pygame.flowviewer import FlowGraphLayout FlowGraphLayout(self).display() - def simplify(self, func=None, rpython=True): + def simplify(self, func=None): """Simplifies the control flow graph (default: for all functions).""" if func is None: for func in self.flowgraphs.keys(): - self.simplify(func, rpython) + self.simplify(func) else: graph = self.getflowgraph(func) - simplify_graph(graph, rpython) + simplify_graph(graph) def annotate(self, input_args_types, func=None): """annotate(self, input_arg_types[, func]) -> Annotator From mgedmin at codespeak.net Tue Nov 23 18:31:16 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 18:31:16 +0100 (MET) Subject: [pypy-svn] r7637 - pypy/trunk/src/goal Message-ID: <20041123173116.6F2275B077@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 18:31:15 2004 New Revision: 7637 Modified: pypy/trunk/src/goal/translate_pypy.py Log: Mark functions that get or return SomeObject even when annotation fails. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 23 18:31:15 2004 @@ -50,13 +50,13 @@ a.simplify() t.frozen = True # cannot freeze if we don't have annotations - if not options['-no-mark-some-objects']: - find_someobjects(a) - -def find_someobjects(annotator): +def find_someobjects(translator): """Find all functions in that have SomeObject in their signature.""" - translator = annotator.translator + annotator = translator.annotator + if not annotator: + return # no annotations available + translator.highlight_functions = {} def is_someobject(var): @@ -178,6 +178,10 @@ from pypy.translator.tool.pygame.flowviewer import TranslatorLayout from pypy.translator.tool.pygame.graphdisplay import GraphDisplay import pygame + + if not options['-no-mark-some-objects']: + find_someobjects(t) + display = GraphDisplay(TranslatorLayout(t)) async_quit = display.async_quit return display.run, async_quit, pygame.quit From mgedmin at codespeak.net Tue Nov 23 18:37:10 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 18:37:10 +0100 (MET) Subject: [pypy-svn] r7638 - pypy/trunk/src/pypy/translator/tool Message-ID: <20041123173710.945F15B078@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 18:37:10 2004 New Revision: 7638 Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py Log: Fixed redundant quoting. Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/make_dot.py (original) +++ pypy/trunk/src/pypy/translator/tool/make_dot.py Tue Nov 23 18:37:10 2004 @@ -102,7 +102,7 @@ name = self.prefix # +'_'+funcgraph.name data = funcgraph.name if hasattr(funcgraph, 'source'): - source = funcgraph.source.replace('"', '\\"') + source = funcgraph.source data += "\\n" + "\\l".join(source.split('\n')) if hasattr(funcgraph, 'func'): self.func = funcgraph.func @@ -153,7 +153,6 @@ maxlineno, source) data = data + "\l".join(lines) - data = data.replace('"', '\\"') # make dot happy self.emit_node(name, label=data, shape=shape, color=color, style="filled", fillcolor=fillcolor) From mgedmin at codespeak.net Tue Nov 23 18:45:31 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 18:45:31 +0100 (MET) Subject: [pypy-svn] r7639 - pypy/trunk/src/goal Message-ID: <20041123174531.D23985B079@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 18:45:31 2004 New Revision: 7639 Modified: pypy/trunk/src/goal/translate_pypy.py Log: If annotation fails, mark functions with SomeObjects *quietly*, otherwise the traceback obscured. Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Tue Nov 23 18:45:31 2004 @@ -49,9 +49,12 @@ a = t.annotate([]) a.simplify() t.frozen = True # cannot freeze if we don't have annotations + if not options['-no-mark-some-objects']: + options['-no-mark-some-objects'] = True # Do not do this again + find_someobjects(t) -def find_someobjects(translator): +def find_someobjects(translator, quiet=False): """Find all functions in that have SomeObject in their signature.""" annotator = translator.annotator if not annotator: @@ -84,27 +87,31 @@ unknown_input_args = len(filter(is_someobject, graph.getargs())) unknown_return_value = is_someobject(graph.getreturnvar()) if unknown_input_args or unknown_return_value: - if header: - header = False - print "=" * 70 - print "Functions that have SomeObject in their signature" - print "=" * 70 - translator.highlight_functions[func] = True - print ("%(name)s(%(args)s) -> %(result)s\n" - "%(filename)s:%(lineno)s\n" - % {'name': graph.name, - 'filename': func.func_globals.get('__name__', '?'), - 'lineno': func.func_code.co_firstlineno, - 'args': ', '.join(map(short_binding, graph.getargs())), - 'result': short_binding(graph.getreturnvar())}) someobjnum += 1 + translator.highlight_functions[func] = True + if not quiet: + if header: + header = False + print "=" * 70 + print "Functions that have SomeObject in their signature" + print "=" * 70 + print ("%(name)s(%(args)s) -> %(result)s\n" + "%(filename)s:%(lineno)s\n" + % {'name': graph.name, + 'filename': func.func_globals.get('__name__', '?'), + 'lineno': func.func_code.co_firstlineno, + 'args': ', '.join(map(short_binding, + graph.getargs())), + 'result': short_binding(graph.getreturnvar())}) num += 1 - print "=" * 70 - percent = int(num and (100.0*someobjnum / num) or 0) - print "somobjectness: %2d percent" % (percent) - print "(%d out of %d functions get or return SomeObjects" % ( - someobjnum, num) - print "=" * 70 + if not quiet: + print "=" * 70 + percent = int(num and (100.0*someobjnum / num) or 0) + print "somobjectness: %2d percent" % (percent) + print "(%d out of %d functions get or return SomeObjects" % ( + someobjnum, num) + print "=" * 70 + def update_usession_dir(stabledir = udir.dirpath('usession')): from py import path @@ -180,7 +187,7 @@ import pygame if not options['-no-mark-some-objects']: - find_someobjects(t) + find_someobjects(t, quiet=True) display = GraphDisplay(TranslatorLayout(t)) async_quit = display.async_quit From arigo at codespeak.net Tue Nov 23 18:53:59 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 18:53:59 +0100 (MET) Subject: [pypy-svn] r7640 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20041123175359.6D13F5B067@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 18:53:58 2004 New Revision: 7640 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: SomePBC need to remove from their prebuiltinstances dicts all bound method objects that also appear as functions with a classdef. Otherwise, two PBCs can appear different by mistake: one with only a function+classdef and one with a function+classdef and also a redundant bound method. Added a test for this case. --This line, and those below, will be ignored-- M pypy/translator/test/test_annrpython.py M pypy/translator/test/snippet.py M pypy/annotation/model.py Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue Nov 23 18:53:58 2004 @@ -165,12 +165,25 @@ # objects as keys. # if the key is a function, the value can be a classdef to # indicate that it is really a method. - self.prebuiltinstances = prebuiltinstances + prebuiltinstances = prebuiltinstances.copy() + self.prebuiltinstances = prebuiltinstances + self.simplify() self.knowntype = reduce(commonbase, [new_or_old_class(x) for x in prebuiltinstances]) - if len(prebuiltinstances) == 1: + if prebuiltinstances.values() == [True]: + # hack for the convenience of direct callers to SomePBC(): + # only if there is a single object in prebuiltinstances and + # it doesn't have an associated ClassDef self.const, = prebuiltinstances - + def simplify(self): + # We check that the dictionary does not contain at the same time + # a function bound to a classdef, and constant bound method objects + # on that class. + for x, ignored in self.prebuiltinstances.items(): + if isinstance(x, MethodType) and x.im_func in self.prebuiltinstances: + classdef = self.prebuiltinstances[x.im_func] + if isinstance(x.im_self, classdef.cls): + del self.prebuiltinstances[x] class SomeBuiltin(SomePBC): "Stands for a built-in function or method with special-cased analysis." Modified: pypy/trunk/src/pypy/translator/test/snippet.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/snippet.py (original) +++ pypy/trunk/src/pypy/translator/test/snippet.py Tue Nov 23 18:53:58 2004 @@ -438,6 +438,14 @@ def global_instance(): return global_z.my_method() +def call_Z_my_method(z): + return z.my_method + +def somepbc_simplify(): + z = Z() + call_Z_my_method(global_z) + call_Z_my_method(z) + global_c = C() global_c.a = 1 Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Tue Nov 23 18:53:58 2004 @@ -352,7 +352,12 @@ s = a.build_types(snippet.isinstance_and_knowntype, [x]) #a.simplify() #a.translator.view() - self.assertEquals(s, x) + self.assertEquals(s, x) + + def test_somepbc_simplify(self): + a = RPythonAnnotator() + # this example used to trigger an AssertionError + a.build_types(snippet.somepbc_simplify, []) def g(n): return [0,1,2,n] From arigo at codespeak.net Tue Nov 23 18:57:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 18:57:58 +0100 (MET) Subject: [pypy-svn] r7641 - pypy/trunk/src/pypy/annotation Message-ID: <20041123175758.51B135B07A@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 18:57:57 2004 New Revision: 7641 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: don't raise BlockedInference from a union() method. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 18:57:57 2004 @@ -304,7 +304,7 @@ class __extend__(pairtype(SomeInstance, SomePBC)): def union((ins, pbc)): - classdef = ins.currentdef().superdef_containing(pbc.knowntype) + classdef = ins.classdef.superdef_containing(pbc.knowntype) if classdef is None: # print warning? return SomeObject() From mgedmin at codespeak.net Tue Nov 23 18:58:02 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 18:58:02 +0100 (MET) Subject: [pypy-svn] r7642 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041123175802.3E3F45B091@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 18:58:00 2004 New Revision: 7642 Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Added search for the previous occurrence (bound to p) in the graph viewer. This changes the binding of 'p' which used to be layout_back, I hope nobody minds that. Modified: pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/drawgraph.py Tue Nov 23 18:58:00 2004 @@ -448,23 +448,15 @@ for cmd in self.draw_commands(): cmd() - def _search_for(self, items, searchstr, start_at=None): - """Find an object that contains a search string.""" - it = iter(items) - if start_at is not None: - # Skip all items up to and including 'start_at' - for item in it: - if item is start_at: - break - for item in it: + def findall(self, searchstr): + """Return an iterator for all nodes and edges that contain a searchstr. + """ + for item in self.graphlayout.nodes.itervalues(): if item.label and searchstr in item.label: - return item - return None - - def search(self, searchstr, start_at=None): - """Find a node or an edge that contains a search string.""" - items = self.graphlayout.nodes.values() + self.graphlayout.edges - return self._search_for(items, searchstr, start_at) + yield item + for item in self.graphlayout.edges: + if item.label and searchstr in item.label: + yield item def at_position(self, (x, y)): """Figure out the word under the cursor.""" Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 23 18:58:00 2004 @@ -84,11 +84,11 @@ 'quit' : 'quit', 'meta right' : 'layout_forward', 'meta left': 'layout_back', - 'p' : 'layout_back', 'backspace' : 'layout_back', 'f': 'search', '/': 'search', 'n': 'find_next', + 'p': 'find_prev', 'left' : ('pan', (-1, 0)), 'right' : ('pan', (1, 0)), 'up' : ('pan', (0, -1)), @@ -117,6 +117,7 @@ F or / Search for text N Find next occurrence + P Find previous occurrence F1, H or ? This help message @@ -143,7 +144,8 @@ self.ascii_key_cache = {} self.status_bar_height = 0 self.searchstr = None - self.searchpos = None + self.searchpos = 0 + self.searchresults = [] self.initialize_keys() self.setlayout(layout) @@ -277,17 +279,29 @@ if not searchstr: return self.searchstr = searchstr - self.searchpos = None + self.searchpos = -1 + self.searchresults = list(self.viewer.findall(self.searchstr)) self.find_next() def find_next(self): if not self.searchstr: return - item = self.viewer.search(self.searchstr, start_at=self.searchpos) - if item is None: + if self.searchpos + 1 >= len(self.searchresults): self.setstatusbar('Not found: %s' % self.searchstr) return - self.searchpos = item + self.searchpos += 1 + self.highlight_found_item(self.searchresults[self.searchpos]) + + def find_prev(self): + if not self.searchstr: + return + if self.searchpos - 1 < 0: + self.setstatusbar('Not found: %s' % self.searchstr) + return + self.searchpos -= 1 + self.highlight_found_item(self.searchresults[self.searchpos]) + + def highlight_found_item(self, item): self.sethighlight(obj=item) if isinstance(item, Node): self.setstatusbar('Found node containing %s' % self.searchstr) @@ -305,7 +319,8 @@ del self.forward_viewers_history[:] self.layout = layout self.viewer = GraphRenderer(self.screen, layout) - self.searchpos = None + self.searchpos = 0 + self.searchresults = [] self.zoom_to_fit() def zoom_actual_size(self): From arigo at codespeak.net Tue Nov 23 19:00:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 19:00:45 +0100 (MET) Subject: [pypy-svn] r7643 - pypy/trunk/src/pypy/annotation Message-ID: <20041123180045.2E5455B07B@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 19:00:44 2004 New Revision: 7643 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: obvious fix. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue Nov 23 19:00:44 2004 @@ -260,6 +260,9 @@ else: return ins2 basedef = ins1.classdef.commonbase(ins2.classdef) + if basedef is None: + # print warning? + return SomeObject() return SomeInstance(basedef) class __extend__(pairtype(SomeIterator, SomeIterator)): From mgedmin at codespeak.net Tue Nov 23 19:02:11 2004 From: mgedmin at codespeak.net (mgedmin at codespeak.net) Date: Tue, 23 Nov 2004 19:02:11 +0100 (MET) Subject: [pypy-svn] r7644 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041123180211.AA6DC5B090@thoth.codespeak.net> Author: mgedmin Date: Tue Nov 23 19:02:07 2004 New Revision: 7644 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Log: Show how many items were found. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphdisplay.py Tue Nov 23 19:02:07 2004 @@ -290,7 +290,7 @@ self.setstatusbar('Not found: %s' % self.searchstr) return self.searchpos += 1 - self.highlight_found_item(self.searchresults[self.searchpos]) + self.highlight_found_item() def find_prev(self): if not self.searchstr: @@ -299,19 +299,22 @@ self.setstatusbar('Not found: %s' % self.searchstr) return self.searchpos -= 1 - self.highlight_found_item(self.searchresults[self.searchpos]) + self.highlight_found_item() - def highlight_found_item(self, item): + def highlight_found_item(self): + item = self.searchresults[self.searchpos] self.sethighlight(obj=item) + msg = 'Found %%s containing %s (%d/%d)' % (self.searchstr, + self.searchpos+1, len(self.searchresults)) if isinstance(item, Node): - self.setstatusbar('Found node containing %s' % self.searchstr) + self.setstatusbar(msg % 'node') self.look_at_node(item, keep_highlight=True) elif isinstance(item, Edge): - self.setstatusbar('Found edge containing %s' % self.searchstr) + self.setstatusbar(msg % 'edge') self.look_at_edge(item, keep_highlight=True) else: # should never happen - self.setstatusbar('Found %r containing %s' % (item, self.searchstr)) + self.setstatusbar(msg % item) def setlayout(self, layout): if self.viewer: From mwh at codespeak.net Tue Nov 23 19:06:02 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Tue, 23 Nov 2004 19:06:02 +0100 (MET) Subject: [pypy-svn] r7645 - pypy/trunk/src/pypy/annotation Message-ID: <20041123180602.290DF5B093@thoth.codespeak.net> Author: mwh Date: Tue Nov 23 19:06:00 2004 New Revision: 7645 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: Don't call getvalue() in about_attribute(). Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 19:06:00 2004 @@ -458,7 +458,7 @@ def about_attribute(self, name): for cdef in self.getmro(): if name in cdef.attrs: - return cdef.attrs[name].getvalue() + return cdef.attrs[name] return None From arigo at codespeak.net Tue Nov 23 19:09:16 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 19:09:16 +0100 (MET) Subject: [pypy-svn] r7646 - pypy/trunk/src/pypy/annotation Message-ID: <20041123180916.CCCF05B097@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 19:09:12 2004 New Revision: 7646 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: Oups. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 19:09:12 2004 @@ -458,7 +458,7 @@ def about_attribute(self, name): for cdef in self.getmro(): if name in cdef.attrs: - return cdef.attrs[name] + return cdef.attrs[name].s_value return None From arigo at codespeak.net Tue Nov 23 19:19:25 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 19:19:25 +0100 (MET) Subject: [pypy-svn] r7647 - pypy/trunk/src/pypy/annotation Message-ID: <20041123181925.841A05B098@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 19:19:14 2004 New Revision: 7647 Modified: pypy/trunk/src/pypy/annotation/unaryop.py Log: SomePBC.getattr() needs to mark the attribute as read in the classdefs. Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 23 19:19:14 2004 @@ -8,7 +8,7 @@ from pypy.annotation.model import SomeString, SomeChar, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin -from pypy.annotation.model import SomeIterator, SomePBC +from pypy.annotation.model import SomeIterator, SomePBC, new_or_old_class from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper from pypy.annotation.factory import isclassdef @@ -161,12 +161,16 @@ class __extend__(SomePBC): def getattr(pbc, s_attr): + bookkeeper = getbookkeeper() assert s_attr.is_constant() attr = s_attr.const actuals = [] - for c in pbc.prebuiltinstances: if hasattr(c, attr): + # force the attribute to be considered on the class + classdef = bookkeeper.getclassdef(new_or_old_class(c)) + classdef.find_attribute(attr).getvalue() + # but only return the more precise result getattr(c, attr) actuals.append(immutablevalue(getattr(c, attr))) return unionof(*actuals) From arigo at codespeak.net Tue Nov 23 19:29:22 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 23 Nov 2004 19:29:22 +0100 (MET) Subject: [pypy-svn] r7648 - pypy/trunk/src/pypy/annotation Message-ID: <20041123182922.ACB8F5B09A@thoth.codespeak.net> Author: arigo Date: Tue Nov 23 19:29:20 2004 New Revision: 7648 Modified: pypy/trunk/src/pypy/annotation/factory.py Log: Cache SomePBC instances. This is not just an optimization, but needed to avoid infinitely repeated calls to add_source_for_attribute(). Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue Nov 23 19:29:20 2004 @@ -50,6 +50,7 @@ self.userclasses = {} # map classes to ClassDefs self.userclasseslist = []# userclasses.keys() in creation order self.cachespecializations = {} + self.pbccache = {} def enter(self, position_key): """Start of an operation. @@ -126,15 +127,12 @@ s_name = self.immutablevalue(x.__name__) result = s_self.getattr(s_name) else: - result = SomePBC({x : True}) + return self.getpbc(x) elif hasattr(x, '__class__') \ and x.__class__.__module__ != '__builtin__': if isinstance(x, Cache) and not x.frozen: x.freeze() - result = SomePBC({x: True}) # pre-built inst - clsdef = self.getclassdef(x.__class__) - for attr in x.__dict__: - clsdef.add_source_for_attribute(attr, x) + return self.getpbc(x) elif x is None: result = SomeNone() else: @@ -142,6 +140,19 @@ result.const = x return result + def getpbc(self, x): + try: + # this is not just an optimization, but needed to avoid + # infinitely repeated calls to add_source_for_attribute() + return self.pbccache[x] + except KeyError: + result = SomePBC({x: True}) # pre-built inst + clsdef = self.getclassdef(new_or_old_class(x)) + for attr in x.__dict__: + clsdef.add_source_for_attribute(attr, x) + self.pbccache[x] = result + return result + def valueoftype(self, t): """The most precise SomeValue instance that contains all objects of type t.""" From tismer at codespeak.net Tue Nov 23 19:33:02 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 19:33:02 +0100 (MET) Subject: [pypy-svn] r7649 - pypy/trunk/src/pypy/translator Message-ID: <20041123183302.B305C5B09B@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 19:32:58 2004 New Revision: 7649 Modified: pypy/trunk/src/pypy/translator/genrpy.py Log: almost quite workable. Needs some more hacks and of course non-C style renderings :-) Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 23 19:32:58 2004 @@ -91,11 +91,24 @@ class GenRpy: - def __init__(self, f, translator): + def __init__(self, f, translator, modname=None): self.f = f self.translator = translator - self.rpynames = {} + self.modname = (modname or + translator.functions[0].__name__) + self.rpynames = {Constant(None).key: 'w(None)', + Constant(False).key: 'w(False)', + Constant(True).key: 'w(True)', + } + self.seennames = {} + self.initcode = [] # list of lines for the module's initxxx() + self.latercode = [] # list of generators generating extra lines + # for later in initxxx() -- for recursive + # objects + self.globaldecl = [] + self.globalobjects = [] + self.pendingfunctions = [] # special constructors: self.has_listarg = {} @@ -156,14 +169,7 @@ def nameof_int(self, value): - if value >= 0: - name = 'gint_%d' % value - else: - name = 'gint_minus%d' % abs(value) - name = self.uniquename(name) - self.initcode.append('INITCHK(%s = ' - 'PyInt_FromLong(%d))' % (name, value)) - return name + return "w(%d)" % value def nameof_long(self, value): assert type(int(value)) is int, "your literal long is too long" @@ -177,36 +183,10 @@ return name def nameof_float(self, value): - name = 'gfloat_%s' % value - name = (name.replace('-', 'minus') - .replace('.', 'dot')) - chrs = [c for c in name if ('a' <= c <='z' or - 'A' <= c <='Z' or - '0' <= c <='9' or - '_' == c )] - name = ''.join(chrs) - name = self.uniquename(name) - self.initcode.append('INITCHK(%s = ' - 'PyFloat_FromDouble(%r))' % (name, value)) - return name + return "w(%s)" % value def nameof_str(self, value): - chrs = [c for c in value[:32] if ('a' <= c <='z' or - 'A' <= c <='Z' or - '0' <= c <='9' or - '_' == c )] - name = self.uniquename('gstr_' + ''.join(chrs)) - if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']: - # non-printable string - s = 'chr_%s' % name - self.globaldecl.append('static char %s[] = { %s };' % ( - s, ', '.join(['%d' % ord(c) for c in value]))) - else: - # printable string - s = '"%s"' % value - self.initcode.append('INITCHK(%s = PyString_FromStringAndSize(' - '%s, %d))' % (name, s, len(value))) - return name + return "w(%s)" % repr(value) def skipped_function(self, func): # debugging only! Generates a placeholder for missing functions @@ -219,8 +199,7 @@ self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) return name - def nameof_function(self, func, progress=['-\x08', '\\\x08', - '|\x08', '/\x08']): + def nameof_function(self, func): printable_name = '(%s:%d) %s' % ( func.func_globals.get('__name__', '?'), func.func_code.co_firstlineno, @@ -234,9 +213,6 @@ func.func_doc.lstrip().startswith('NOT_RPYTHON')): print "skipped", printable_name return self.skipped_function(func) - p = progress.pop(0) - sys.stderr.write(p) - progress.append(p) name = self.uniquename('gfunc_' + func.__name__) self.initcode.append('INITCHK(%s = PyCFunction_New(' '&ml_%s, NULL))' % (name, name)) @@ -284,7 +260,7 @@ return False def later(self, gen): - self.latercode.append((gen, self.debugstack)) + self.latercode.append(gen) def nameof_instance(self, instance): name = self.uniquename('ginst_' + instance.__class__.__name__) @@ -339,7 +315,7 @@ metaclass = "&PyType_Type" if issubclass(cls, Exception): if cls.__module__ == 'exceptions': - return 'PyExc_%s'%cls.__name__ + return 'w(%s)'%cls.__name__ #else: # # exceptions must be old-style classes (grr!) # metaclass = "&PyClass_Type" @@ -386,6 +362,7 @@ def nameof_type(self, cls): + return "w(%s)" % cls.__name__ ##?? if cls in self.typename_mapping: return '(PyObject*) %s' % self.typename_mapping[cls] assert cls.__module__ != '__builtin__', \ @@ -512,7 +489,7 @@ f = self.f t = self.translator - t.simplify(func, rpython=False) + t.simplify(func) graph = t.getflowgraph(func) start = graph.startblock @@ -553,13 +530,13 @@ else: # regular return block retval = expr(block.inputargs[0]) - yield"return %s" % retval + yield "return %s" % retval return elif block.exitswitch is None: # single-exit block assert len(block.exits) == 1 for op in gen_link(block.exits[0]): - yield " %s" % op + yield "%s" % op elif catch_exception: # block catching the exceptions raised by its last operation # we handle the non-exceptional case first @@ -604,12 +581,10 @@ for line in render_block(block): print " %s" % line -entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [2] - -t = Translator(entry_point, verbose=False, simplifying=False) -# hack: replace class +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [0] -#t.simplify(rpython=False) +t = Translator(entry_point, verbose=False, simplifying=True) +#t.simplify() #t.view() gen = GenRpy(sys.stdout, t) gen.gen_rpyfunction(t.functions[0]) From tismer at codespeak.net Tue Nov 23 20:50:26 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Tue, 23 Nov 2004 20:50:26 +0100 (MET) Subject: [pypy-svn] r7650 - pypy/trunk/src/pypy/translator Message-ID: <20041123195026.57D585B09D@thoth.codespeak.net> Author: tismer Date: Tue Nov 23 20:50:25 2004 New Revision: 7650 Modified: pypy/trunk/src/pypy/translator/simplify.py Log: small cleanup: reset exitswitch to None if the exception gets removed. Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Tue Nov 23 20:50:25 2004 @@ -81,6 +81,7 @@ lst = list(link.prevblock.exits) lst.remove(link) link.prevblock.exits = tuple(lst) + link.prevblock.exitswitch = None traverse(visit, graph) def simplify_graph(graph): From tismer at codespeak.net Wed Nov 24 01:17:14 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 24 Nov 2004 01:17:14 +0100 (MET) Subject: [pypy-svn] r7651 - pypy/trunk/src/pypy/translator Message-ID: <20041124001714.8F0CF5B09E@thoth.codespeak.net> Author: tismer Date: Wed Nov 24 01:17:14 2004 New Revision: 7651 Modified: pypy/trunk/src/pypy/translator/genrpy.py pypy/trunk/src/pypy/translator/simplify.py Log: modified simplify to set the exitswitch to None if no exception exists. Also added the _formatting as the test case and switched optimisation to off, in order to see all the generated exceptions. Armin, I see a problem with layer levels: I get general exceptions together with IndexError and KeyError. Maybe they need some common treatment, since I always expect a wrapped exception, only? Please run my program and have a look. Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Wed Nov 24 01:17:14 2004 @@ -1,16 +1,17 @@ """ -Implementation of a translator from Python to interpreter level RPython. +Implementation of a translator from application Python to interpreter level RPython. The idea is that we can automatically transform app-space implementations of methods into some equivalent representation at interpreter level. Then, the RPython to C translation might hopefully spit out some more efficient code than always interpreting these methods. -Note that the appspace things are treated as RPythonic, in a sense -that globals are constant,for instance. +Note that the appspace functions are treated as rpythonic, in a sense +that globals are constants, for instance. This definition is not +exact and might change. -This module is very much under construction and not yet usable but -for testing. +This module is very much under construction and not yet usable for much +more than testing. """ from pypy.objspace.flow.model import traverse @@ -58,6 +59,16 @@ global glob return 42+glob +def app_mod__String_ANY(format, values): + import _formatting + if isinstance(values, tuple): + return _formatting.format(format, values, None) + else: + if hasattr(values, 'keys'): + return _formatting.format(format, (values,), values) + else: + return _formatting.format(format, (values,), None) + def app_str_decode__String_ANY_ANY(str, encoding=None, errors=None): if encoding is None and errors is None: return unicode(str) @@ -115,6 +126,8 @@ for name in "newtuple newlist newdict newstring".split(): self.has_listarg[name] = name + self.gen_source() + def nameof(self, obj): key = Constant(obj).key try: @@ -432,6 +445,38 @@ return 'PySys_GetObject("stderr")' raise Exception, 'Cannot translate an already-open file: %r' % (fil,) + def gen_source(self): + f = self.f + info = { + 'modname': self.modname, + 'entrypointname': self.translator.functions[0].__name__, + 'entrypoint': self.nameof(self.translator.functions[0]), + } + + # function implementations + while self.pendingfunctions: + func = self.pendingfunctions.pop() + print "#######", func.__name__ + self.gen_rpyfunction(func) + # collect more of the latercode after each function + while self.latercode: + #gen, self.debugstack = self.latercode.pop() + gen = self.latercode.pop() + #self.initcode.extend(gen) -- eats TypeError! bad CPython! + for line in gen: + self.initcode.append(line) + self.debugstack = () + #self.gen_global_declarations() + + # footer + # maybe not needed + return + print >> f, self.C_INIT_HEADER % info + if self.f2name is not None: + print >> f, '#include "%s"' % self.f2name + for codeline in self.initcode: + print >> f, '\t' + codeline + print >> f, self.C_INIT_FOOTER % info def gen_rpyfunction(self, func): @@ -489,7 +534,7 @@ f = self.f t = self.translator - t.simplify(func) + #t.simplify(func) graph = t.getflowgraph(func) start = graph.startblock @@ -546,9 +591,10 @@ yield " %s" % op # we must catch the exception raised by the last operation, # which goes to the last err%d_%d label written above. - yield "except OperationError, e:" for link in block.exits[1:]: assert issubclass(link.exitcase, Exception) + yield "except OperationError, e:" + print "*"*10, link.exitcase for op in gen_link(link, { Constant(last_exception): 'e.w_type', Constant(last_exc_value): 'e.w_value'}): @@ -581,13 +627,22 @@ for line in render_block(block): print " %s" % line -entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY) [0] +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY, app_mod__String_ANY) [-1] -t = Translator(entry_point, verbose=False, simplifying=True) +import os, sys +from pypy.interpreter import autopath +srcdir = os.path.dirname(autopath.pypydir) +appdir = os.path.join(autopath.pypydir, 'appspace') + +try: + hold = sys.path[:] + sys.path.insert(0, appdir) + t = Translator(entry_point, verbose=False, simplifying=not True) + gen = GenRpy(sys.stdout, t) +finally: + sys.path[:] = hold #t.simplify() #t.view() -gen = GenRpy(sys.stdout, t) -gen.gen_rpyfunction(t.functions[0]) # debugging graph = t.getflowgraph() ab = ordered_blocks(graph) # use ctrl-b in PyWin with ab Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Wed Nov 24 01:17:14 2004 @@ -81,7 +81,8 @@ lst = list(link.prevblock.exits) lst.remove(link) link.prevblock.exits = tuple(lst) - link.prevblock.exitswitch = None + if len(lst) <= 1: + link.prevblock.exitswitch = None traverse(visit, graph) def simplify_graph(graph): From mwh at codespeak.net Wed Nov 24 01:23:30 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 24 Nov 2004 01:23:30 +0100 (MET) Subject: [pypy-svn] r7652 - pypy/trunk/src/pypy/annotation Message-ID: <20041124002330.1210D5B09F@thoth.codespeak.net> Author: mwh Date: Wed Nov 24 01:23:29 2004 New Revision: 7652 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: This can never have worked! Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 24 01:23:29 2004 @@ -77,7 +77,7 @@ def builtin_issubclass(s_cls1, s_cls2): if s_cls1.is_constant() and s_cls2.is_constant(): - return immutablevalue(issubclass(s_cls1, s_cls2)) + return immutablevalue(issubclass(s_cls1.const, s_cls2.const)) else: return SomeBool() From mwh at codespeak.net Wed Nov 24 01:38:31 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 24 Nov 2004 01:38:31 +0100 (MET) Subject: [pypy-svn] r7653 - pypy/trunk/src/pypy/annotation Message-ID: <20041124003831.1EA9A5B0A0@thoth.codespeak.net> Author: mwh Date: Wed Nov 24 01:38:30 2004 New Revision: 7653 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: builtin_hash (!?) Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 24 01:38:30 2004 @@ -94,6 +94,9 @@ 'hasattr(%r, %r) is not RPythonic enough' % (s_obj, s_attr) return SomeBool() +def builtin_hash(s_obj): + return SomeInteger() + def builtin_callable(s_obj): return SomeBool() From lac at codespeak.net Wed Nov 24 13:12:37 2004 From: lac at codespeak.net (lac at codespeak.net) Date: Wed, 24 Nov 2004 13:12:37 +0100 (MET) Subject: [pypy-svn] r7655 - pypy/trunk/src/pypy/appspace Message-ID: <20041124121237.069AD5B0AF@thoth.codespeak.net> Author: lac Date: Wed Nov 24 13:12:37 2004 New Revision: 7655 Modified: pypy/trunk/src/pypy/appspace/_file.py Log: Finish making certain attributes readonly. This requires renaming the attributes 'mode' 'name' and 'closed' as used in the init, or else Modified: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_file.py (original) +++ pypy/trunk/src/pypy/appspace/_file.py Wed Nov 24 13:12:37 2004 @@ -4,35 +4,35 @@ """An implementation of file objects in Python. it relies on Guido's sio.py implementation. """ - def __init__(self, filename, mode='r', bufsize=None): + def __init__(self, filename, filemode='r', bufsize=None): self.reading = False self.writing = False - if not mode: + if not filemode: raise IOError('invalid mode : ') - if mode[0] not in ['r', 'w', 'a', 'U']: - raise IOError('invalid mode : %s' % mode) + if filemode[0] not in ['r', 'w', 'a', 'U']: + raise IOError('invalid mode : %s' % filemode) else: - if mode[0] in ['r', 'U']: + if filemode[0] in ['r', 'U']: self.reading = True else: self.writing = True try: - if mode[1] == 'b': - plus = mode[2] + if filemode[1] == 'b': + plus = filemode[2] else: - plus = mode[1] + plus = filemode[1] if plus == '+': self.reading = self.writing = True except IndexError: pass - self.mode = mode - self.name = filename - self.closed = False + self.filemode = filemode + self.filename = filename + self.isclosed = False self.softspace = 0 # Required according to file object docs - self.fd = sio.DiskFile(filename, mode) - if mode in ['U', 'rU']: + self.fd = sio.DiskFile(filename, filemode) + if filemode in ['U', 'rU']: # Wants universal newlines self.fd = sio.TextInputFilter(self.fd) if bufsize < 0: @@ -52,13 +52,14 @@ self.fd = sio.BufferingInputOutputStream(self.fd, bufsize) return self.fd - def __getattr__(self, name): - if name == 'close': - self.closed = True + def __getattr__(self, attr): """ - Delegate all other methods to the underlying file object. + Delegate all methods to the underlying file object. """ - return getattr(self.fd, name) + if attr == 'close': + self.isclosed = True + + return getattr(self.fd, attr) def __setattr__(self, attr, val): "Make some attributes readonly." From mwh at codespeak.net Wed Nov 24 13:40:42 2004 From: mwh at codespeak.net (mwh at codespeak.net) Date: Wed, 24 Nov 2004 13:40:42 +0100 (MET) Subject: [pypy-svn] r7656 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041124124042.32D9A5B0B0@thoth.codespeak.net> Author: mwh Date: Wed Nov 24 13:40:41 2004 New Revision: 7656 Modified: pypy/trunk/src/pypy/objspace/std/fake.py Log: an experimental and different way to wrap certain descriptor types. Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Wed Nov 24 13:40:41 2004 @@ -108,3 +108,13 @@ _fake_type_cache.content[type(len)] = fake_builtin_callable _fake_type_cache.content[type(list.append)] = fake_builtin_callable _fake_type_cache.content[type(type(None).__repr__)] = fake_builtin_callable + +from pypy.interpreter.typedef import GetSetProperty + +def fake_descriptor(space, d): + n = d.__name__ + return space.wrap(GetSetProperty(lambda x:getattr(x, n), + lambda x,y:setattr(x, n, y))) + +_fake_type_cache.content[type(file.softspace)] = fake_descriptor +_fake_type_cache.content[type(type.__dict__['__dict__'])] = fake_descriptor From tismer at codespeak.net Wed Nov 24 15:38:43 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 24 Nov 2004 15:38:43 +0100 (MET) Subject: [pypy-svn] r7657 - pypy/trunk/src/pypy/translator Message-ID: <20041124143843.DFB095B0B3@thoth.codespeak.net> Author: tismer Date: Wed Nov 24 15:38:43 2004 New Revision: 7657 Modified: pypy/trunk/src/pypy/translator/genrpy.py Log: added testwise the md5 implementation. It looks quite good, but there is a problem with the flow space: md5 unfortuantely uses copy.deepcopy, which makes the flow space dig into that, and we crash with the message AssertionError: Not generating the same operation sequence: v4162 = simple_call((type type), v4157) ---> | while repeating we see here | v4163 = simple_call((builtin_function_or_method get), v4162) v4163 = simple_call((builtin_function_or_method get), v4162) v4164 = is_true(v4163) >>> I guess there is so much stuff in the copy module that the flow space gets confused somehow. But well, it may be a real bug. For now, I'll replace the copy.deepcopy part of md5 with something else, to protect the analysis. Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Wed Nov 24 15:38:43 2004 @@ -20,6 +20,7 @@ from pypy.objspace.flow.model import last_exception, last_exc_value from pypy.translator.simplify import simplify_graph from pypy.interpreter.error import OperationError +from types import FunctionType from pypy.translator.translator import Translator @@ -148,7 +149,7 @@ if meth: break else: - raise Exception, "nameof(%r)" % (obj,) + raise Exception, "nameof(%r) in %r" % (obj, self.current_func) name = meth(obj) self.rpynames[key] = name return name @@ -165,7 +166,7 @@ def nameof_object(self, value): if type(value) is not object: - raise Exception, "nameof(%r)" % (value,) + raise Exception, "nameof(%r) in %r" % (value, self.current_func) name = self.uniquename('g_object') self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) return name @@ -185,15 +186,11 @@ return "w(%d)" % value def nameof_long(self, value): - assert type(int(value)) is int, "your literal long is too long" - if value >= 0: - name = 'glong%d' % value + # assume we want them in hex most of the time + if value < 256L: + return "%dL" % value else: - name = 'glong_minus%d' % abs(value) - name = self.uniquename(name) - self.initcode.append('INITCHK(%s = ' - 'PyLong_FromLong(%d))' % (name, value)) - return name + return "0x%08xL" % value def nameof_float(self, value): return "w(%s)" % value @@ -402,6 +399,7 @@ return name def nameof_dict(self, dic): + return 'space.newdict([w("sorry", "not yet"])' assert dic is not __builtins__ assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( dic.get('__name__', '?'),) @@ -455,7 +453,7 @@ # function implementations while self.pendingfunctions: - func = self.pendingfunctions.pop() + func = self.current_func = self.pendingfunctions.pop() print "#######", func.__name__ self.gen_rpyfunction(func) # collect more of the latercode after each function @@ -540,7 +538,6 @@ start = graph.startblock blocks = ordered_blocks(graph) nblocks = len(blocks) - assert blocks[0] is start blocknum = {} for block in blocks: @@ -552,7 +549,7 @@ argstr = ", ".join(args) print >> f, "def %s(space, %s):" % (name, argstr) print >> f, " w = space.wrap" - print >> f, " goto = 1 # startblock" + print >> f, " goto = %d # startblock" % blocknum[start] print >> f, " while True:" def render_block(block): @@ -627,7 +624,13 @@ for line in render_block(block): print " %s" % line -entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY, app_mod__String_ANY) [-1] +def test_md5(): + #import md5 + # how do I avoid the builtin module? + from pypy.appspace import md5 + digest = md5.new("hello") + +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY, app_mod__String_ANY, test_md5) [-1] import os, sys from pypy.interpreter import autopath @@ -637,7 +640,7 @@ try: hold = sys.path[:] sys.path.insert(0, appdir) - t = Translator(entry_point, verbose=False, simplifying=not True) + t = Translator(entry_point, verbose=False, simplifying=True) gen = GenRpy(sys.stdout, t) finally: sys.path[:] = hold From lac at codespeak.net Wed Nov 24 16:14:42 2004 From: lac at codespeak.net (lac at codespeak.net) Date: Wed, 24 Nov 2004 16:14:42 +0100 (MET) Subject: [pypy-svn] r7658 - in pypy/trunk/src/pypy/appspace: . test Message-ID: <20041124151442.608865B0B6@thoth.codespeak.net> Author: lac Date: Wed Nov 24 16:14:41 2004 New Revision: 7658 Modified: pypy/trunk/src/pypy/appspace/_file.py pypy/trunk/src/pypy/appspace/test/test_file.py Log: The last thing couldn't have worked. This works a little better but I need to write some more tests. Modified: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_file.py (original) +++ pypy/trunk/src/pypy/appspace/_file.py Wed Nov 24 16:14:41 2004 @@ -4,35 +4,36 @@ """An implementation of file objects in Python. it relies on Guido's sio.py implementation. """ - def __init__(self, filename, filemode='r', bufsize=None): + def __init__(self, name, mode='r', bufsize=None): self.reading = False self.writing = False - if not filemode: + if not mode: raise IOError('invalid mode : ') - if filemode[0] not in ['r', 'w', 'a', 'U']: - raise IOError('invalid mode : %s' % filemode) + if mode[0] not in ['r', 'w', 'a', 'U']: + raise IOError('invalid mode : %s' % mode) else: - if filemode[0] in ['r', 'U']: + if mode[0] in ['r', 'U']: self.reading = True else: self.writing = True try: - if filemode[1] == 'b': - plus = filemode[2] + if mode[1] == 'b': + plus = mode[2] else: - plus = filemode[1] + plus = mode[1] if plus == '+': self.reading = self.writing = True except IndexError: pass - self.filemode = filemode - self.filename = filename - self.isclosed = False - self.softspace = 0 # Required according to file object docs - self.fd = sio.DiskFile(filename, filemode) - if filemode in ['U', 'rU']: + self._mode = mode + self._name = name + self._closed = False + self.softspace = 0 # Required according to file object docs + self._encoding = None # Fix when we find out how encoding should be + self.fd = sio.DiskFile(name, mode) + if mode in ['U', 'rU']: # Wants universal newlines self.fd = sio.TextInputFilter(self.fd) if bufsize < 0: @@ -54,11 +55,17 @@ def __getattr__(self, attr): """ - Delegate all methods to the underlying file object. + Handle the readonly attributes and then delegate the other + methods to the underlying file object, setting the 'closed' + attribute if you close the file. """ - if attr == 'close': - self.isclosed = True - + if attr in ['fd', 'softspace', 'reading', 'writing']: + return self.__dict__[attr] + elif attr in ['mode', 'name', 'closed', 'encoding']: + return self.__dict__['_' + attr] + elif attr == 'close': + self._closed = True + return getattr(self.fd, attr) def __setattr__(self, attr, val): Modified: pypy/trunk/src/pypy/appspace/test/test_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_file.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_file.py Wed Nov 24 16:14:41 2004 @@ -14,9 +14,15 @@ def test_case_1(self): self.assertEquals(self.fd.tell(), 0) + def test_case_readonly(self): + f=_file.file_('/tmp/tt', 'w') + self.assertEquals(f.name, '/tmp/tt') + self.assertEquals(f.mode, 'w') + self.assertEquals(f.closed, False) + self.assertEquals(f.encoding, None) # Fix when we find out what this is + def test_main(): unittest.main() - if __name__ == "__main__": test_main() From lac at codespeak.net Wed Nov 24 17:07:05 2004 From: lac at codespeak.net (lac at codespeak.net) Date: Wed, 24 Nov 2004 17:07:05 +0100 (MET) Subject: [pypy-svn] r7659 - in pypy/trunk/src/pypy/appspace: . test Message-ID: <20041124160705.5E6D25B0BB@thoth.codespeak.net> Author: lac Date: Wed Nov 24 17:07:04 2004 New Revision: 7659 Modified: pypy/trunk/src/pypy/appspace/_file.py pypy/trunk/src/pypy/appspace/test/test_file.py Log: I am now mystified. I made a testRaises TypeError. A TypeError gets raised. But the test still claims to fail. Now to go read unittest source, but if anybody knows why this fails, drop me a note ... Modified: pypy/trunk/src/pypy/appspace/_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/_file.py (original) +++ pypy/trunk/src/pypy/appspace/_file.py Wed Nov 24 17:07:04 2004 @@ -71,5 +71,5 @@ def __setattr__(self, attr, val): "Make some attributes readonly." if attr in ['mode', 'name', 'closed', 'encoding']: - raise TypeError('readonly attribute: %s' % attr) + raise TypeError, "readonly attribute:'%s'" % attr self.__dict__[attr] = val Modified: pypy/trunk/src/pypy/appspace/test/test_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_file.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_file.py Wed Nov 24 17:07:04 2004 @@ -20,6 +20,8 @@ self.assertEquals(f.mode, 'w') self.assertEquals(f.closed, False) self.assertEquals(f.encoding, None) # Fix when we find out what this is + self.assertRaises(TypeError, setattr(f, 'name', 42)) + #I am totally confused. This test fails, but a Type Error gets raised. def test_main(): unittest.main() From pedronis at codespeak.net Wed Nov 24 17:38:46 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 24 Nov 2004 17:38:46 +0100 (MET) Subject: [pypy-svn] r7660 - pypy/trunk/src/pypy/appspace/test Message-ID: <20041124163846.A51DF5B0BC@thoth.codespeak.net> Author: pedronis Date: Wed Nov 24 17:38:46 2004 New Revision: 7660 Modified: pypy/trunk/src/pypy/appspace/test/test_file.py (props changed) Log: eol-style From pedronis at codespeak.net Wed Nov 24 17:52:37 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 24 Nov 2004 17:52:37 +0100 (MET) Subject: [pypy-svn] r7661 - pypy/trunk/src/pypy/appspace/test Message-ID: <20041124165237.67C1B5B0BD@thoth.codespeak.net> Author: pedronis Date: Wed Nov 24 17:52:36 2004 New Revision: 7661 Modified: pypy/trunk/src/pypy/appspace/test/test_file.py Log: assertRaises takes callable+*args to do its job here the test still fails because of the mapping 'w' -> os.O_WRONLY btw /tmp/tt is a unixism Modified: pypy/trunk/src/pypy/appspace/test/test_file.py ============================================================================== --- pypy/trunk/src/pypy/appspace/test/test_file.py (original) +++ pypy/trunk/src/pypy/appspace/test/test_file.py Wed Nov 24 17:52:36 2004 @@ -20,8 +20,7 @@ self.assertEquals(f.mode, 'w') self.assertEquals(f.closed, False) self.assertEquals(f.encoding, None) # Fix when we find out what this is - self.assertRaises(TypeError, setattr(f, 'name', 42)) - #I am totally confused. This test fails, but a Type Error gets raised. + self.assertRaises(TypeError, setattr, f, 'name', 42) def test_main(): unittest.main() From tismer at codespeak.net Wed Nov 24 17:57:39 2004 From: tismer at codespeak.net (tismer at codespeak.net) Date: Wed, 24 Nov 2004 17:57:39 +0100 (MET) Subject: [pypy-svn] r7662 - pypy/trunk/src/pypy/appspace Message-ID: <20041124165739.95A6B5B0BE@thoth.codespeak.net> Author: tismer Date: Wed Nov 24 17:57:39 2004 New Revision: 7662 Modified: pypy/trunk/src/pypy/appspace/md5.py Log: wrote MD5.copy without copy.deepcopy, to make genrpy happy. Modified: pypy/trunk/src/pypy/appspace/md5.py ============================================================================== --- pypy/trunk/src/pypy/appspace/md5.py (original) +++ pypy/trunk/src/pypy/appspace/md5.py Wed Nov 24 17:57:39 2004 @@ -169,6 +169,7 @@ "Initialize the message-digest and set all fields to zero." self.length = 0L + self.count = [0, 0] self.input = [] # Load magic initialization constants. @@ -389,8 +390,17 @@ to efficiently compute the digests of strings that share a common initial substring. """ - - return copy.deepcopy(self) + if 0: # set this to 1 to make the flow space crash + return copy.deepcopy(self) + clone = self.__class__() + clone.length = self.length + clone.count = [] + self.count[:] + clone.input = [] + self.input + clone.A = self.A + clone.B = self.B + clone.C = self.C + clone.D = self.D + return clone # ====================================================================== From pedronis at codespeak.net Wed Nov 24 18:13:54 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Wed, 24 Nov 2004 18:13:54 +0100 (MET) Subject: [pypy-svn] r7663 - pypy/trunk/src/pypy/appspace Message-ID: <20041124171354.0E9265B0C3@thoth.codespeak.net> Author: pedronis Date: Wed Nov 24 18:13:53 2004 New Revision: 7663 Modified: pypy/trunk/src/pypy/appspace/sio.py (contents, props changed) Log: O_CREAT | O_TRUNC should be the right thing for w... modes test_file passes (if there's a /tmp dir) Modified: pypy/trunk/src/pypy/appspace/sio.py ============================================================================== --- pypy/trunk/src/pypy/appspace/sio.py (original) +++ pypy/trunk/src/pypy/appspace/sio.py Wed Nov 24 18:13:53 2004 @@ -604,16 +604,16 @@ 'rb' : os.O_RDONLY, 'rU' : os.O_RDONLY, 'U' : os.O_RDONLY, - 'w' : os.O_WRONLY, - 'wb' : os.O_WRONLY, + 'w' : os.O_WRONLY | os.O_CREAT | os.O_TRUNC, + 'wb' : os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 'a' : os.O_WRONLY | os.O_CREAT | os.O_EXCL, 'ab' : os.O_WRONLY | os.O_CREAT | os.O_EXCL, 'r+' : os.O_RDWR, 'rb+': os.O_RDWR, 'r+b': os.O_RDWR, - 'w+' : os.O_RDWR | os.O_CREAT, - 'wb+': os.O_RDWR | os.O_CREAT, - 'w+b': os.O_RDWR | os.O_CREAT, + 'w+' : os.O_RDWR | os.O_CREAT | os.O_TRUNC, + 'wb+': os.O_RDWR | os.O_CREAT | os.O_TRUNC, + 'w+b': os.O_RDWR | os.O_CREAT | os.O_TRUNC, 'a+' : os.O_RDWR | os.O_CREAT | os.O_EXCL, 'ab+': os.O_RDWR | os.O_CREAT | os.O_EXCL, 'a+b': os.O_RDWR | os.O_CREAT | os.O_EXCL, From arigo at codespeak.net Wed Nov 24 20:48:56 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 24 Nov 2004 20:48:56 +0100 (MET) Subject: [pypy-svn] r7664 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20041124194856.90AA35B0C5@thoth.codespeak.net> Author: arigo Date: Wed Nov 24 20:48:54 2004 New Revision: 7664 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genc.py pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Removed SomeNone and turned it into a prebuilt constant (PBC). A fix in genpyrex which gets confused by all the stuff that is now annotated as prebuilt constant. Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Wed Nov 24 20:48:54 2004 @@ -134,7 +134,7 @@ x.freeze() return self.getpbc(x) elif x is None: - result = SomeNone() + return self.getpbc(None) else: result = SomeObject() result.const = x @@ -148,7 +148,7 @@ except KeyError: result = SomePBC({x: True}) # pre-built inst clsdef = self.getclassdef(new_or_old_class(x)) - for attr in x.__dict__: + for attr in getattr(x, '__dict__', {}): clsdef.add_source_for_attribute(attr, x) self.pbccache[x] = result return result @@ -469,7 +469,11 @@ def about_attribute(self, name): for cdef in self.getmro(): if name in cdef.attrs: - return cdef.attrs[name].s_value + s_result = cdef.attrs[name].s_value + if s_result != SomeImpossibleValue(): + return s_result + else: + return None return None Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 24 20:48:54 2004 @@ -77,12 +77,6 @@ del set_caused_by_merge -class SomeNone(SomeObject): - "Stands for None." - knowntype = type(None) - const = None - - class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." knowntype = int Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 24 20:48:54 2004 @@ -226,7 +226,7 @@ if graph.hasonlyexceptionreturns(): # XXX for functions with exceptions what to # do anyway? - return annmodel.SomeNone() + return self.bookkeeper.immutablevalue(None) return annmodel.SomeImpossibleValue() def reflowfromposition(self, position_key): Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Wed Nov 24 20:48:54 2004 @@ -241,8 +241,7 @@ else: return "probably" # True classdef = ann.getuserclasses().get(pbc.__class__) - if (classdef and classdef.about_attribute(attr) not in [ - None, annmodel.SomeImpossibleValue()]): + if classdef and classdef.about_attribute(attr) is not None: return True return False Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Wed Nov 24 20:48:54 2004 @@ -256,7 +256,8 @@ def _gettypename(self, vartype): if vartype in (int, bool): ctype = "int" - elif self.annotator and vartype in self.annotator.getuserclasses(): + elif (self.annotator and vartype in self.annotator.getuserclasses() + and vartype.__module__ != '__builtin__'): ctype = self.getclassname(vartype) else: ctype = "object" Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Wed Nov 24 20:48:54 2004 @@ -344,7 +344,7 @@ s = a.build_types(snippet.is_and_knowntype, [bool]) #a.simplify() #a.translator.view() - self.assert_(isinstance(s, annmodel.SomeNone)) + self.assertEquals(s, a.bookkeeper.immutablevalue(None)) def test_isinstance_and_knowntype_data(self): a = RPythonAnnotator() From arigo at codespeak.net Wed Nov 24 21:17:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Wed, 24 Nov 2004 21:17:09 +0100 (MET) Subject: [pypy-svn] r7665 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20041124201709.4CBEA5B0D1@thoth.codespeak.net> Author: arigo Date: Wed Nov 24 21:17:08 2004 New Revision: 7665 Added: pypy/trunk/src/pypy/annotation/bookkeeper.py - copied, changed from r7664, pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/classdef.py - copied, changed from r7664, pypy/trunk/src/pypy/annotation/factory.py Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/builtin.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genpyrex.py Log: Don't be impressed by the diff size. This is merely a split of the now rather large annotation.factory module into three modules: annotation.factory annotation.bookkeeper annotation.classdef Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Wed Nov 24 21:17:08 2004 @@ -9,7 +9,9 @@ from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeIterator from pypy.annotation.model import SomePBC from pypy.annotation.model import unionof, set, setunion, missing_operation -from pypy.annotation.factory import generalize, isclassdef, getbookkeeper +from pypy.annotation.factory import generalize +from pypy.annotation.bookkeeper import getbookkeeper +from pypy.annotation.classdef import isclassdef from pypy.objspace.flow.model import Constant # convenience only! Copied: pypy/trunk/src/pypy/annotation/bookkeeper.py (from r7664, pypy/trunk/src/pypy/annotation/factory.py) ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/bookkeeper.py Wed Nov 24 21:17:08 2004 @@ -1,41 +1,14 @@ """ -Mutable Objects Factories. - -A factory is associated to an SpaceOperation in the source that creates a -mutable object, currently 'newlist' and 'call' (which can build instances). -The factory remembers how general an object it has to create here. +The Bookkeeper class. """ -from __future__ import generators -import new from types import FunctionType, ClassType, MethodType from pypy.annotation.model import * +from pypy.annotation.classdef import ClassDef from pypy.interpreter.miscutils import getthreadlocals from pypy.interpreter.pycode import CO_VARARGS from pypy.tool.hack import func_with_new_name -def ishashable(x): - try: - hash(x) - except TypeError: - return False - else: - return True - -class BlockedInference(Exception): - """This exception signals the type inference engine that the situation - is currently blocked, and that it should try to progress elsewhere.""" - - def __init__(self): - try: - self.break_at = getbookkeeper().position_key - except AttributeError: - self.break_at = None - - def __repr__(self): - return "" %(self.break_at,) - __str__ = __repr__ - class Bookkeeper: """The log of choices that have been made while analysing the operations. It ensures that the same 'choice objects' will be returned if we ask @@ -51,6 +24,9 @@ self.userclasseslist = []# userclasses.keys() in creation order self.cachespecializations = {} self.pbccache = {} + # import ordering hack + global BUILTIN_ANALYZERS + from pypy.annotation.builtin import BUILTIN_ANALYZERS def enter(self, position_key): """Start of an operation. @@ -264,57 +240,13 @@ Only works during the analysis of an operation.""" return getthreadlocals().bookkeeper - -# -# Factories -# - -def generalize(factories, *args): - modified = [factory for factory in factories if factory.generalize(*args)] - if modified: - for factory in modified: - factory.bookkeeper.annotator.reflowfromposition(factory.position_key) - raise BlockedInference # reflow now - -def isclassdef(x): - return isinstance(x, ClassDef) - -class ListFactory: - s_item = SomeImpossibleValue() - - def __repr__(self): - return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) - - def create(self): - return SomeList(factories = {self: True}, s_item = self.s_item) - - def generalize(self, s_new_item): - if not self.s_item.contains(s_new_item): - self.s_item = unionof(self.s_item, s_new_item) - return True - else: - return False - - -class DictFactory: - items = {} - - def __repr__(self): - return '%s(items=%r)' % (self.__class__.__name__, self.items) - - def create(self): - return SomeDict(factories = {self: True}, items = self.items) - - def generalize(self, key, s_new_value): - self.items = self.items.copy() - if key not in self.items: - self.items[key] = s_new_value - return True - elif not self.items[key].contains(s_new_value): - self.items[key] = unionof(self.items[key], s_new_value) - return True - else: - return False +def ishashable(x): + try: + hash(x) + except TypeError: + return False + else: + return True def short_type_name(args): l = [] @@ -325,157 +257,3 @@ name = x.__class__.__name__ l.append(name) return "__".join(l) - - -class Attribute: - # readonly-ness - # SomeThing-ness - # more potential sources (pbcs or classes) of information - - def __init__(self, name, bookkeeper): - self.name = name - self.bookkeeper = bookkeeper - self.sources = {} # source -> None or ClassDef - # XXX a SomeImpossibleValue() constant? later!! - self.s_value = SomeImpossibleValue() - self.readonly = True - - def getvalue(self): - while self.sources: - source, classdef = self.sources.popitem() - s_value = self.bookkeeper.immutablevalue( - source.__dict__[self.name]) - if classdef: - s_value = s_value.bindcallables(classdef) - self.s_value = unionof(self.s_value, s_value) - return self.s_value - - def merge(self, other): - assert self.name == other.name - self.sources.update(other.sources) - self.s_value = unionof(self.s_value, other.s_value) - self.readonly = self.readonly and other.readonly - - -class ClassDef: - "Wraps a user class." - - def __init__(self, cls, bookkeeper): - self.bookkeeper = bookkeeper - self.attrs = {} # {name: Attribute} - self.revision = 0 # which increases the revision number - self.instantiation_locations = {} - self.cls = cls - self.subdefs = {} - assert (len(cls.__bases__) <= 1 or - cls.__bases__[1:] == (object,), # for baseobjspace.Wrappable - "single inheritance only right now: %r" % (cls,)) - if cls.__bases__: - base = cls.__bases__[0] - else: - base = object - self.basedef = bookkeeper.getclassdef(base) - if self.basedef: - self.basedef.subdefs[cls] = self - - # collect the (supposed constant) class attributes - for name, value in cls.__dict__.items(): - # ignore some special attributes - if name.startswith('_') and not isinstance(value, FunctionType): - continue - if isinstance(value, FunctionType): - value.class_ = cls # remember that this is really a method - self.add_source_for_attribute(name, cls, self) - - def add_source_for_attribute(self, attr, source, clsdef=None): - self.find_attribute(attr).sources[source] = clsdef - - def locate_attribute(self, attr): - for cdef in self.getmro(): - if attr in cdef.attrs: - return cdef - self.generalize_attr(attr) - return self - - def find_attribute(self, attr): - return self.locate_attribute(attr).attrs[attr] - - def __repr__(self): - return "" % (self.cls.__module__, self.cls.__name__) - - def commonbase(self, other): - while other is not None and not issubclass(self.cls, other.cls): - other = other.basedef - return other - - def superdef_containing(self, cls): - clsdef = self - while clsdef is not None and not issubclass(cls, clsdef.cls): - clsdef = clsdef.basedef - return clsdef - - def getmro(self): - while self is not None: - yield self - self = self.basedef - - def getallsubdefs(self): - pending = [self] - seen = {} - for clsdef in pending: - yield clsdef - for sub in clsdef.subdefs.values(): - if sub not in seen: - pending.append(sub) - seen[sub] = True - - def getallinstantiations(self): - locations = {} - for clsdef in self.getallsubdefs(): - locations.update(clsdef.instantiation_locations) - return locations - - def _generalize_attr(self, attr, s_value): - # first remove the attribute from subclasses -- including us! - subclass_attrs = [] - for subdef in self.getallsubdefs(): - if attr in subdef.attrs: - subclass_attrs.append(subdef.attrs[attr]) - del subdef.attrs[attr] - # bump the revision number of this class and all subclasses - subdef.revision += 1 - - # do the generalization - newattr = Attribute(attr, self.bookkeeper) - if s_value: - newattr.s_value = s_value - - for subattr in subclass_attrs: - newattr.merge(subattr) - self.attrs[attr] = newattr - - # reflow from all factories - for position in self.getallinstantiations(): - self.bookkeeper.annotator.reflowfromposition(position) - - def generalize_attr(self, attr, s_value=None): - # if the attribute exists in a superclass, generalize there. - for clsdef in self.getmro(): - if attr in clsdef.attrs: - clsdef._generalize_attr(attr, s_value) - else: - self._generalize_attr(attr, s_value) - - def about_attribute(self, name): - for cdef in self.getmro(): - if name in cdef.attrs: - s_result = cdef.attrs[name].s_value - if s_result != SomeImpossibleValue(): - return s_result - else: - return None - return None - - - -from pypy.annotation.builtin import BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Wed Nov 24 21:17:08 2004 @@ -4,7 +4,8 @@ from pypy.annotation.model import SomeInteger, SomeObject, SomeChar, SomeBool from pypy.annotation.model import SomeList, SomeString, SomeTuple -from pypy.annotation.factory import ListFactory, getbookkeeper +from pypy.annotation.bookkeeper import getbookkeeper +from pypy.annotation.factory import ListFactory from pypy.objspace.flow.model import Constant import pypy.objspace.std.restricted_int Copied: pypy/trunk/src/pypy/annotation/classdef.py (from r7664, pypy/trunk/src/pypy/annotation/factory.py) ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/classdef.py Wed Nov 24 21:17:08 2004 @@ -1,330 +1,10 @@ """ -Mutable Objects Factories. - -A factory is associated to an SpaceOperation in the source that creates a -mutable object, currently 'newlist' and 'call' (which can build instances). -The factory remembers how general an object it has to create here. +Type inference for user-defined classes. """ from __future__ import generators -import new -from types import FunctionType, ClassType, MethodType -from pypy.annotation.model import * -from pypy.interpreter.miscutils import getthreadlocals -from pypy.interpreter.pycode import CO_VARARGS -from pypy.tool.hack import func_with_new_name - -def ishashable(x): - try: - hash(x) - except TypeError: - return False - else: - return True - -class BlockedInference(Exception): - """This exception signals the type inference engine that the situation - is currently blocked, and that it should try to progress elsewhere.""" - - def __init__(self): - try: - self.break_at = getbookkeeper().position_key - except AttributeError: - self.break_at = None - - def __repr__(self): - return "" %(self.break_at,) - __str__ = __repr__ - -class Bookkeeper: - """The log of choices that have been made while analysing the operations. - It ensures that the same 'choice objects' will be returned if we ask - again during reflowing. Like ExecutionContext, there is an implicit - Bookkeeper that can be obtained from a thread-local variable. - - Currently used for factories and user-defined classes.""" - - def __init__(self, annotator): - self.annotator = annotator - self.creationpoints = {} # map position-in-a-block to its Factory - self.userclasses = {} # map classes to ClassDefs - self.userclasseslist = []# userclasses.keys() in creation order - self.cachespecializations = {} - self.pbccache = {} - - def enter(self, position_key): - """Start of an operation. - The operation is uniquely identified by the given key.""" - self.position_key = position_key - getthreadlocals().bookkeeper = self - - def leave(self): - """End of an operation.""" - del getthreadlocals().bookkeeper - del self.position_key - - def is_in_an_operation(self): - return hasattr(self, 'position_key') - - def getfactory(self, factorycls): - """Get the Factory associated with the current position, - or build it if it doesn't exist yet.""" - try: - factory = self.creationpoints[self.position_key] - except KeyError: - factory = factorycls() - factory.bookkeeper = self - factory.position_key = self.position_key - self.creationpoints[self.position_key] = factory - assert isinstance(factory, factorycls) - return factory - - def getclassdef(self, cls): - """Get the ClassDef associated with the given user cls.""" - if cls is object: - return None - try: - return self.userclasses[cls] - except KeyError: - cdef = ClassDef(cls, self) - self.userclasses[cls] = cdef - self.userclasseslist.append(cdef) - return self.userclasses[cls] - - - def immutablevalue(self, x): - """The most precise SomeValue instance that contains the - immutable value x.""" - tp = type(x) - if tp is bool: - result = SomeBool() - elif tp is int: - result = SomeInteger(nonneg = x>=0) - elif tp is str: - result = SomeString() - elif tp is tuple: - result = SomeTuple(items = [self.immutablevalue(e) for e in x]) - elif tp is list: - items_s = [self.immutablevalue(e) for e in x] - result = SomeList({}, unionof(*items_s)) - elif tp is dict: # exactly a dict - items = {} - for key, value in x.items(): - items[key] = self.immutablevalue(value) - result = SomeDict({}, items) - elif ishashable(x) and x in BUILTIN_ANALYZERS: - result = SomeBuiltin(BUILTIN_ANALYZERS[x]) - elif callable(x) or isinstance(x, staticmethod): # XXX - # maybe 'x' is a method bound to a not-yet-frozen cache? - # fun fun fun. - if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) - and not x.im_self.frozen): - x.im_self.freeze() - if hasattr(x, '__self__') and x.__self__ is not None: - s_self = self.immutablevalue(x.__self__) - # stop infinite recursion getattr<->immutablevalue - del s_self.const - s_name = self.immutablevalue(x.__name__) - result = s_self.getattr(s_name) - else: - return self.getpbc(x) - elif hasattr(x, '__class__') \ - and x.__class__.__module__ != '__builtin__': - if isinstance(x, Cache) and not x.frozen: - x.freeze() - return self.getpbc(x) - elif x is None: - return self.getpbc(None) - else: - result = SomeObject() - result.const = x - return result - - def getpbc(self, x): - try: - # this is not just an optimization, but needed to avoid - # infinitely repeated calls to add_source_for_attribute() - return self.pbccache[x] - except KeyError: - result = SomePBC({x: True}) # pre-built inst - clsdef = self.getclassdef(new_or_old_class(x)) - for attr in getattr(x, '__dict__', {}): - clsdef.add_source_for_attribute(attr, x) - self.pbccache[x] = result - return result - - def valueoftype(self, t): - """The most precise SomeValue instance that contains all - objects of type t.""" - if t is bool: - return SomeBool() - elif t is int: - return SomeInteger() - elif t is str: - return SomeString() - elif t is list: - return SomeList(factories={}) - # can't do dict, tuple - elif isinstance(t, (type, ClassType)) and \ - t.__module__ != '__builtin__': - classdef = self.getclassdef(t) - if self.is_in_an_operation(): - # woha! instantiating a "mutable" SomeXxx like - # SomeInstance is always dangerous, because we need to - # allow reflowing from the current operation if/when - # the classdef later changes. - classdef.instantiation_locations[self.position_key] = True - return SomeInstance(classdef) - else: - o = SomeObject() - o.knowntype = t - return o - - def pycall(self, func, *args): - if isinstance(func, (type, ClassType)) and \ - func.__module__ != '__builtin__': - cls = func - x = getattr(cls, "_specialize_", False) - if x: - if x == "location": - cls = self.specialize_by_key(cls, self.position_key) - else: - raise Exception, \ - "unsupported specialization type '%s'"%(x,) - - classdef = self.getclassdef(cls) - classdef.instantiation_locations[self.position_key] = True - s_instance = SomeInstance(classdef) - # flow into __init__() if the class has got one - init = getattr(cls, '__init__', None) - if init is not None and init != object.__init__: - attrdef = classdef.find_attribute('__init__') - attrdef.getvalue() - self.pycall(init, s_instance, *args) - else: - assert not args, "no __init__ found in %r" % (cls,) - return s_instance - if hasattr(func, '__call__') and \ - isinstance(func.__call__, MethodType): - func = func.__call__ - if hasattr(func, 'im_func'): - if func.im_self is not None: - s_self = self.immutablevalue(func.im_self) - args = [s_self] + list(args) - try: - func.im_func.class_ = func.im_class - except AttributeError: - # probably a builtin function, we don't care to preserve - # class information then - pass - func = func.im_func - assert isinstance(func, FunctionType), "expected function, got %r"%func - # do we need to specialize this function in several versions? - x = getattr(func, '_specialize_', False) - #if not x: - # x = 'argtypes' - if x: - if x == 'argtypes': - key = short_type_name(args) - func = self.specialize_by_key(func, key, - func.__name__+'__'+key) - elif x == "location": - # fully specialize: create one version per call position - func = self.specialize_by_key(func, self.position_key) - else: - raise Exception, "unsupported specialization type '%s'"%(x,) - - elif func.func_code.co_flags & CO_VARARGS: - # calls to *arg functions: create one version per number of args - func = self.specialize_by_key(func, len(args), - name='%s__%d' % (func.func_name, - len(args))) - return self.annotator.recursivecall(func, self.position_key, *args) - - def specialize_by_key(self, thing, key, name=None): - key = thing, key - try: - thing = self.cachespecializations[key] - except KeyError: - if isinstance(thing, FunctionType): - # XXX XXX XXX HAAAAAAAAAAAACK - self.annotator.translator.getflowgraph(thing) - thing = func_with_new_name(thing, name or thing.func_name) - elif isinstance(thing, (type, ClassType)): - assert not "not working yet" - thing = type(thing)(name or thing.__name__, (thing,)) - else: - raise Exception, "specializing %r?? why??"%thing - self.cachespecializations[key] = thing - return thing - - -def getbookkeeper(): - """Get the current Bookkeeper. - Only works during the analysis of an operation.""" - return getthreadlocals().bookkeeper - - -# -# Factories -# - -def generalize(factories, *args): - modified = [factory for factory in factories if factory.generalize(*args)] - if modified: - for factory in modified: - factory.bookkeeper.annotator.reflowfromposition(factory.position_key) - raise BlockedInference # reflow now - -def isclassdef(x): - return isinstance(x, ClassDef) - -class ListFactory: - s_item = SomeImpossibleValue() - - def __repr__(self): - return '%s(s_item=%r)' % (self.__class__.__name__, self.s_item) - - def create(self): - return SomeList(factories = {self: True}, s_item = self.s_item) - - def generalize(self, s_new_item): - if not self.s_item.contains(s_new_item): - self.s_item = unionof(self.s_item, s_new_item) - return True - else: - return False - - -class DictFactory: - items = {} - - def __repr__(self): - return '%s(items=%r)' % (self.__class__.__name__, self.items) - - def create(self): - return SomeDict(factories = {self: True}, items = self.items) - - def generalize(self, key, s_new_value): - self.items = self.items.copy() - if key not in self.items: - self.items[key] = s_new_value - return True - elif not self.items[key].contains(s_new_value): - self.items[key] = unionof(self.items[key], s_new_value) - return True - else: - return False - -def short_type_name(args): - l = [] - for x in args: - if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'): - name = "SI_" + x.knowntype.__name__ - else: - name = x.__class__.__name__ - l.append(name) - return "__".join(l) +from types import FunctionType +from pypy.annotation.model import SomeImpossibleValue, unionof class Attribute: @@ -477,5 +157,5 @@ return None - -from pypy.annotation.builtin import BUILTIN_ANALYZERS +def isclassdef(x): + return isinstance(x, ClassDef) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Wed Nov 24 21:17:08 2004 @@ -2,25 +2,14 @@ Mutable Objects Factories. A factory is associated to an SpaceOperation in the source that creates a -mutable object, currently 'newlist' and 'call' (which can build instances). +built-in mutable object: currently 'newlist' and 'newdict'. The factory remembers how general an object it has to create here. """ -from __future__ import generators -import new -from types import FunctionType, ClassType, MethodType -from pypy.annotation.model import * -from pypy.interpreter.miscutils import getthreadlocals -from pypy.interpreter.pycode import CO_VARARGS -from pypy.tool.hack import func_with_new_name - -def ishashable(x): - try: - hash(x) - except TypeError: - return False - else: - return True +from pypy.annotation.model import SomeList, SomeDict +from pypy.annotation.model import SomeImpossibleValue, unionof +from pypy.annotation.bookkeeper import getbookkeeper + class BlockedInference(Exception): """This exception signals the type inference engine that the situation @@ -36,248 +25,6 @@ return "" %(self.break_at,) __str__ = __repr__ -class Bookkeeper: - """The log of choices that have been made while analysing the operations. - It ensures that the same 'choice objects' will be returned if we ask - again during reflowing. Like ExecutionContext, there is an implicit - Bookkeeper that can be obtained from a thread-local variable. - - Currently used for factories and user-defined classes.""" - - def __init__(self, annotator): - self.annotator = annotator - self.creationpoints = {} # map position-in-a-block to its Factory - self.userclasses = {} # map classes to ClassDefs - self.userclasseslist = []# userclasses.keys() in creation order - self.cachespecializations = {} - self.pbccache = {} - - def enter(self, position_key): - """Start of an operation. - The operation is uniquely identified by the given key.""" - self.position_key = position_key - getthreadlocals().bookkeeper = self - - def leave(self): - """End of an operation.""" - del getthreadlocals().bookkeeper - del self.position_key - - def is_in_an_operation(self): - return hasattr(self, 'position_key') - - def getfactory(self, factorycls): - """Get the Factory associated with the current position, - or build it if it doesn't exist yet.""" - try: - factory = self.creationpoints[self.position_key] - except KeyError: - factory = factorycls() - factory.bookkeeper = self - factory.position_key = self.position_key - self.creationpoints[self.position_key] = factory - assert isinstance(factory, factorycls) - return factory - - def getclassdef(self, cls): - """Get the ClassDef associated with the given user cls.""" - if cls is object: - return None - try: - return self.userclasses[cls] - except KeyError: - cdef = ClassDef(cls, self) - self.userclasses[cls] = cdef - self.userclasseslist.append(cdef) - return self.userclasses[cls] - - - def immutablevalue(self, x): - """The most precise SomeValue instance that contains the - immutable value x.""" - tp = type(x) - if tp is bool: - result = SomeBool() - elif tp is int: - result = SomeInteger(nonneg = x>=0) - elif tp is str: - result = SomeString() - elif tp is tuple: - result = SomeTuple(items = [self.immutablevalue(e) for e in x]) - elif tp is list: - items_s = [self.immutablevalue(e) for e in x] - result = SomeList({}, unionof(*items_s)) - elif tp is dict: # exactly a dict - items = {} - for key, value in x.items(): - items[key] = self.immutablevalue(value) - result = SomeDict({}, items) - elif ishashable(x) and x in BUILTIN_ANALYZERS: - result = SomeBuiltin(BUILTIN_ANALYZERS[x]) - elif callable(x) or isinstance(x, staticmethod): # XXX - # maybe 'x' is a method bound to a not-yet-frozen cache? - # fun fun fun. - if (hasattr(x, 'im_self') and isinstance(x.im_self, Cache) - and not x.im_self.frozen): - x.im_self.freeze() - if hasattr(x, '__self__') and x.__self__ is not None: - s_self = self.immutablevalue(x.__self__) - # stop infinite recursion getattr<->immutablevalue - del s_self.const - s_name = self.immutablevalue(x.__name__) - result = s_self.getattr(s_name) - else: - return self.getpbc(x) - elif hasattr(x, '__class__') \ - and x.__class__.__module__ != '__builtin__': - if isinstance(x, Cache) and not x.frozen: - x.freeze() - return self.getpbc(x) - elif x is None: - return self.getpbc(None) - else: - result = SomeObject() - result.const = x - return result - - def getpbc(self, x): - try: - # this is not just an optimization, but needed to avoid - # infinitely repeated calls to add_source_for_attribute() - return self.pbccache[x] - except KeyError: - result = SomePBC({x: True}) # pre-built inst - clsdef = self.getclassdef(new_or_old_class(x)) - for attr in getattr(x, '__dict__', {}): - clsdef.add_source_for_attribute(attr, x) - self.pbccache[x] = result - return result - - def valueoftype(self, t): - """The most precise SomeValue instance that contains all - objects of type t.""" - if t is bool: - return SomeBool() - elif t is int: - return SomeInteger() - elif t is str: - return SomeString() - elif t is list: - return SomeList(factories={}) - # can't do dict, tuple - elif isinstance(t, (type, ClassType)) and \ - t.__module__ != '__builtin__': - classdef = self.getclassdef(t) - if self.is_in_an_operation(): - # woha! instantiating a "mutable" SomeXxx like - # SomeInstance is always dangerous, because we need to - # allow reflowing from the current operation if/when - # the classdef later changes. - classdef.instantiation_locations[self.position_key] = True - return SomeInstance(classdef) - else: - o = SomeObject() - o.knowntype = t - return o - - def pycall(self, func, *args): - if isinstance(func, (type, ClassType)) and \ - func.__module__ != '__builtin__': - cls = func - x = getattr(cls, "_specialize_", False) - if x: - if x == "location": - cls = self.specialize_by_key(cls, self.position_key) - else: - raise Exception, \ - "unsupported specialization type '%s'"%(x,) - - classdef = self.getclassdef(cls) - classdef.instantiation_locations[self.position_key] = True - s_instance = SomeInstance(classdef) - # flow into __init__() if the class has got one - init = getattr(cls, '__init__', None) - if init is not None and init != object.__init__: - attrdef = classdef.find_attribute('__init__') - attrdef.getvalue() - self.pycall(init, s_instance, *args) - else: - assert not args, "no __init__ found in %r" % (cls,) - return s_instance - if hasattr(func, '__call__') and \ - isinstance(func.__call__, MethodType): - func = func.__call__ - if hasattr(func, 'im_func'): - if func.im_self is not None: - s_self = self.immutablevalue(func.im_self) - args = [s_self] + list(args) - try: - func.im_func.class_ = func.im_class - except AttributeError: - # probably a builtin function, we don't care to preserve - # class information then - pass - func = func.im_func - assert isinstance(func, FunctionType), "expected function, got %r"%func - # do we need to specialize this function in several versions? - x = getattr(func, '_specialize_', False) - #if not x: - # x = 'argtypes' - if x: - if x == 'argtypes': - key = short_type_name(args) - func = self.specialize_by_key(func, key, - func.__name__+'__'+key) - elif x == "location": - # fully specialize: create one version per call position - func = self.specialize_by_key(func, self.position_key) - else: - raise Exception, "unsupported specialization type '%s'"%(x,) - - elif func.func_code.co_flags & CO_VARARGS: - # calls to *arg functions: create one version per number of args - func = self.specialize_by_key(func, len(args), - name='%s__%d' % (func.func_name, - len(args))) - return self.annotator.recursivecall(func, self.position_key, *args) - - def specialize_by_key(self, thing, key, name=None): - key = thing, key - try: - thing = self.cachespecializations[key] - except KeyError: - if isinstance(thing, FunctionType): - # XXX XXX XXX HAAAAAAAAAAAACK - self.annotator.translator.getflowgraph(thing) - thing = func_with_new_name(thing, name or thing.func_name) - elif isinstance(thing, (type, ClassType)): - assert not "not working yet" - thing = type(thing)(name or thing.__name__, (thing,)) - else: - raise Exception, "specializing %r?? why??"%thing - self.cachespecializations[key] = thing - return thing - - -def getbookkeeper(): - """Get the current Bookkeeper. - Only works during the analysis of an operation.""" - return getthreadlocals().bookkeeper - - -# -# Factories -# - -def generalize(factories, *args): - modified = [factory for factory in factories if factory.generalize(*args)] - if modified: - for factory in modified: - factory.bookkeeper.annotator.reflowfromposition(factory.position_key) - raise BlockedInference # reflow now - -def isclassdef(x): - return isinstance(x, ClassDef) class ListFactory: s_item = SomeImpossibleValue() @@ -316,166 +63,14 @@ else: return False -def short_type_name(args): - l = [] - for x in args: - if isinstance(x, SomeInstance) and hasattr(x, 'knowntype'): - name = "SI_" + x.knowntype.__name__ - else: - name = x.__class__.__name__ - l.append(name) - return "__".join(l) - - -class Attribute: - # readonly-ness - # SomeThing-ness - # more potential sources (pbcs or classes) of information - - def __init__(self, name, bookkeeper): - self.name = name - self.bookkeeper = bookkeeper - self.sources = {} # source -> None or ClassDef - # XXX a SomeImpossibleValue() constant? later!! - self.s_value = SomeImpossibleValue() - self.readonly = True - - def getvalue(self): - while self.sources: - source, classdef = self.sources.popitem() - s_value = self.bookkeeper.immutablevalue( - source.__dict__[self.name]) - if classdef: - s_value = s_value.bindcallables(classdef) - self.s_value = unionof(self.s_value, s_value) - return self.s_value - - def merge(self, other): - assert self.name == other.name - self.sources.update(other.sources) - self.s_value = unionof(self.s_value, other.s_value) - self.readonly = self.readonly and other.readonly - - -class ClassDef: - "Wraps a user class." - - def __init__(self, cls, bookkeeper): - self.bookkeeper = bookkeeper - self.attrs = {} # {name: Attribute} - self.revision = 0 # which increases the revision number - self.instantiation_locations = {} - self.cls = cls - self.subdefs = {} - assert (len(cls.__bases__) <= 1 or - cls.__bases__[1:] == (object,), # for baseobjspace.Wrappable - "single inheritance only right now: %r" % (cls,)) - if cls.__bases__: - base = cls.__bases__[0] - else: - base = object - self.basedef = bookkeeper.getclassdef(base) - if self.basedef: - self.basedef.subdefs[cls] = self - - # collect the (supposed constant) class attributes - for name, value in cls.__dict__.items(): - # ignore some special attributes - if name.startswith('_') and not isinstance(value, FunctionType): - continue - if isinstance(value, FunctionType): - value.class_ = cls # remember that this is really a method - self.add_source_for_attribute(name, cls, self) - - def add_source_for_attribute(self, attr, source, clsdef=None): - self.find_attribute(attr).sources[source] = clsdef - - def locate_attribute(self, attr): - for cdef in self.getmro(): - if attr in cdef.attrs: - return cdef - self.generalize_attr(attr) - return self - - def find_attribute(self, attr): - return self.locate_attribute(attr).attrs[attr] - - def __repr__(self): - return "" % (self.cls.__module__, self.cls.__name__) - - def commonbase(self, other): - while other is not None and not issubclass(self.cls, other.cls): - other = other.basedef - return other - - def superdef_containing(self, cls): - clsdef = self - while clsdef is not None and not issubclass(cls, clsdef.cls): - clsdef = clsdef.basedef - return clsdef - - def getmro(self): - while self is not None: - yield self - self = self.basedef - - def getallsubdefs(self): - pending = [self] - seen = {} - for clsdef in pending: - yield clsdef - for sub in clsdef.subdefs.values(): - if sub not in seen: - pending.append(sub) - seen[sub] = True - - def getallinstantiations(self): - locations = {} - for clsdef in self.getallsubdefs(): - locations.update(clsdef.instantiation_locations) - return locations - - def _generalize_attr(self, attr, s_value): - # first remove the attribute from subclasses -- including us! - subclass_attrs = [] - for subdef in self.getallsubdefs(): - if attr in subdef.attrs: - subclass_attrs.append(subdef.attrs[attr]) - del subdef.attrs[attr] - # bump the revision number of this class and all subclasses - subdef.revision += 1 - - # do the generalization - newattr = Attribute(attr, self.bookkeeper) - if s_value: - newattr.s_value = s_value - - for subattr in subclass_attrs: - newattr.merge(subattr) - self.attrs[attr] = newattr - - # reflow from all factories - for position in self.getallinstantiations(): - self.bookkeeper.annotator.reflowfromposition(position) - - def generalize_attr(self, attr, s_value=None): - # if the attribute exists in a superclass, generalize there. - for clsdef in self.getmro(): - if attr in clsdef.attrs: - clsdef._generalize_attr(attr, s_value) - else: - self._generalize_attr(attr, s_value) - - def about_attribute(self, name): - for cdef in self.getmro(): - if name in cdef.attrs: - s_result = cdef.attrs[name].s_value - if s_result != SomeImpossibleValue(): - return s_result - else: - return None - return None - - -from pypy.annotation.builtin import BUILTIN_ANALYZERS +def generalize(factories, *args): + """Signals all the factories in the given set to generalize themselves. + The args must match the signature of the generalize() method of the + particular factories (which should all be of the same class). + """ + modified = [factory for factory in factories if factory.generalize(*args)] + if modified: + for factory in modified: + factory.bookkeeper.annotator.reflowfromposition(factory.position_key) + raise BlockedInference # reflow now Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Wed Nov 24 21:17:08 2004 @@ -60,7 +60,8 @@ def __new__(cls, *args, **kw): self = super(SomeObject, cls).__new__(cls, *args, **kw) try: - position_key = pypy.annotation.factory.getbookkeeper().position_key + bookkeeper = pypy.annotation.bookkeeper.getbookkeeper() + position_key = bookkeeper.position_key except AttributeError: pass else: @@ -240,4 +241,3 @@ # this has the side-effect of registering the unary and binary operations from pypy.annotation.unaryop import UNARY_OPERATIONS from pypy.annotation.binaryop import BINARY_OPERATIONS -from pypy.annotation.builtin import BUILTIN_ANALYZERS Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Wed Nov 24 21:17:08 2004 @@ -10,8 +10,9 @@ from pypy.annotation.model import SomeInstance, SomeBuiltin from pypy.annotation.model import SomeIterator, SomePBC, new_or_old_class from pypy.annotation.model import unionof, set, setunion, missing_operation -from pypy.annotation.factory import BlockedInference, getbookkeeper -from pypy.annotation.factory import isclassdef +from pypy.annotation.factory import BlockedInference +from pypy.annotation.bookkeeper import getbookkeeper +from pypy.annotation.classdef import isclassdef # convenience only! def immutablevalue(x): Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Wed Nov 24 21:17:08 2004 @@ -3,8 +3,8 @@ from types import FunctionType, ClassType from pypy.annotation import model as annmodel from pypy.annotation.model import pair -from pypy.annotation.factory import ListFactory, DictFactory -from pypy.annotation.factory import BlockedInference, Bookkeeper +from pypy.annotation.factory import ListFactory, DictFactory, BlockedInference +from pypy.annotation.bookkeeper import Bookkeeper from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation, FunctionGraph from pypy.objspace.flow.model import last_exception, last_exc_value Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Wed Nov 24 21:17:08 2004 @@ -7,7 +7,7 @@ from pypy.objspace.flow.model import mkentrymap, last_exception from pypy.translator.annrpython import RPythonAnnotator from pypy.annotation.model import SomePBC -from pypy.annotation.factory import isclassdef +from pypy.annotation.classdef import isclassdef import inspect class Op: From arigo at codespeak.net Thu Nov 25 11:45:47 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 25 Nov 2004 11:45:47 +0100 (MET) Subject: [pypy-svn] r7670 - pypy/trunk/src/pypy/annotation Message-ID: <20041125104547.3F1085B151@thoth.codespeak.net> Author: arigo Date: Thu Nov 25 11:45:46 2004 New Revision: 7670 Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py Log: Fixed the handling of the implicit call to __init__ upon instance creation. Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/trunk/src/pypy/annotation/bookkeeper.py (original) +++ pypy/trunk/src/pypy/annotation/bookkeeper.py Thu Nov 25 11:45:46 2004 @@ -3,6 +3,7 @@ """ from types import FunctionType, ClassType, MethodType +from types import BuiltinMethodType from pypy.annotation.model import * from pypy.annotation.classdef import ClassDef from pypy.interpreter.miscutils import getthreadlocals @@ -174,9 +175,15 @@ # flow into __init__() if the class has got one init = getattr(cls, '__init__', None) if init is not None and init != object.__init__: - attrdef = classdef.find_attribute('__init__') - attrdef.getvalue() - self.pycall(init, s_instance, *args) + # don't record the access of __init__ on the classdef + # because it is not a dynamic attribute look-up, but + # merely a static function call + if hasattr(init, 'im_func'): + init = init.im_func + else: + assert isinstance(init, BuiltinMethodType) + s_init = self.immutablevalue(init) + s_init.simple_call(s_instance, *args) else: assert not args, "no __init__ found in %r" % (cls,) return s_instance From arigo at codespeak.net Thu Nov 25 12:37:25 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 25 Nov 2004 12:37:25 +0100 (MET) Subject: [pypy-svn] r7671 - pypy/trunk/src/pypy/annotation Message-ID: <20041125113725.BAD515B051@thoth.codespeak.net> Author: arigo Date: Thu Nov 25 12:37:25 2004 New Revision: 7671 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/unaryop.py Log: The assert contains() is still failing for wrong reasons related to revision numbers. Gave up and implemented a contains() that ignores revision numbers. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu Nov 25 12:37:25 2004 @@ -256,11 +256,6 @@ class __extend__(pairtype(SomeInstance, SomeInstance)): def union((ins1, ins2)): - if ins1.classdef == ins2.classdef: - if ins1.revision > ins2.revision: - return ins1 - else: - return ins2 basedef = ins1.classdef.commonbase(ins2.classdef) if basedef is None: # print warning? Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu Nov 25 12:37:25 2004 @@ -150,6 +150,14 @@ raise BlockedInference return + def contains(self, other): + # override the default contains() to ignore revision numbers + if self == other: + return True + s_union = pair(self, other).union() + return (isinstance(s_union, SomeInstance) and + s_union.classdef is self.classdef) + class __extend__(SomeBuiltin): def simple_call(bltn, *args): From arigo at codespeak.net Sat Nov 27 22:33:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 27 Nov 2004 22:33:58 +0100 (MET) Subject: [pypy-svn] r7690 - pypy/trunk/src/pypy/annotation Message-ID: <20041127213358.49AE05A1D3@thoth.codespeak.net> Author: arigo Date: Sat Nov 27 22:33:57 2004 New Revision: 7690 Modified: pypy/trunk/src/pypy/annotation/builtin.py Log: support for the built-in method Exception.__init__. Modified: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- pypy/trunk/src/pypy/annotation/builtin.py (original) +++ pypy/trunk/src/pypy/annotation/builtin.py Sat Nov 27 22:33:57 2004 @@ -126,6 +126,9 @@ print "XXX ignoring apply%r" % (stuff,) return SomeObject() +def exception_init(s_self, *args): + s_self.setattr(immutablevalue('args'), SomeTuple(args)) + # collect all functions import __builtin__ BUILTIN_ANALYZERS = {} @@ -136,3 +139,5 @@ BUILTIN_ANALYZERS[pypy.objspace.std.restricted_int.r_int] = builtin_int BUILTIN_ANALYZERS[pypy.objspace.std.restricted_int.r_uint] = restricted_uint +BUILTIN_ANALYZERS[Exception.__init__.im_func] = exception_init + From arigo at codespeak.net Sat Nov 27 23:47:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 27 Nov 2004 23:47:58 +0100 (MET) Subject: [pypy-svn] r7691 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041127224758.66C365A1D3@thoth.codespeak.net> Author: arigo Date: Sat Nov 27 23:47:57 2004 New Revision: 7691 Modified: pypy/trunk/src/pypy/objspace/std/fake.py Log: Marked this as not RPython. Modified: pypy/trunk/src/pypy/objspace/std/fake.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/fake.py (original) +++ pypy/trunk/src/pypy/objspace/std/fake.py Sat Nov 27 23:47:57 2004 @@ -112,6 +112,7 @@ from pypy.interpreter.typedef import GetSetProperty def fake_descriptor(space, d): + "NOT_RPYTHON (don't try to fake extra descriptors after initialization!)" n = d.__name__ return space.wrap(GetSetProperty(lambda x:getattr(x, n), lambda x,y:setattr(x, n, y))) From arigo at codespeak.net Sat Nov 27 23:48:57 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 27 Nov 2004 23:48:57 +0100 (MET) Subject: [pypy-svn] r7692 - pypy/trunk/src/pypy/translator Message-ID: <20041127224857.D80A05A1D3@thoth.codespeak.net> Author: arigo Date: Sat Nov 27 23:48:57 2004 New Revision: 7692 Modified: pypy/trunk/src/pypy/translator/genc.py Log: Generic handling of characters forbidden in C identifiers. Triggered by the bug that "gfunc_" isn't a valid C identifier :-) Modified: pypy/trunk/src/pypy/translator/genc.py ============================================================================== --- pypy/trunk/src/pypy/translator/genc.py (original) +++ pypy/trunk/src/pypy/translator/genc.py Sat Nov 27 23:48:57 2004 @@ -93,6 +93,7 @@ return name def uniquename(self, basename): + basename = basename.translate(C_IDENTIFIER) n = self.seennames.get(basename, 0) self.seennames[basename] = n+1 if n == 0: @@ -145,22 +146,13 @@ name = 'gfloat_%s' % value name = (name.replace('-', 'minus') .replace('.', 'dot')) - chrs = [c for c in name if ('a' <= c <='z' or - 'A' <= c <='Z' or - '0' <= c <='9' or - '_' == c )] - name = ''.join(chrs) name = self.uniquename(name) self.initcode.append('INITCHK(%s = ' 'PyFloat_FromDouble(%r))' % (name, value)) return name def nameof_str(self, value): - chrs = [c for c in value[:32] if ('a' <= c <='z' or - 'A' <= c <='Z' or - '0' <= c <='9' or - '_' == c )] - name = self.uniquename('gstr_' + ''.join(chrs)) + name = self.uniquename('gstr_' + value[:32]) if [c for c in value if c<' ' or c>'~' or c=='"' or c=='\\']: # non-printable string s = 'chr_%s' % name @@ -837,3 +829,10 @@ return type.replace('@', name) else: return ('%s %s' % (type, name)).rstrip() + +# a translation table suitable for str.translate() to remove +# non-C characters from an identifier +C_IDENTIFIER = ''.join([(('0' <= chr(i) <= '9' or + 'a' <= chr(i) <= 'z' or + 'A' <= chr(i) <= 'Z') and chr(i) or '_') + for i in range(256)]) From arigo at codespeak.net Sun Nov 28 04:27:36 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 28 Nov 2004 04:27:36 +0100 (MET) Subject: [pypy-svn] r7693 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20041128032736.C00395AEDF@thoth.codespeak.net> Author: arigo Date: Sun Nov 28 04:27:34 2004 New Revision: 7693 Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Oups. Forgot to fix this. Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sun Nov 28 04:27:34 2004 @@ -3,7 +3,8 @@ from pypy.translator.tool.pygame.drawgraph import GraphLayout from pypy.translator.tool.make_dot import DotGen from pypy.interpreter.pycode import CO_VARARGS, CO_VARKEYWORDS -from pypy.annotation import model, factory +from pypy.annotation import model +from pypy.annotation.classdef import ClassDef from pypy.tool.uid import uid @@ -202,7 +203,7 @@ # link the function names to the individual flow graphs for name, obj in self.object_by_name.iteritems(): - if isinstance(obj, factory.ClassDef): + if isinstance(obj, ClassDef): #data = '%s.%s' % (obj.cls.__module__, obj.cls.__name__) data = repr(obj.cls) else: @@ -228,7 +229,7 @@ def followlink(self, name): obj = self.object_by_name[name] - if isinstance(obj, factory.ClassDef): + if isinstance(obj, ClassDef): return ClassDefLayout(self.translator, obj) else: return FlowGraphLayout(self.translator, [obj], self.name_by_object) From arigo at codespeak.net Sun Nov 28 13:01:54 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 28 Nov 2004 13:01:54 +0100 (MET) Subject: [pypy-svn] r7694 - in pypy/trunk/src/pypy/translator: . tool/pygame Message-ID: <20041128120154.A16555A8B2@thoth.codespeak.net> Author: arigo Date: Sun Nov 28 13:01:53 2004 New Revision: 7694 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Re-oups. A previous check-in broked the history of variables in the pygame viewer. Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sun Nov 28 13:01:53 2004 @@ -31,10 +31,10 @@ self.blocked_functions = {} # set of functions that have blocked blocks self.notify = {} # {block: {positions-to-reflow-from-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues - self.binding_caused_by = {} # map Variables to Factories - # records the FuncCallFactory that caused bindings of inputargs - # to be updated - self.binding_cause_history = {} # map Variables to lists of Factories + self.binding_caused_by = {} # map Variables to position_keys + # records the caller position that caused bindings of inputargs + # to be updated + self.binding_cause_history = {} # map Variables to lists of positions # history of binding_caused_by, kept in sync with # bindingshistory self.bookkeeper = Bookkeeper(self) Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Sun Nov 28 13:01:53 2004 @@ -30,7 +30,7 @@ if info.origin is not None: label += "\\n" + self.createlink(info.origin, 'Originated at') if caused_by is not None: - label += '\\n' + self.createlink(caused_by.position_key) + label += '\\n' + self.createlink(caused_by) if info.caused_by_merge is not None: data = 'unionof%r' % (info.caused_by_merge,) label += '\\n%s' % nottoowide(data) @@ -41,7 +41,7 @@ if data.origin is not None: label += "\\n" + self.createlink(data.origin, 'Originated at') if caused_by is not None: - label += '\\n' + self.createlink(caused_by.position_key) + label += '\\n' + self.createlink(caused_by) dotgen.emit_node(str(n+1), shape="box", label=label) dotgen.emit_edge(str(n+1), str(n)) links = self.links # GraphLayout.__init__ will override it with {} From arigo at codespeak.net Mon Nov 29 14:57:37 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 29 Nov 2004 14:57:37 +0100 (MET) Subject: [pypy-svn] r7701 - in pypy/trunk/src: goal pypy/annotation pypy/translator pypy/translator/tool/pygame Message-ID: <20041129135737.E6EF75AC7E@thoth.codespeak.net> Author: arigo Date: Mon Nov 29 14:57:37 2004 New Revision: 7701 Modified: pypy/trunk/src/goal/translate_pypy.py pypy/trunk/src/pypy/annotation/bookkeeper.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Log: Added a global flag pypy.annotation.model.DEBUG which can be set to False to disable the collecting of debugging information. Also added comments to (some) places where things are done for debugging purpose only. 'translate_pypy.py -no-d' sets DEBUG to False; this can run longer before it runs out of memory :-) Modified: pypy/trunk/src/goal/translate_pypy.py ============================================================================== --- pypy/trunk/src/goal/translate_pypy.py (original) +++ pypy/trunk/src/goal/translate_pypy.py Mon Nov 29 14:57:37 2004 @@ -13,6 +13,7 @@ Do not mark functions that have SomeObject in their signature. -tcc Equivalent to the envvar PYPY_CC='tcc -shared -o "%s.so" "%s.c"' -- http://fabrice.bellard.free.fr/tcc/ + -no-d Disable recording of debugging information """ import autopath, sys, threading, pdb, os from pypy.objspace.std.objspace import StdObjSpace, W_Object @@ -146,6 +147,7 @@ '-no-mark-some-objects': False, '-no-a': False, '-tcc': False, + '-no-d': False, } for arg in sys.argv[1:]: if arg in ('-h', '--help'): @@ -155,6 +157,8 @@ options[arg] = True if options['-tcc']: os.environ['PYPY_CC'] = 'tcc -shared -o "%s.so" "%s.c"' + if options['-no-d']: + annmodel.DEBUG = False def about(x): """ interactive debugging helper """ Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/trunk/src/pypy/annotation/bookkeeper.py (original) +++ pypy/trunk/src/pypy/annotation/bookkeeper.py Mon Nov 29 14:57:37 2004 @@ -194,6 +194,7 @@ if func.im_self is not None: s_self = self.immutablevalue(func.im_self) args = [s_self] + list(args) + # for debugging only, but useful to keep anyway: try: func.im_func.class_ = func.im_class except AttributeError: Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Mon Nov 29 14:57:37 2004 @@ -37,6 +37,9 @@ import inspect +DEBUG = True # set to False to disable recording of debugging information + + class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" @@ -56,16 +59,18 @@ return hasattr(self, 'const') # for debugging, record where each instance comes from + # this is disabled if DEBUG is set to False _coming_from = {} def __new__(cls, *args, **kw): self = super(SomeObject, cls).__new__(cls, *args, **kw) - try: - bookkeeper = pypy.annotation.bookkeeper.getbookkeeper() - position_key = bookkeeper.position_key - except AttributeError: - pass - else: - SomeObject._coming_from[id(self)] = position_key, None + if DEBUG: + try: + bookkeeper = pypy.annotation.bookkeeper.getbookkeeper() + position_key = bookkeeper.position_key + except AttributeError: + pass + else: + SomeObject._coming_from[id(self)] = position_key, None return self def origin(self): return SomeObject._coming_from.get(id(self), (None, None))[0] @@ -199,7 +204,7 @@ for s2 in somevalues: if s1 != s2: s1 = pair(s1, s2).union() - if s1.caused_by_merge is None and len(somevalues) > 1: + if DEBUG and s1.caused_by_merge is None and len(somevalues) > 1: s1.caused_by_merge = somevalues return s1 Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Mon Nov 29 14:57:37 2004 @@ -25,11 +25,13 @@ self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen self.links_followed = {} # set of links that have ever been followed + self.notify = {} # {block: {positions-to-reflow-from-when-done}} + # --- the following information is recorded for debugging only --- + # --- and only if annotation.model.DEBUG is kept to True self.why_not_annotated = {} # {block: (exc_type, exc_value, traceback)} # records the location of BlockedInference # exceptions that blocked some blocks. self.blocked_functions = {} # set of functions that have blocked blocks - self.notify = {} # {block: {positions-to-reflow-from-when-done}} self.bindingshistory = {}# map Variables to lists of SomeValues self.binding_caused_by = {} # map Variables to position_keys # records the caller position that caused bindings of inputargs @@ -37,6 +39,7 @@ self.binding_cause_history = {} # map Variables to lists of positions # history of binding_caused_by, kept in sync with # bindingshistory + # --- end of debugging information --- self.bookkeeper = Bookkeeper(self) #___ convenience high-level interface __________________ @@ -98,7 +101,6 @@ for attr, s_value in clsdef.attrs.items(): v = Variable(name=attr) self.bindings[v] = s_value - self.binding_caused_by[v] = None yield v #___ medium-level interface ____________________________ @@ -118,18 +120,19 @@ fn, block, cells, called_from = self.pendingblocks.pop() self.processblock(fn, block, cells, called_from) if False in self.annotated.values(): - for block in self.annotated: - if self.annotated[block] is False: - fn = self.why_not_annotated[block][1].break_at[0] - self.blocked_functions[fn] = True - import traceback - print '-+' * 30 - print 'BLOCKED block at:', - print self.why_not_annotated[block][1].break_at - print 'because of:' - traceback.print_exception(*self.why_not_annotated[block]) - print '-+' * 30 - print + if annmodel.DEBUG: + for block in self.annotated: + if self.annotated[block] is False: + fn = self.why_not_annotated[block][1].break_at[0] + self.blocked_functions[fn] = True + import traceback + print '-+' * 30 + print 'BLOCKED block at:', + print self.why_not_annotated[block][1].break_at + print 'because of:' + traceback.print_exception(*self.why_not_annotated[block]) + print '-+' * 30 + print print "++-" * 20 print ('%d blocks are still blocked' % self.annotated.values().count(False)) @@ -158,12 +161,14 @@ assert s_value.contains(self.bindings[arg]) # for debugging purposes, record the history of bindings that # have been given to this variable - history = self.bindingshistory.setdefault(arg, []) - history.append(self.bindings[arg]) - cause_history = self.binding_cause_history.setdefault(arg, []) - cause_history.append(self.binding_caused_by[arg]) + if annmodel.DEBUG: + history = self.bindingshistory.setdefault(arg, []) + history.append(self.bindings[arg]) + cause_history = self.binding_cause_history.setdefault(arg, []) + cause_history.append(self.binding_caused_by[arg]) self.bindings[arg] = s_value - self.binding_caused_by[arg] = called_from + if annmodel.DEBUG: + self.binding_caused_by[arg] = called_from #___ interface for annotator.factory _______ @@ -300,8 +305,9 @@ #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily - import sys - self.why_not_annotated[block] = sys.exc_info() + if annmodel.DEBUG: + import sys + self.why_not_annotated[block] = sys.exc_info() except Exception, e: # hack for debug tools only if not hasattr(e, '__annotator_block'): Modified: pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/flowviewer.py Mon Nov 29 14:57:37 2004 @@ -96,9 +96,11 @@ info = '%s: %s' % (var.name, s_value) self.links[var.name] = info self.current_value[var.name] = s_value - self.caused_by[var.name] = self.annotator.binding_caused_by[var] + self.caused_by[var.name] = ( + self.annotator.binding_caused_by.get(var)) for var, history in self.annotator.bindingshistory.items(): - cause_history = self.annotator.binding_cause_history[var] + cause_history = ( + self.annotator.binding_cause_history.get(var, [])) self.binding_history[var.name] = zip(history, cause_history) def followlink(self, varname): From arigo at codespeak.net Mon Nov 29 15:33:17 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 29 Nov 2004 15:33:17 +0100 (MET) Subject: [pypy-svn] r7702 - pypy/trunk/src/pypy/annotation Message-ID: <20041129143317.42E885AC7E@thoth.codespeak.net> Author: arigo Date: Mon Nov 29 15:33:16 2004 New Revision: 7702 Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py Log: consider None as a NULL function pointer. Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/trunk/src/pypy/annotation/bookkeeper.py (original) +++ pypy/trunk/src/pypy/annotation/bookkeeper.py Mon Nov 29 15:33:16 2004 @@ -158,6 +158,8 @@ return o def pycall(self, func, *args): + if func is None: # consider None as a NULL function pointer + return SomeImpossibleValue() if isinstance(func, (type, ClassType)) and \ func.__module__ != '__builtin__': cls = func From arigo at codespeak.net Mon Nov 29 15:58:26 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 29 Nov 2004 15:58:26 +0100 (MET) Subject: [pypy-svn] r7703 - pypy/trunk/src/pypy/annotation Message-ID: <20041129145826.663DB5AC7E@thoth.codespeak.net> Author: arigo Date: Mon Nov 29 15:58:25 2004 New Revision: 7703 Modified: pypy/trunk/src/pypy/annotation/unaryop.py Log: the method str.join(). Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Mon Nov 29 15:58:25 2004 @@ -100,6 +100,9 @@ class __extend__(SomeString): + def method_join(str, s_list): + return SomeString() + def iter(str): return SomeIterator(SomeChar()) From arigo at codespeak.net Mon Nov 29 16:14:31 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 29 Nov 2004 16:14:31 +0100 (MET) Subject: [pypy-svn] r7704 - pypy/trunk/src/pypy/translator/test Message-ID: <20041129151431.537AD5AC7E@thoth.codespeak.net> Author: arigo Date: Mon Nov 29 16:14:30 2004 New Revision: 7704 Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: A test for the fragile hack in immutabluevalue(). Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_annrpython.py (original) +++ pypy/trunk/src/pypy/translator/test/test_annrpython.py Mon Nov 29 16:14:30 2004 @@ -359,6 +359,25 @@ # this example used to trigger an AssertionError a.build_types(snippet.somepbc_simplify, []) + def test_builtin_methods(self): + a = RPythonAnnotator() + iv = a.bookkeeper.immutablevalue + # this checks that some built-in methods are really supported by + # the annotator (it doesn't check that they operate property, though) + for example, methname, s_example in [ + ('', 'join', annmodel.SomeString()), + ([], 'append', annmodel.SomeList({})), + ([], 'reverse', annmodel.SomeList({})), + ([], 'insert', annmodel.SomeList({})), + ([], 'pop', annmodel.SomeList({})), + ]: + constmeth = getattr(example, methname) + s_constmeth = iv(constmeth) + self.assert_(isinstance(s_constmeth, annmodel.SomeBuiltin)) + s_meth = s_example.getattr(iv(methname)) + self.assert_(isinstance(s_constmeth, annmodel.SomeBuiltin)) + + def g(n): return [0,1,2,n] From arigo at codespeak.net Mon Nov 29 18:56:12 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 29 Nov 2004 18:56:12 +0100 (MET) Subject: [pypy-svn] r7705 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20041129175612.D706A5AC7E@thoth.codespeak.net> Author: arigo Date: Mon Nov 29 18:56:12 2004 New Revision: 7705 Added: pypy/trunk/src/pypy/objspace/std/test/test_strutil.py (contents, props changed) Modified: pypy/trunk/src/pypy/objspace/std/inttype.py Log: A pure Python reimplementation of int(str, base), with a test suite. Modified: pypy/trunk/src/pypy/objspace/std/inttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/inttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/inttype.py Mon Nov 29 18:56:12 2004 @@ -1,38 +1,47 @@ from pypy.objspace.std.stdtypedef import * +from pypy.objspace.std.strutil import string_to_int from pypy.interpreter.error import OperationError def descr__new__(space, w_inttype, w_value=None, w_base=None): from pypy.objspace.std.intobject import W_IntObject if w_base is None: - w_base = space.w_None - if w_value is None: - value = 0 - elif w_base == space.w_None and not space.is_true(space.isinstance(w_value, space.w_str)): - w_obj = space.int(w_value) - if space.is_true(space.is_(w_inttype, space.w_int)): - return w_obj # 'int(x)' should return whatever x.__int__() returned - value = space.unwrap(w_obj) - if not isinstance(value, int): # XXX typechecking in unwrap! - raise OperationError(space.w_ValueError, + # check for easy cases + if w_value is None: + value = 0 + elif isinstance(w_value, W_IntObject): + value = w_value.intval + elif space.is_true(space.isinstance(w_value, space.w_str)): + try: + value = string_to_int(space.unwrap(w_value)) + except ValueError, e: + raise OperationError(space.w_ValueError, + space.wrap(e.args[0])) + else: + # otherwise, use the __int__() method + w_obj = space.int(w_value) + # 'int(x)' should return whatever x.__int__() returned + if space.is_true(space.is_(w_inttype, space.w_int)): + return w_obj + value = space.unwrap(w_obj) + if not isinstance(value, int): # XXX typechecking in unwrap! + raise OperationError(space.w_ValueError, space.wrap("value can't be converted to int")) else: - if w_base == space.w_None: - base = -909 # don't blame us!! - else: - base = space.unwrap(w_base) - # XXX write the logic for int("str", base) + base = space.unwrap(w_base) + if not isinstance(base, int): # XXX typechecking in unwrap! + raise OperationError(space.w_TypeError, + space.wrap("an integer is required")) s = space.unwrap(w_value) - try: - value = int(s, base) - except TypeError, e: + if not isinstance(s, str): # XXX typechecking in unwrap! raise OperationError(space.w_TypeError, - space.wrap(str(e))) + space.wrap("int() can't convert non-string " + "with explicit base")) + try: + value = string_to_int(s, base) except ValueError, e: raise OperationError(space.w_ValueError, - space.wrap(str(e))) - except OverflowError, e: - raise OperationError(space.w_OverflowError, - space.wrap(str(e))) + space.wrap(e.args[0])) + if isinstance(value, long): # XXX is this right?? from pypy.objspace.std.longobject import W_LongObject Added: pypy/trunk/src/pypy/objspace/std/test/test_strutil.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/std/test/test_strutil.py Mon Nov 29 18:56:12 2004 @@ -0,0 +1,106 @@ +import autopath +from pypy.tool import testit +from pypy.objspace.std.strutil import * + +class TestStrUtil(testit.TestCase): + + def test_string_to_int(self): + cases = [('0', 0), + ('1', 1), + ('9', 9), + ('10', 10), + ('09', 9), + ('0000101', 101), # not octal unless base 0 or 8 + ('5123', 5123), + ('1891234174197319', 1891234174197319), + (' 0', 0), + ('0 ', 0), + (' \t \n 32313 \f \v \r \n\r ', 32313), + ('+12', 12), + ('-5', -5), + (' -123456789 ', -123456789), + ] + for s, expected in cases: + self.assertEquals(string_to_int(s), expected) + + def test_string_to_int_base(self): + cases = [('111', 2, 7), + ('010', 2, 2), + ('102', 3, 11), + ('103', 4, 19), + ('107', 8, 71), + ('109', 10, 109), + ('10A', 11, 131), + ('10a', 11, 131), + ('10f', 16, 271), + ('10F', 16, 271), + ('0x10f', 16, 271), + ('0x10F', 16, 271), + ('10z', 36, 1331), + ('10Z', 36, 1331), + ('12', 0, 12), + ('015', 0, 13), + ('0x10', 0, 16), + ('0XE', 0, 14), + ('0', 0, 0), + ('0x', 0, 0), # according to CPython so far + ('0X', 0, 0), # " " + ('0x', 16, 0), # " " + ('0X', 16, 0), # " " + ] + for s, base, expected in cases: + self.assertEquals(string_to_int(s, base), expected) + self.assertEquals(string_to_int('+'+s, base), expected) + self.assertEquals(string_to_int('-'+s, base), -expected) + self.assertEquals(string_to_int(s+'\n', base), expected) + self.assertEquals(string_to_int(' +'+s, base), expected) + self.assertEquals(string_to_int('-'+s+' ', base), -expected) + + def test_string_to_int_error(self): + cases = ['0x123', # must use base 0 or 16 + ' 0X12 ', + '', + '++12', + '+-12', + '-+12', + '--12', + '- 5', + '+ 5', + '12a6', + '12A6', + 'f', + 'Z', + '.', + '@', + ] + for s in cases: + self.assertRaises(ValueError, string_to_int, s) + self.assertRaises(ValueError, string_to_int, ' '+s) + self.assertRaises(ValueError, string_to_int, s+' ') + self.assertRaises(ValueError, string_to_int, '+'+s) + self.assertRaises(ValueError, string_to_int, '-'+s) + + def test_string_to_int_base_error(self): + cases = [('1', 1), + ('1', 37), + ('a', 0), + ('9', 9), + ('0x123', 7), + ('145cdf', 15), + ('12', 37), + ('12', 98172), + ('12', -1), + ('12', -908), + ('12.3', 10), + ('12.3', 13), + ('12.3', 16), + ] + for s, base in cases: + self.assertRaises(ValueError, string_to_int, s, base) + self.assertRaises(ValueError, string_to_int, ' '+s, base) + self.assertRaises(ValueError, string_to_int, s+' ', base) + self.assertRaises(ValueError, string_to_int, '+'+s, base) + self.assertRaises(ValueError, string_to_int, '-'+s, base) + +if __name__ == '__main__': + testit.main() From arigo at codespeak.net Tue Nov 30 12:59:56 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 30 Nov 2004 12:59:56 +0100 (MET) Subject: [pypy-svn] r7709 - pypy/trunk/src/pypy/objspace/std Message-ID: <20041130115956.0718A5AEDF@thoth.codespeak.net> Author: arigo Date: Tue Nov 30 12:59:56 2004 New Revision: 7709 Added: pypy/trunk/src/pypy/objspace/std/strutil.py (contents, props changed) Log: Oh no. Forgot to add this file with the previous check-in. Added: pypy/trunk/src/pypy/objspace/std/strutil.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/objspace/std/strutil.py Tue Nov 30 12:59:56 2004 @@ -0,0 +1,61 @@ +""" +Pure Python implementation of string utilities. +""" + +# XXX factor more functions out of stringobject.py. +# This module is independent from PyPy. + +def strip_spaces(s): + # XXX this is not locate-dependent + p = 0 + q = len(s) + while p < q and s[p] in ' \f\n\r\t\v': + p += 1 + while p < q and s[q-1] in ' \f\n\r\t\v': + q -= 1 + return s[p:q] + +def string_to_int(s, base=10): + """Utility to converts a string to an integer (or possibly a long). + If base is 0, the proper base is guessed based on the leading + characters of 's'. Raises ValueError in case of error. + """ + s = literal = strip_spaces(s) + sign = 1 + if s.startswith('-'): + sign = -1 + s = s[1:] + elif s.startswith('+'): + s = s[1:] + if base == 0: + if s.startswith('0x') or s.startswith('0X'): + base = 16 + elif s.startswith('0'): + base = 8 + else: + base = 10 + elif base < 2 or base > 36: + raise ValueError, "int() base must be >= 2 and <= 36" + if not s: + if not literal: + raise ValueError, 'empty literal for int()' + else: + raise ValueError, 'invalid literal for int(): ' + literal + if base == 16 and (s.startswith('0x') or s.startswith('0X')): + s = s[2:] + # XXX uses int-to-long overflow so far + result = 0 + for c in s: + digit = ord(c) + if '0' <= c <= '9': + digit -= ord('0') + elif 'A' <= c <= 'Z': + digit = (digit - ord('A')) + 10 + elif 'a' <= c <= 'z': + digit = (digit - ord('a')) + 10 + else: + raise ValueError, 'invalid literal for int(): ' + literal + if digit >= base: + raise ValueError, 'invalid literal for int(): ' + literal + result = result*base + digit + return result * sign From arigo at codespeak.net Tue Nov 30 13:00:42 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 30 Nov 2004 13:00:42 +0100 (MET) Subject: [pypy-svn] r7710 - in pypy/trunk/src/pypy: annotation/test appspace appspace/test translator Message-ID: <20041130120042.5EB945AEDF@thoth.codespeak.net> Author: arigo Date: Tue Nov 30 13:00:41 2004 New Revision: 7710 Modified: pypy/trunk/src/pypy/annotation/test/test_pairtype.py (props changed) pypy/trunk/src/pypy/appspace/_file.py (props changed) pypy/trunk/src/pypy/appspace/test/test_sio.py (props changed) pypy/trunk/src/pypy/translator/genrpy.py (contents, props changed) Log: fixeol. Modified: pypy/trunk/src/pypy/translator/genrpy.py ============================================================================== --- pypy/trunk/src/pypy/translator/genrpy.py (original) +++ pypy/trunk/src/pypy/translator/genrpy.py Tue Nov 30 13:00:41 2004 @@ -1,652 +1,652 @@ -""" -Implementation of a translator from application Python to interpreter level RPython. - -The idea is that we can automatically transform app-space implementations -of methods into some equivalent representation at interpreter level. -Then, the RPython to C translation might hopefully spit out some -more efficient code than always interpreting these methods. - -Note that the appspace functions are treated as rpythonic, in a sense -that globals are constants, for instance. This definition is not -exact and might change. - -This module is very much under construction and not yet usable for much -more than testing. -""" - -from pypy.objspace.flow.model import traverse -from pypy.objspace.flow import FlowObjSpace -from pypy.objspace.flow.model import FunctionGraph, Block, Link, Variable, Constant -from pypy.objspace.flow.model import last_exception, last_exc_value -from pypy.translator.simplify import simplify_graph -from pypy.interpreter.error import OperationError -from types import FunctionType - -from pypy.translator.translator import Translator - -import sys - -def somefunc(arg): - pass - -def f(a,b): - print "start" - a = [] - a.append(3) - for i in range(3): - print i - if a > b: - try: - if b == 123: - raise ValueError - elif b == 321: - raise IndexError - return 123 - except ValueError: - raise TypeError - else: - dummy = somefunc(23) - return 42 - -def ff(a, b): - try: - raise SystemError, 42 - return a+b - finally: - a = 7 - -glob = 100 -def fff(): - global glob - return 42+glob - -def app_mod__String_ANY(format, values): - import _formatting - if isinstance(values, tuple): - return _formatting.format(format, values, None) - else: - if hasattr(values, 'keys'): - return _formatting.format(format, (values,), values) - else: - return _formatting.format(format, (values,), None) - -def app_str_decode__String_ANY_ANY(str, encoding=None, errors=None): - if encoding is None and errors is None: - return unicode(str) - elif errors is None: - return unicode(str, encoding) - else: - return unicode(str, encoding, errors) - - -def ordered_blocks(graph): - # collect all blocks - allblocks = [] - def visit(block): - if isinstance(block, Block): - # first we order by offset in the code string - if block.operations: - ofs = block.operations[0].offset - else: - ofs = sys.maxint - # then we order by input variable name or value - if block.inputargs: - txt = str(block.inputargs[0]) - else: - txt = "dummy" - allblocks.append((ofs, txt, block)) - traverse(visit, graph) - allblocks.sort() - #for ofs, txt, block in allblocks: - # print ofs, txt, block - return [block for ofs, txt, block in allblocks] - - -class GenRpy: - def __init__(self, f, translator, modname=None): - self.f = f - self.translator = translator - self.modname = (modname or - translator.functions[0].__name__) - self.rpynames = {Constant(None).key: 'w(None)', - Constant(False).key: 'w(False)', - Constant(True).key: 'w(True)', - } - - self.seennames = {} - self.initcode = [] # list of lines for the module's initxxx() - self.latercode = [] # list of generators generating extra lines - # for later in initxxx() -- for recursive - # objects - self.globaldecl = [] - self.globalobjects = [] - self.pendingfunctions = [] - - # special constructors: - self.has_listarg = {} - for name in "newtuple newlist newdict newstring".split(): - self.has_listarg[name] = name - - self.gen_source() - - def nameof(self, obj): - key = Constant(obj).key - try: - return self.rpynames[key] - except KeyError: - #name = "w(%s)" % str(obj) - #self.rpynames[key] = name - #return name - if (type(obj).__module__ != '__builtin__' and - not isinstance(obj, type)): # skip user-defined metaclasses - # assume it's a user defined thingy - name = self.nameof_instance(obj) - else: - for cls in type(obj).__mro__: - meth = getattr(self, - 'nameof_' + cls.__name__.replace(' ', ''), - None) - if meth: - break - else: - raise Exception, "nameof(%r) in %r" % (obj, self.current_func) - name = meth(obj) - self.rpynames[key] = name - return name - - def uniquename(self, basename): - n = self.seennames.get(basename, 0) - self.seennames[basename] = n+1 - if n == 0: - self.globalobjects.append(basename) - self.globaldecl.append('static PyObject *%s;' % (basename,)) - return basename - else: - return self.uniquename('%s_%d' % (basename, n)) - - def nameof_object(self, value): - if type(value) is not object: - raise Exception, "nameof(%r) in %r" % (value, self.current_func) - name = self.uniquename('g_object') - self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) - return name - - def nameof_module(self, value): - assert value is os or not hasattr(value, "__file__") or \ - not (value.__file__.endswith('.pyc') or - value.__file__.endswith('.py') or - value.__file__.endswith('.pyo')), \ - "%r is not a builtin module (probably :)"%value - name = self.uniquename('mod%s'%value.__name__) - self.initcode.append('INITCHK(%s = PyImport_ImportModule("%s"))'%(name, value.__name__)) - return name - - - def nameof_int(self, value): - return "w(%d)" % value - - def nameof_long(self, value): - # assume we want them in hex most of the time - if value < 256L: - return "%dL" % value - else: - return "0x%08xL" % value - - def nameof_float(self, value): - return "w(%s)" % value - - def nameof_str(self, value): - return "w(%s)" % repr(value) - - def skipped_function(self, func): - # debugging only! Generates a placeholder for missing functions - # that raises an exception when called. - name = self.uniquename('gskippedfunc_' + func.__name__) - self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) - self.initcode.append('INITCHK(%s = PyCFunction_New(' - '&ml_%s, NULL))' % (name, name)) - self.initcode.append('\tPy_INCREF(%s);' % name) - self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) - return name - - def nameof_function(self, func): - printable_name = '(%s:%d) %s' % ( - func.func_globals.get('__name__', '?'), - func.func_code.co_firstlineno, - func.__name__) - if self.translator.frozen: - if func not in self.translator.flowgraphs: - print "NOT GENERATING", printable_name - return self.skipped_function(func) - else: - if (func.func_doc and - func.func_doc.lstrip().startswith('NOT_RPYTHON')): - print "skipped", printable_name - return self.skipped_function(func) - name = self.uniquename('gfunc_' + func.__name__) - self.initcode.append('INITCHK(%s = PyCFunction_New(' - '&ml_%s, NULL))' % (name, name)) - self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) - self.pendingfunctions.append(func) - return name - - def nameof_staticmethod(self, sm): - # XXX XXX XXXX - func = sm.__get__(42.5) - name = self.uniquename('gsm_' + func.__name__) - functionname = self.nameof(func) - self.initcode.append('INITCHK(%s = PyCFunction_New(' - '&ml_%s, NULL))' % (name, functionname)) - return name - - def nameof_instancemethod(self, meth): - if meth.im_self is None: - # no error checking here - return self.nameof(meth.im_func) - else: - ob = self.nameof(meth.im_self) - func = self.nameof(meth.im_func) - typ = self.nameof(meth.im_class) - name = self.uniquename('gmeth_'+meth.im_func.__name__) - self.initcode.append( - 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( - name, func, ob, typ)) - return name - - def should_translate_attr(self, pbc, attr): - ann = self.translator.annotator - if ann is None: - ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', []) - if attr in ignore: - return False - else: - return "probably" # True - if attr in ann.getpbcattrs(pbc): - return True - classdef = ann.getuserclasses().get(pbc.__class__) - if (classdef and - classdef.about_attribute(attr) != annmodel.SomeImpossibleValue()): - return True - return False - - def later(self, gen): - self.latercode.append(gen) - - def nameof_instance(self, instance): - name = self.uniquename('ginst_' + instance.__class__.__name__) - cls = self.nameof(instance.__class__) - def initinstance(): - content = instance.__dict__.items() - content.sort() - for key, value in content: - if self.should_translate_attr(instance, key): - yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( - name, key, self.nameof(value)) - self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( - name, cls)) - self.later(initinstance()) - return name - - def nameof_builtin_function_or_method(self, func): - if func.__self__ is None: - # builtin function - # where does it come from? Python2.2 doesn't have func.__module__ - for modname, module in sys.modules.items(): - if hasattr(module, '__file__'): - if (module.__file__.endswith('.py') or - module.__file__.endswith('.pyc') or - module.__file__.endswith('.pyo')): - continue # skip non-builtin modules - if func is getattr(module, func.__name__, None): - break - else: - raise Exception, '%r not found in any built-in module' % (func,) - name = self.uniquename('gbltin_' + func.__name__) - if modname == '__builtin__': - self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' - 'PyEval_GetBuiltins(), "%s"))' % ( - name, func.__name__)) - else: - self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' - '%s, "%s"))' % ( - name, self.nameof(module), func.__name__)) - else: - # builtin (bound) method - name = self.uniquename('gbltinmethod_' + func.__name__) - self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' - '%s, "%s"))' % ( - name, self.nameof(func.__self__), func.__name__)) - return name - - def nameof_classobj(self, cls): - if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): - raise Exception, "%r should never be reached" % (cls,) - - metaclass = "&PyType_Type" - if issubclass(cls, Exception): - if cls.__module__ == 'exceptions': - return 'w(%s)'%cls.__name__ - #else: - # # exceptions must be old-style classes (grr!) - # metaclass = "&PyClass_Type" - # For the moment, use old-style classes exactly when the - # pypy source uses old-style classes, to avoid strange problems. - if not isinstance(cls, type): - assert type(cls) is type(Exception) - metaclass = "&PyClass_Type" - - name = self.uniquename('gcls_' + cls.__name__) - basenames = [self.nameof(base) for base in cls.__bases__] - def initclassobj(): - content = cls.__dict__.items() - content.sort() - for key, value in content: - if key.startswith('__'): - if key in ['__module__', '__doc__', '__dict__', - '__weakref__', '__repr__', '__metaclass__']: - continue - # XXX some __NAMES__ are important... nicer solution sought - #raise Exception, "unexpected name %r in class %s"%(key, cls) - if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen: - print value - continue - if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: - print value - continue - - yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( - name, key, self.nameof(value)) - - baseargs = ", ".join(basenames) - if baseargs: - baseargs = ', '+baseargs - self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) %s,' - %(name, metaclass)) - self.initcode.append('\t\t"s(%s){}", "%s"%s))' - %("O"*len(basenames), cls.__name__, baseargs)) - - self.later(initclassobj()) - return name - - nameof_class = nameof_classobj # for Python 2.2 - - - def nameof_type(self, cls): - return "w(%s)" % cls.__name__ ##?? - if cls in self.typename_mapping: - return '(PyObject*) %s' % self.typename_mapping[cls] - assert cls.__module__ != '__builtin__', \ - "built-in class %r not found in typename_mapping" % (cls,) - return self.nameof_classobj(cls) - - def nameof_tuple(self, tup): - name = self.uniquename('g%dtuple' % len(tup)) - args = [self.nameof(x) for x in tup] - args.insert(0, '%d' % len(tup)) - args = ', '.join(args) - self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) - return name - - def nameof_list(self, lis): - name = self.uniquename('g%dlist' % len(lis)) - def initlist(): - for i in range(len(lis)): - item = self.nameof(lis[i]) - yield '\tPy_INCREF(%s);' % item - yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) - self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) - self.later(initlist()) - return name - - def nameof_dict(self, dic): - return 'space.newdict([w("sorry", "not yet"])' - assert dic is not __builtins__ - assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( - dic.get('__name__', '?'),) - name = self.uniquename('g%ddict' % len(dic)) - def initdict(): - for k in dic: - if type(k) is str: - yield ('\tINITCHK(PyDict_SetItemString' - '(%s, "%s", %s) >= 0)'%( - name, k, self.nameof(dic[k]))) - else: - yield ('\tINITCHK(PyDict_SetItem' - '(%s, %s, %s) >= 0)'%( - name, self.nameof(k), self.nameof(dic[k]))) - self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) - self.later(initdict()) - return name - - # strange prebuilt instances below, don't look too closely - # XXX oh well. - def nameof_member_descriptor(self, md): - name = self.uniquename('gdescriptor_%s_%s' % ( - md.__objclass__.__name__, md.__name__)) - cls = self.nameof(md.__objclass__) - self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % - cls) - self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' - '((PyTypeObject*) %s)->tp_dict, "%s"))' % - (name, cls, md.__name__)) - return name - nameof_getset_descriptor = nameof_member_descriptor - nameof_method_descriptor = nameof_member_descriptor - nameof_wrapper_descriptor = nameof_member_descriptor - - def nameof_file(self, fil): - if fil is sys.stdin: - return 'PySys_GetObject("stdin")' - if fil is sys.stdout: - return 'PySys_GetObject("stdout")' - if fil is sys.stderr: - return 'PySys_GetObject("stderr")' - raise Exception, 'Cannot translate an already-open file: %r' % (fil,) - - def gen_source(self): - f = self.f - info = { - 'modname': self.modname, - 'entrypointname': self.translator.functions[0].__name__, - 'entrypoint': self.nameof(self.translator.functions[0]), - } - - # function implementations - while self.pendingfunctions: - func = self.current_func = self.pendingfunctions.pop() - print "#######", func.__name__ - self.gen_rpyfunction(func) - # collect more of the latercode after each function - while self.latercode: - #gen, self.debugstack = self.latercode.pop() - gen = self.latercode.pop() - #self.initcode.extend(gen) -- eats TypeError! bad CPython! - for line in gen: - self.initcode.append(line) - self.debugstack = () - #self.gen_global_declarations() - - # footer - # maybe not needed - return - print >> f, self.C_INIT_HEADER % info - if self.f2name is not None: - print >> f, '#include "%s"' % self.f2name - for codeline in self.initcode: - print >> f, '\t' + codeline - print >> f, self.C_INIT_FOOTER % info - - def gen_rpyfunction(self, func): - - local_names = {} - - def expr(v, wrapped = True): - if isinstance(v, Variable): - n = v.name - if n.startswith("v") and n[1:].isdigit(): - ret = local_names.get(v.name) - if not ret: - if wrapped: - local_names[v.name] = ret = "w_%d" % len(local_names) - else: - local_names[v.name] = ret = "v%d" % len(local_names) - return ret - return v.name - elif isinstance(v, Constant): - return self.nameof(v.value) - else: - #raise TypeError, "expr(%r)" % (v,) - # XXX how do I resolve these? - return "space.%s" % str(v) - - def arglist(args): - res = [expr(arg) for arg in args] - return ", ".join(res) - - def oper(op): - # specialcase is_true - if op.opname in self.has_listarg: - fmt = "%s = %s([%s])" - else: - fmt = "%s = %s(%s)" - if op.opname == "is_true": - return fmt % (expr(op.result, False), expr(op.opname), arglist(op.args)) - return fmt % (expr(op.result), expr(op.opname), arglist(op.args)) - - def gen_link(link, linklocalvars=None): - "Generate the code to jump across the given Link." - linklocalvars = linklocalvars or {} - left, right = [], [] - for a1, a2 in zip(link.args, link.target.inputargs): - if a1 in linklocalvars: - src = linklocalvars[a1] - else: - src = expr(a1) - left.append(expr(a2)) - right.append(src) - yield "%s = %s" % (", ".join(left), ", ".join(right)) - goto = blocknum[link.target] - yield 'goto = %d' % goto - if goto <= blocknum[block]: - yield 'continue' - - f = self.f - t = self.translator - #t.simplify(func) - graph = t.getflowgraph(func) - - start = graph.startblock - blocks = ordered_blocks(graph) - nblocks = len(blocks) - - blocknum = {} - for block in blocks: - blocknum[block] = len(blocknum)+1 - - # create function declaration - name = func.__name__ # change this - args = [expr(var) for var in start.inputargs] - argstr = ", ".join(args) - print >> f, "def %s(space, %s):" % (name, argstr) - print >> f, " w = space.wrap" - print >> f, " goto = %d # startblock" % blocknum[start] - print >> f, " while True:" - - def render_block(block): - catch_exception = block.exitswitch == Constant(last_exception) - regular_op = len(block.operations) - catch_exception - # render all but maybe the last op - for op in block.operations[:regular_op]: - yield "%s" % oper(op) - # render the last op if it is exception handled - for op in block.operations[regular_op:]: - yield "try:" - yield " %s" % oper(op) - - if len(block.exits) == 0: - if len(block.inputargs) == 2: # exc_cls, exc_value - # exceptional return block - exc_cls = expr(block.inputargs[0]) - exc_val = expr(block.inputargs[1]) - yield "raise OperationError(%s, %s)" % (exc_cls, exc_val) - else: - # regular return block - retval = expr(block.inputargs[0]) - yield "return %s" % retval - return - elif block.exitswitch is None: - # single-exit block - assert len(block.exits) == 1 - for op in gen_link(block.exits[0]): - yield "%s" % op - elif catch_exception: - # block catching the exceptions raised by its last operation - # we handle the non-exceptional case first - link = block.exits[0] - assert link.exitcase is None - for op in gen_link(link): - yield " %s" % op - # we must catch the exception raised by the last operation, - # which goes to the last err%d_%d label written above. - for link in block.exits[1:]: - assert issubclass(link.exitcase, Exception) - yield "except OperationError, e:" - print "*"*10, link.exitcase - for op in gen_link(link, { - Constant(last_exception): 'e.w_type', - Constant(last_exc_value): 'e.w_value'}): - yield " %s" % op - else: - # block ending in a switch on a value - exits = list(block.exits) - if len(exits) == 2 and ( - exits[0].exitcase is False and exits[1].exitcase is True): - # order these guys like Python does - exits.reverse() - q = "if" - for link in exits[:-1]: - yield "%s %s == %s:" % (q, expr(block.exitswitch), - link.exitcase) - for op in gen_link(link): - yield " %s" % op - q = "elif" - link = exits[-1] - yield "else:" - yield " assert %s == %s" % (expr(block.exitswitch), - link.exitcase) - for op in gen_link(exits[-1]): - yield " %s" % op - - for block in blocks: - blockno = blocknum[block] - print >> f - print " if goto == %d:" % blockno - for line in render_block(block): - print " %s" % line - -def test_md5(): - #import md5 - # how do I avoid the builtin module? - from pypy.appspace import md5 - digest = md5.new("hello") - -entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY, app_mod__String_ANY, test_md5) [-1] - -import os, sys -from pypy.interpreter import autopath -srcdir = os.path.dirname(autopath.pypydir) -appdir = os.path.join(autopath.pypydir, 'appspace') - -try: - hold = sys.path[:] - sys.path.insert(0, appdir) - t = Translator(entry_point, verbose=False, simplifying=True) - gen = GenRpy(sys.stdout, t) -finally: - sys.path[:] = hold -#t.simplify() -#t.view() -# debugging -graph = t.getflowgraph() -ab = ordered_blocks(graph) # use ctrl-b in PyWin with ab - +""" +Implementation of a translator from application Python to interpreter level RPython. + +The idea is that we can automatically transform app-space implementations +of methods into some equivalent representation at interpreter level. +Then, the RPython to C translation might hopefully spit out some +more efficient code than always interpreting these methods. + +Note that the appspace functions are treated as rpythonic, in a sense +that globals are constants, for instance. This definition is not +exact and might change. + +This module is very much under construction and not yet usable for much +more than testing. +""" + +from pypy.objspace.flow.model import traverse +from pypy.objspace.flow import FlowObjSpace +from pypy.objspace.flow.model import FunctionGraph, Block, Link, Variable, Constant +from pypy.objspace.flow.model import last_exception, last_exc_value +from pypy.translator.simplify import simplify_graph +from pypy.interpreter.error import OperationError +from types import FunctionType + +from pypy.translator.translator import Translator + +import sys + +def somefunc(arg): + pass + +def f(a,b): + print "start" + a = [] + a.append(3) + for i in range(3): + print i + if a > b: + try: + if b == 123: + raise ValueError + elif b == 321: + raise IndexError + return 123 + except ValueError: + raise TypeError + else: + dummy = somefunc(23) + return 42 + +def ff(a, b): + try: + raise SystemError, 42 + return a+b + finally: + a = 7 + +glob = 100 +def fff(): + global glob + return 42+glob + +def app_mod__String_ANY(format, values): + import _formatting + if isinstance(values, tuple): + return _formatting.format(format, values, None) + else: + if hasattr(values, 'keys'): + return _formatting.format(format, (values,), values) + else: + return _formatting.format(format, (values,), None) + +def app_str_decode__String_ANY_ANY(str, encoding=None, errors=None): + if encoding is None and errors is None: + return unicode(str) + elif errors is None: + return unicode(str, encoding) + else: + return unicode(str, encoding, errors) + + +def ordered_blocks(graph): + # collect all blocks + allblocks = [] + def visit(block): + if isinstance(block, Block): + # first we order by offset in the code string + if block.operations: + ofs = block.operations[0].offset + else: + ofs = sys.maxint + # then we order by input variable name or value + if block.inputargs: + txt = str(block.inputargs[0]) + else: + txt = "dummy" + allblocks.append((ofs, txt, block)) + traverse(visit, graph) + allblocks.sort() + #for ofs, txt, block in allblocks: + # print ofs, txt, block + return [block for ofs, txt, block in allblocks] + + +class GenRpy: + def __init__(self, f, translator, modname=None): + self.f = f + self.translator = translator + self.modname = (modname or + translator.functions[0].__name__) + self.rpynames = {Constant(None).key: 'w(None)', + Constant(False).key: 'w(False)', + Constant(True).key: 'w(True)', + } + + self.seennames = {} + self.initcode = [] # list of lines for the module's initxxx() + self.latercode = [] # list of generators generating extra lines + # for later in initxxx() -- for recursive + # objects + self.globaldecl = [] + self.globalobjects = [] + self.pendingfunctions = [] + + # special constructors: + self.has_listarg = {} + for name in "newtuple newlist newdict newstring".split(): + self.has_listarg[name] = name + + self.gen_source() + + def nameof(self, obj): + key = Constant(obj).key + try: + return self.rpynames[key] + except KeyError: + #name = "w(%s)" % str(obj) + #self.rpynames[key] = name + #return name + if (type(obj).__module__ != '__builtin__' and + not isinstance(obj, type)): # skip user-defined metaclasses + # assume it's a user defined thingy + name = self.nameof_instance(obj) + else: + for cls in type(obj).__mro__: + meth = getattr(self, + 'nameof_' + cls.__name__.replace(' ', ''), + None) + if meth: + break + else: + raise Exception, "nameof(%r) in %r" % (obj, self.current_func) + name = meth(obj) + self.rpynames[key] = name + return name + + def uniquename(self, basename): + n = self.seennames.get(basename, 0) + self.seennames[basename] = n+1 + if n == 0: + self.globalobjects.append(basename) + self.globaldecl.append('static PyObject *%s;' % (basename,)) + return basename + else: + return self.uniquename('%s_%d' % (basename, n)) + + def nameof_object(self, value): + if type(value) is not object: + raise Exception, "nameof(%r) in %r" % (value, self.current_func) + name = self.uniquename('g_object') + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*)&PyBaseObject_Type, ""))'%name) + return name + + def nameof_module(self, value): + assert value is os or not hasattr(value, "__file__") or \ + not (value.__file__.endswith('.pyc') or + value.__file__.endswith('.py') or + value.__file__.endswith('.pyo')), \ + "%r is not a builtin module (probably :)"%value + name = self.uniquename('mod%s'%value.__name__) + self.initcode.append('INITCHK(%s = PyImport_ImportModule("%s"))'%(name, value.__name__)) + return name + + + def nameof_int(self, value): + return "w(%d)" % value + + def nameof_long(self, value): + # assume we want them in hex most of the time + if value < 256L: + return "%dL" % value + else: + return "0x%08xL" % value + + def nameof_float(self, value): + return "w(%s)" % value + + def nameof_str(self, value): + return "w(%s)" % repr(value) + + def skipped_function(self, func): + # debugging only! Generates a placeholder for missing functions + # that raises an exception when called. + name = self.uniquename('gskippedfunc_' + func.__name__) + self.globaldecl.append('static PyMethodDef ml_%s = { "%s", &skipped, METH_VARARGS };' % (name, name)) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\tPy_INCREF(%s);' % name) + self.initcode.append('\tPyCFunction_GET_SELF(%s) = %s;' % (name, name)) + return name + + def nameof_function(self, func): + printable_name = '(%s:%d) %s' % ( + func.func_globals.get('__name__', '?'), + func.func_code.co_firstlineno, + func.__name__) + if self.translator.frozen: + if func not in self.translator.flowgraphs: + print "NOT GENERATING", printable_name + return self.skipped_function(func) + else: + if (func.func_doc and + func.func_doc.lstrip().startswith('NOT_RPYTHON')): + print "skipped", printable_name + return self.skipped_function(func) + name = self.uniquename('gfunc_' + func.__name__) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, name)) + self.initcode.append('\t%s->ob_type = &PyGenCFunction_Type;' % name) + self.pendingfunctions.append(func) + return name + + def nameof_staticmethod(self, sm): + # XXX XXX XXXX + func = sm.__get__(42.5) + name = self.uniquename('gsm_' + func.__name__) + functionname = self.nameof(func) + self.initcode.append('INITCHK(%s = PyCFunction_New(' + '&ml_%s, NULL))' % (name, functionname)) + return name + + def nameof_instancemethod(self, meth): + if meth.im_self is None: + # no error checking here + return self.nameof(meth.im_func) + else: + ob = self.nameof(meth.im_self) + func = self.nameof(meth.im_func) + typ = self.nameof(meth.im_class) + name = self.uniquename('gmeth_'+meth.im_func.__name__) + self.initcode.append( + 'INITCHK(%s = gencfunc_descr_get(%s, %s, %s))'%( + name, func, ob, typ)) + return name + + def should_translate_attr(self, pbc, attr): + ann = self.translator.annotator + if ann is None: + ignore = getattr(pbc.__class__, 'NOT_RPYTHON_ATTRIBUTES', []) + if attr in ignore: + return False + else: + return "probably" # True + if attr in ann.getpbcattrs(pbc): + return True + classdef = ann.getuserclasses().get(pbc.__class__) + if (classdef and + classdef.about_attribute(attr) != annmodel.SomeImpossibleValue()): + return True + return False + + def later(self, gen): + self.latercode.append(gen) + + def nameof_instance(self, instance): + name = self.uniquename('ginst_' + instance.__class__.__name__) + cls = self.nameof(instance.__class__) + def initinstance(): + content = instance.__dict__.items() + content.sort() + for key, value in content: + if self.should_translate_attr(instance, key): + yield 'INITCHK(SETUP_INSTANCE_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) + self.initcode.append('INITCHK(SETUP_INSTANCE(%s, %s))' % ( + name, cls)) + self.later(initinstance()) + return name + + def nameof_builtin_function_or_method(self, func): + if func.__self__ is None: + # builtin function + # where does it come from? Python2.2 doesn't have func.__module__ + for modname, module in sys.modules.items(): + if hasattr(module, '__file__'): + if (module.__file__.endswith('.py') or + module.__file__.endswith('.pyc') or + module.__file__.endswith('.pyo')): + continue # skip non-builtin modules + if func is getattr(module, func.__name__, None): + break + else: + raise Exception, '%r not found in any built-in module' % (func,) + name = self.uniquename('gbltin_' + func.__name__) + if modname == '__builtin__': + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + 'PyEval_GetBuiltins(), "%s"))' % ( + name, func.__name__)) + else: + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(module), func.__name__)) + else: + # builtin (bound) method + name = self.uniquename('gbltinmethod_' + func.__name__) + self.initcode.append('INITCHK(%s = PyObject_GetAttrString(' + '%s, "%s"))' % ( + name, self.nameof(func.__self__), func.__name__)) + return name + + def nameof_classobj(self, cls): + if cls.__doc__ and cls.__doc__.lstrip().startswith('NOT_RPYTHON'): + raise Exception, "%r should never be reached" % (cls,) + + metaclass = "&PyType_Type" + if issubclass(cls, Exception): + if cls.__module__ == 'exceptions': + return 'w(%s)'%cls.__name__ + #else: + # # exceptions must be old-style classes (grr!) + # metaclass = "&PyClass_Type" + # For the moment, use old-style classes exactly when the + # pypy source uses old-style classes, to avoid strange problems. + if not isinstance(cls, type): + assert type(cls) is type(Exception) + metaclass = "&PyClass_Type" + + name = self.uniquename('gcls_' + cls.__name__) + basenames = [self.nameof(base) for base in cls.__bases__] + def initclassobj(): + content = cls.__dict__.items() + content.sort() + for key, value in content: + if key.startswith('__'): + if key in ['__module__', '__doc__', '__dict__', + '__weakref__', '__repr__', '__metaclass__']: + continue + # XXX some __NAMES__ are important... nicer solution sought + #raise Exception, "unexpected name %r in class %s"%(key, cls) + if isinstance(value, staticmethod) and value.__get__(1) not in self.translator.flowgraphs and self.translator.frozen: + print value + continue + if isinstance(value, FunctionType) and value not in self.translator.flowgraphs and self.translator.frozen: + print value + continue + + yield 'INITCHK(SETUP_CLASS_ATTR(%s, "%s", %s))' % ( + name, key, self.nameof(value)) + + baseargs = ", ".join(basenames) + if baseargs: + baseargs = ', '+baseargs + self.initcode.append('INITCHK(%s = PyObject_CallFunction((PyObject*) %s,' + %(name, metaclass)) + self.initcode.append('\t\t"s(%s){}", "%s"%s))' + %("O"*len(basenames), cls.__name__, baseargs)) + + self.later(initclassobj()) + return name + + nameof_class = nameof_classobj # for Python 2.2 + + + def nameof_type(self, cls): + return "w(%s)" % cls.__name__ ##?? + if cls in self.typename_mapping: + return '(PyObject*) %s' % self.typename_mapping[cls] + assert cls.__module__ != '__builtin__', \ + "built-in class %r not found in typename_mapping" % (cls,) + return self.nameof_classobj(cls) + + def nameof_tuple(self, tup): + name = self.uniquename('g%dtuple' % len(tup)) + args = [self.nameof(x) for x in tup] + args.insert(0, '%d' % len(tup)) + args = ', '.join(args) + self.initcode.append('INITCHK(%s = PyTuple_Pack(%s))' % (name, args)) + return name + + def nameof_list(self, lis): + name = self.uniquename('g%dlist' % len(lis)) + def initlist(): + for i in range(len(lis)): + item = self.nameof(lis[i]) + yield '\tPy_INCREF(%s);' % item + yield '\tPyList_SET_ITEM(%s, %d, %s);' % (name, i, item) + self.initcode.append('INITCHK(%s = PyList_New(%d))' % (name, len(lis))) + self.later(initlist()) + return name + + def nameof_dict(self, dic): + return 'space.newdict([w("sorry", "not yet"])' + assert dic is not __builtins__ + assert '__builtins__' not in dic, 'Seems to be the globals of %s' % ( + dic.get('__name__', '?'),) + name = self.uniquename('g%ddict' % len(dic)) + def initdict(): + for k in dic: + if type(k) is str: + yield ('\tINITCHK(PyDict_SetItemString' + '(%s, "%s", %s) >= 0)'%( + name, k, self.nameof(dic[k]))) + else: + yield ('\tINITCHK(PyDict_SetItem' + '(%s, %s, %s) >= 0)'%( + name, self.nameof(k), self.nameof(dic[k]))) + self.initcode.append('INITCHK(%s = PyDict_New())' % (name,)) + self.later(initdict()) + return name + + # strange prebuilt instances below, don't look too closely + # XXX oh well. + def nameof_member_descriptor(self, md): + name = self.uniquename('gdescriptor_%s_%s' % ( + md.__objclass__.__name__, md.__name__)) + cls = self.nameof(md.__objclass__) + self.initcode.append('INITCHK(PyType_Ready((PyTypeObject*) %s) >= 0)' % + cls) + self.initcode.append('INITCHK(%s = PyMapping_GetItemString(' + '((PyTypeObject*) %s)->tp_dict, "%s"))' % + (name, cls, md.__name__)) + return name + nameof_getset_descriptor = nameof_member_descriptor + nameof_method_descriptor = nameof_member_descriptor + nameof_wrapper_descriptor = nameof_member_descriptor + + def nameof_file(self, fil): + if fil is sys.stdin: + return 'PySys_GetObject("stdin")' + if fil is sys.stdout: + return 'PySys_GetObject("stdout")' + if fil is sys.stderr: + return 'PySys_GetObject("stderr")' + raise Exception, 'Cannot translate an already-open file: %r' % (fil,) + + def gen_source(self): + f = self.f + info = { + 'modname': self.modname, + 'entrypointname': self.translator.functions[0].__name__, + 'entrypoint': self.nameof(self.translator.functions[0]), + } + + # function implementations + while self.pendingfunctions: + func = self.current_func = self.pendingfunctions.pop() + print "#######", func.__name__ + self.gen_rpyfunction(func) + # collect more of the latercode after each function + while self.latercode: + #gen, self.debugstack = self.latercode.pop() + gen = self.latercode.pop() + #self.initcode.extend(gen) -- eats TypeError! bad CPython! + for line in gen: + self.initcode.append(line) + self.debugstack = () + #self.gen_global_declarations() + + # footer + # maybe not needed + return + print >> f, self.C_INIT_HEADER % info + if self.f2name is not None: + print >> f, '#include "%s"' % self.f2name + for codeline in self.initcode: + print >> f, '\t' + codeline + print >> f, self.C_INIT_FOOTER % info + + def gen_rpyfunction(self, func): + + local_names = {} + + def expr(v, wrapped = True): + if isinstance(v, Variable): + n = v.name + if n.startswith("v") and n[1:].isdigit(): + ret = local_names.get(v.name) + if not ret: + if wrapped: + local_names[v.name] = ret = "w_%d" % len(local_names) + else: + local_names[v.name] = ret = "v%d" % len(local_names) + return ret + return v.name + elif isinstance(v, Constant): + return self.nameof(v.value) + else: + #raise TypeError, "expr(%r)" % (v,) + # XXX how do I resolve these? + return "space.%s" % str(v) + + def arglist(args): + res = [expr(arg) for arg in args] + return ", ".join(res) + + def oper(op): + # specialcase is_true + if op.opname in self.has_listarg: + fmt = "%s = %s([%s])" + else: + fmt = "%s = %s(%s)" + if op.opname == "is_true": + return fmt % (expr(op.result, False), expr(op.opname), arglist(op.args)) + return fmt % (expr(op.result), expr(op.opname), arglist(op.args)) + + def gen_link(link, linklocalvars=None): + "Generate the code to jump across the given Link." + linklocalvars = linklocalvars or {} + left, right = [], [] + for a1, a2 in zip(link.args, link.target.inputargs): + if a1 in linklocalvars: + src = linklocalvars[a1] + else: + src = expr(a1) + left.append(expr(a2)) + right.append(src) + yield "%s = %s" % (", ".join(left), ", ".join(right)) + goto = blocknum[link.target] + yield 'goto = %d' % goto + if goto <= blocknum[block]: + yield 'continue' + + f = self.f + t = self.translator + #t.simplify(func) + graph = t.getflowgraph(func) + + start = graph.startblock + blocks = ordered_blocks(graph) + nblocks = len(blocks) + + blocknum = {} + for block in blocks: + blocknum[block] = len(blocknum)+1 + + # create function declaration + name = func.__name__ # change this + args = [expr(var) for var in start.inputargs] + argstr = ", ".join(args) + print >> f, "def %s(space, %s):" % (name, argstr) + print >> f, " w = space.wrap" + print >> f, " goto = %d # startblock" % blocknum[start] + print >> f, " while True:" + + def render_block(block): + catch_exception = block.exitswitch == Constant(last_exception) + regular_op = len(block.operations) - catch_exception + # render all but maybe the last op + for op in block.operations[:regular_op]: + yield "%s" % oper(op) + # render the last op if it is exception handled + for op in block.operations[regular_op:]: + yield "try:" + yield " %s" % oper(op) + + if len(block.exits) == 0: + if len(block.inputargs) == 2: # exc_cls, exc_value + # exceptional return block + exc_cls = expr(block.inputargs[0]) + exc_val = expr(block.inputargs[1]) + yield "raise OperationError(%s, %s)" % (exc_cls, exc_val) + else: + # regular return block + retval = expr(block.inputargs[0]) + yield "return %s" % retval + return + elif block.exitswitch is None: + # single-exit block + assert len(block.exits) == 1 + for op in gen_link(block.exits[0]): + yield "%s" % op + elif catch_exception: + # block catching the exceptions raised by its last operation + # we handle the non-exceptional case first + link = block.exits[0] + assert link.exitcase is None + for op in gen_link(link): + yield " %s" % op + # we must catch the exception raised by the last operation, + # which goes to the last err%d_%d label written above. + for link in block.exits[1:]: + assert issubclass(link.exitcase, Exception) + yield "except OperationError, e:" + print "*"*10, link.exitcase + for op in gen_link(link, { + Constant(last_exception): 'e.w_type', + Constant(last_exc_value): 'e.w_value'}): + yield " %s" % op + else: + # block ending in a switch on a value + exits = list(block.exits) + if len(exits) == 2 and ( + exits[0].exitcase is False and exits[1].exitcase is True): + # order these guys like Python does + exits.reverse() + q = "if" + for link in exits[:-1]: + yield "%s %s == %s:" % (q, expr(block.exitswitch), + link.exitcase) + for op in gen_link(link): + yield " %s" % op + q = "elif" + link = exits[-1] + yield "else:" + yield " assert %s == %s" % (expr(block.exitswitch), + link.exitcase) + for op in gen_link(exits[-1]): + yield " %s" % op + + for block in blocks: + blockno = blocknum[block] + print >> f + print " if goto == %d:" % blockno + for line in render_block(block): + print " %s" % line + +def test_md5(): + #import md5 + # how do I avoid the builtin module? + from pypy.appspace import md5 + digest = md5.new("hello") + +entry_point = (f, ff, fff, app_str_decode__String_ANY_ANY, app_mod__String_ANY, test_md5) [-1] + +import os, sys +from pypy.interpreter import autopath +srcdir = os.path.dirname(autopath.pypydir) +appdir = os.path.join(autopath.pypydir, 'appspace') + +try: + hold = sys.path[:] + sys.path.insert(0, appdir) + t = Translator(entry_point, verbose=False, simplifying=True) + gen = GenRpy(sys.stdout, t) +finally: + sys.path[:] = hold +#t.simplify() +#t.view() +# debugging +graph = t.getflowgraph() +ab = ordered_blocks(graph) # use ctrl-b in PyWin with ab + From arigo at codespeak.net Tue Nov 30 14:53:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 30 Nov 2004 14:53:44 +0100 (MET) Subject: [pypy-svn] r7711 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20041130135344.3FC5F5AEDF@thoth.codespeak.net> Author: arigo Date: Tue Nov 30 14:53:43 2004 New Revision: 7711 Modified: pypy/trunk/src/pypy/objspace/std/inttype.py pypy/trunk/src/pypy/objspace/std/longtype.py pypy/trunk/src/pypy/objspace/std/strutil.py pypy/trunk/src/pypy/objspace/std/test/test_strutil.py Log: long() parsing code, reusing the int() parsing code. Modified: pypy/trunk/src/pypy/objspace/std/inttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/inttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/inttype.py Tue Nov 30 14:53:43 2004 @@ -23,7 +23,7 @@ if space.is_true(space.is_(w_inttype, space.w_int)): return w_obj value = space.unwrap(w_obj) - if not isinstance(value, int): # XXX typechecking in unwrap! + if not isinstance(value, (int, long)): # XXX typechecking in unwrap! raise OperationError(space.w_ValueError, space.wrap("value can't be converted to int")) else: Modified: pypy/trunk/src/pypy/objspace/std/longtype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/longtype.py (original) +++ pypy/trunk/src/pypy/objspace/std/longtype.py Tue Nov 30 14:53:43 2004 @@ -1,42 +1,50 @@ from pypy.objspace.std.stdtypedef import * +from pypy.objspace.std.strutil import string_to_long from pypy.interpreter.error import OperationError from pypy.objspace.std.inttype import int_typedef def descr__new__(space, w_longtype, w_value=None, w_base=None): from pypy.objspace.std.longobject import W_LongObject if w_base is None: - w_base = space.w_None - if w_value is None: - value = 0L - elif w_base == space.w_None and not space.is_true(space.isinstance(w_value, space.w_str)): - w_obj = space.long(w_value) - if space.is_true(space.is_(w_longtype, space.w_long)): - return w_obj # 'long(x)' should return - # whatever x.__long__() returned - value = space.unwrap(w_obj) - if isinstance(value, int): # XXX typechecking in unwrap! - value = long(value) - if not isinstance(value, long): # XXX typechecking in unwrap! - raise OperationError(space.w_ValueError, - space.wrap("value can't be converted to long")) - - else: - if w_base == space.w_None: - base = -909 # don't blame us!! + # check for easy cases + if w_value is None: + value = 0L + elif isinstance(w_value, W_LongObject): + value = w_value.longval + elif space.is_true(space.isinstance(w_value, space.w_str)): + try: + value = string_to_long(space.unwrap(w_value)) + except ValueError, e: + raise OperationError(space.w_ValueError, + space.wrap(e.args[0])) else: - base = space.unwrap(w_base) - s = space.unwrap(w_value) - try: - value = long(s, base) - except TypeError, e: + # otherwise, use the __long__() method + w_obj = space.long(w_value) + # 'long(x)' should return whatever x.__long__() returned + if space.is_true(space.is_(w_longtype, space.w_long)): + return w_obj + value = space.unwrap(w_obj) + if isinstance(value, int): # XXX typechecking in unwrap! + value = long(value) + if not isinstance(value, long): + raise OperationError(space.w_ValueError, + space.wrap("value can't be converted to long")) + else: + base = space.unwrap(w_base) + if not isinstance(base, int): # XXX typechecking in unwrap! + raise OperationError(space.w_TypeError, + space.wrap("an integer is required")) + s = space.unwrap(w_value) + if not isinstance(s, str): # XXX typechecking in unwrap! raise OperationError(space.w_TypeError, - space.wrap(str(e))) + space.wrap("long() can't convert non-string " + "with explicit base")) + try: + value = string_to_long(s, base) except ValueError, e: raise OperationError(space.w_ValueError, - space.wrap(str(e))) - except OverflowError, e: - raise OperationError(space.w_OverflowError, - space.wrap(str(e))) + space.wrap(e.args[0])) + w_obj = space.allocate_instance(W_LongObject, w_longtype) w_obj.__init__(space, value) return w_obj Modified: pypy/trunk/src/pypy/objspace/std/strutil.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/strutil.py (original) +++ pypy/trunk/src/pypy/objspace/std/strutil.py Tue Nov 30 14:53:43 2004 @@ -15,12 +15,11 @@ q -= 1 return s[p:q] -def string_to_int(s, base=10): - """Utility to converts a string to an integer (or possibly a long). - If base is 0, the proper base is guessed based on the leading - characters of 's'. Raises ValueError in case of error. - """ - s = literal = strip_spaces(s) +class InvalidLiteral(Exception): + pass + +def _parse_string(s, literal, base, fname): + # internal utility for string_to_int() and string_to_long(). sign = 1 if s.startswith('-'): sign = -1 @@ -35,27 +34,46 @@ else: base = 10 elif base < 2 or base > 36: - raise ValueError, "int() base must be >= 2 and <= 36" - if not s: - if not literal: - raise ValueError, 'empty literal for int()' + raise ValueError, "%s() base must be >= 2 and <= 36" % (fname,) + try: + if not s: + raise InvalidLiteral + if base == 16 and (s.startswith('0x') or s.startswith('0X')): + s = s[2:] + # XXX uses int-to-long overflow so far + result = 0 + for c in s: + digit = ord(c) + if '0' <= c <= '9': + digit -= ord('0') + elif 'A' <= c <= 'Z': + digit = (digit - ord('A')) + 10 + elif 'a' <= c <= 'z': + digit = (digit - ord('a')) + 10 + else: + raise InvalidLiteral + if digit >= base: + raise InvalidLiteral + result = result*base + digit + return result * sign + except InvalidLiteral: + if literal: + raise ValueError, 'invalid literal for %s(): %s' % (fname, literal) else: - raise ValueError, 'invalid literal for int(): ' + literal - if base == 16 and (s.startswith('0x') or s.startswith('0X')): - s = s[2:] - # XXX uses int-to-long overflow so far - result = 0 - for c in s: - digit = ord(c) - if '0' <= c <= '9': - digit -= ord('0') - elif 'A' <= c <= 'Z': - digit = (digit - ord('A')) + 10 - elif 'a' <= c <= 'z': - digit = (digit - ord('a')) + 10 - else: - raise ValueError, 'invalid literal for int(): ' + literal - if digit >= base: - raise ValueError, 'invalid literal for int(): ' + literal - result = result*base + digit - return result * sign + raise ValueError, 'empty literal for %s()' % (fname,) + +def string_to_int(s, base=10): + """Utility to converts a string to an integer (or possibly a long). + If base is 0, the proper base is guessed based on the leading + characters of 's'. Raises ValueError in case of error. + """ + s = literal = strip_spaces(s) + return _parse_string(s, literal, base, 'int') + +def string_to_long(s, base=10): + """As string_to_int(), but ignores an optional 'l' or 'L' suffix.""" + s = literal = strip_spaces(s) + if (s.endswith('l') or s.endswith('L')) and base < 22: + # in base 22 and above, 'L' is a valid digit! try: long('L',22) + s = s[:-1] + return long(_parse_string(s, literal, base, 'long')) Modified: pypy/trunk/src/pypy/objspace/std/test/test_strutil.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_strutil.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_strutil.py Tue Nov 30 14:53:43 2004 @@ -22,6 +22,7 @@ ] for s, expected in cases: self.assertEquals(string_to_int(s), expected) + self.assertEquals(string_to_long(s), expected) def test_string_to_int_base(self): cases = [('111', 2, 7), @@ -102,5 +103,15 @@ self.assertRaises(ValueError, string_to_int, '+'+s, base) self.assertRaises(ValueError, string_to_int, '-'+s, base) + def test_string_to_long(self): + self.assertEquals(string_to_long('123L'), 123) + self.assertEquals(string_to_long('123L '), 123) + self.assertRaises(ValueError, string_to_long, 'L') + self.assertRaises(ValueError, string_to_long, 'L ') + self.assertEquals(string_to_long('123L', 4), 27) + self.assertEquals(string_to_long('123L', 30), 27000 + 1800 + 90 + 21) + self.assertEquals(string_to_long('123L', 22), 10648 + 968 + 66 + 21) + self.assertEquals(string_to_long('123L', 21), 441 + 42 + 3) + if __name__ == '__main__': testit.main() From arigo at codespeak.net Tue Nov 30 15:41:46 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 30 Nov 2004 15:41:46 +0100 (MET) Subject: [pypy-svn] r7714 - pypy/trunk/src/pypy/annotation Message-ID: <20041130144146.AD5225AEDF@thoth.codespeak.net> Author: arigo Date: Tue Nov 30 15:41:46 2004 New Revision: 7714 Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Trying to get rid of a hack: look for method_xxx() on SomeXxx objects from immutablevalue(). Modified: pypy/trunk/src/pypy/annotation/bookkeeper.py ============================================================================== --- pypy/trunk/src/pypy/annotation/bookkeeper.py (original) +++ pypy/trunk/src/pypy/annotation/bookkeeper.py Tue Nov 30 15:41:46 2004 @@ -99,10 +99,10 @@ x.im_self.freeze() if hasattr(x, '__self__') and x.__self__ is not None: s_self = self.immutablevalue(x.__self__) - # stop infinite recursion getattr<->immutablevalue - del s_self.const - s_name = self.immutablevalue(x.__name__) - result = s_self.getattr(s_name) + try: + result = s_self.find_method(x.__name__) + except AttributeError: + result = SomeObject() else: return self.getpbc(x) elif hasattr(x, '__class__') \ Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue Nov 30 15:41:46 2004 @@ -40,14 +40,20 @@ else: return SomeBool() + def find_method(obj, name): + "Look for a special-case implementation for the named method." + analyser = getattr(obj.__class__, 'method_' + name) + return SomeBuiltin(analyser, obj) + def getattr(obj, s_attr): # get a SomeBuiltin if the SomeObject has # a corresponding method to handle it if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - analyser = getattr(obj.__class__, 'method_' + attr, None) - if analyser is not None: - return SomeBuiltin(analyser, obj) + try: + return obj.find_method(attr) + except AttributeError: + pass # if the SomeObject is itself a constant, allow reading its attrs if obj.is_constant() and hasattr(obj.const, attr): return immutablevalue(getattr(obj.const, attr))