From arigo at codespeak.net Mon May 3 19:30:08 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 3 May 2004 19:30:08 +0200 (MEST) Subject: [pypy-svn] r4261 - in pypy/branch/typeinference/pypy: annotation translator Message-ID: <20040503173008.948115A164@thoth.codespeak.net> Author: arigo Date: Mon May 3 19:30:05 2004 New Revision: 4261 Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py pypy/branch/typeinference/pypy/annotation/model.py pypy/branch/typeinference/pypy/translator/annrpython.py Log: Fixed the block scheduling algorithm, which contained an endless loop: blocks far from the creation point of an object could trigger a reflow from the creation point continuously, not giving the reflow a change to reach the point where the object is used. Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/binaryop.py (original) +++ pypy/branch/typeinference/pypy/annotation/binaryop.py Mon May 3 19:30:05 2004 @@ -3,7 +3,8 @@ """ from pypy.annotation.pairtype import pair, pairtype -from pypy.annotation.model import SomeObject, SomeInteger, SomeString, SomeList +from pypy.annotation.model import SomeObject, SomeInteger, SomeBool +from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.factory import NeedGeneralization @@ -44,6 +45,12 @@ return SomeInteger() +class __extend__(pairtype(SomeBool, SomeBool)): + + def union((boo1, boo2)): + return SomeBool() + + class __extend__(pairtype(SomeString, SomeString)): def union((str1, str2)): Modified: pypy/branch/typeinference/pypy/annotation/model.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/model.py (original) +++ pypy/branch/typeinference/pypy/annotation/model.py Mon May 3 19:30:05 2004 @@ -39,6 +39,9 @@ return (self.__class__, self.__dict__) == (other.__class__, other.__dict__) def __ne__(self, other): return not (self == other) + def __repr__(self): + kwds = ', '.join(['%s=%r' % item for item in self.__dict__.items()]) + return '%s(%s)' % (self.__class__.__name__, kwds) def contains(self, other): return pair(self, other).union() == self @@ -51,8 +54,9 @@ class SomeBool(SomeInteger): "Stands for true or false." knowntype = bool + nonneg = True def __init__(self): - SomeInteger.__init__(self, nonneg=True) + pass class SomeString(SomeObject): "Stands for an object which is known to be a string." Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Mon May 3 19:30:05 2004 @@ -68,7 +68,13 @@ # 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. block, cells = self.pendingblocks.pop() - self.processblock(block, cells) + if self.processblock(block, cells): + # When flowin succeeds, i.e. when the analysis progress, + # we can tentatively re-schedule the delayed blocks. + delay = [(block, None) for block in self.delayedblocks] + delay.reverse() + self.pendingblocks[:0] = delay + del self.delayedblocks[:] if self.delayedblocks: raise AnnotatorError('%d block(s) are still blocked' % len(delayedblocks)) @@ -150,11 +156,8 @@ for factory in e.invalidatefactories: self.reflowpendingblock(factory.block) else: - # When flowin succeeds, i.e. when the analysis progress, - # we can tentatively re-schedlue the delayed blocks. - for block in self.delayedblocks: - self.addpendingblock(block, None) - del self.delayedblocks[:] + return True # progressed + return False def reflowpendingblock(self, block): self.pendingblocks.append((block, None)) @@ -177,6 +180,7 @@ self.bindinputargs(block, unions) def flowin(self, block): + #print 'Flowing', block, [self.binding(a) for a in block.inputargs] if block.operations: for i in range(len(block.operations)): self.curblockpos = block, i From arigo at codespeak.net Mon May 3 19:40:47 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 3 May 2004 19:40:47 +0200 (MEST) Subject: [pypy-svn] r4262 - pypy/branch/typeinference/pypy/translator Message-ID: <20040503174047.308E75A164@thoth.codespeak.net> Author: arigo Date: Mon May 3 19:40:44 2004 New Revision: 4262 Modified: pypy/branch/typeinference/pypy/translator/annrpython.py Log: Why doesn't Python raise a TypeError when I do this kind of mistake?? Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Mon May 3 19:40:44 2004 @@ -32,7 +32,7 @@ # make input arguments and set their type input_arg_types = list(input_arg_types) nbarg = len(flowgraph.getargs()) - while input_arg_types < nbarg: + while len(input_arg_types) < nbarg: input_arg_types.append(object) inputcells = [annmodel.valueoftype(t) for t in input_arg_types] From arigo at codespeak.net Mon May 3 20:25:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 3 May 2004 20:25:44 +0200 (MEST) Subject: [pypy-svn] r4263 - in pypy/branch/typeinference/pypy: annotation translator Message-ID: <20040503182544.CDF045A164@thoth.codespeak.net> Author: arigo Date: Mon May 3 20:25:44 2004 New Revision: 4263 Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py pypy/branch/typeinference/pypy/annotation/model.py pypy/branch/typeinference/pypy/translator/annrpython.py Log: More tests are passing. Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/binaryop.py (original) +++ pypy/branch/typeinference/pypy/annotation/binaryop.py Mon May 3 20:25:44 2004 @@ -82,6 +82,18 @@ return SomeTuple(items = tup1.items + tup2.items) +class __extend__(pairtype(SomeTuple, SomeInteger)): + + def getitem((tup1, int2)): + if int2.is_constant(): + return tup1.items[int2.const] + else: + result = SomeImpossibleValue() + for a in tup1.items: + result = pair(result, a).union() + return result + + class __extend__(pairtype(SomeList, SomeInteger)): def mul((lst1, int2)): Modified: pypy/branch/typeinference/pypy/annotation/model.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/model.py (original) +++ pypy/branch/typeinference/pypy/annotation/model.py Mon May 3 20:25:44 2004 @@ -34,9 +34,10 @@ class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" - knowntype = None + knowntype = object def __eq__(self, other): - return (self.__class__, self.__dict__) == (other.__class__, other.__dict__) + return (self.__class__ is other.__class__ and + self.__dict__ == other.__dict__) def __ne__(self, other): return not (self == other) def __repr__(self): @@ -44,6 +45,11 @@ return '%s(%s)' % (self.__class__.__name__, kwds) def contains(self, other): return pair(self, other).union() == self + def is_constant(self): + return hasattr(self, 'const') + # non-binary default methods + def len(self): + return SomeInteger(nonneg=True) class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." @@ -74,6 +80,8 @@ knowntype = tuple def __init__(self, items): self.items = tuple(items) # tuple of s_xxx elements + def len(self): + return immutablevalue(len(self.items)) class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that @@ -83,15 +91,17 @@ def immutablevalue(x): "The most precise SomeValue instance that contains the immutable value x." if isinstance(bool, type) and isinstance(x, bool): - return SomeBool() + result = SomeBool() elif isinstance(x, int): - return SomeInteger(nonneg = x>=0) + result = SomeInteger(nonneg = x>=0) elif isinstance(x, str): - return SomeString() + result = SomeString() elif isinstance(x, tuple): - return SomeTuple(items = [immutablevalue(e) for e in x]) + result = SomeTuple(items = [immutablevalue(e) for e in x]) else: - return SomeObject() + result = SomeObject() + result.const = x + return result def valueoftype(t): "The most precise SomeValue instance that contains all objects of type t." @@ -103,6 +113,8 @@ return SomeString() elif issubclass(t, list): return SomeList(factories={}) + else: + return SomeObject() # this has the side-effect of registering the binary operations Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Mon May 3 20:25:44 2004 @@ -42,7 +42,8 @@ self.complete() def gettype(self, variable): - """Return the known type of a control flow graph variable, or None.""" + """Return the known type of a control flow graph variable, + defaulting to 'object'.""" if isinstance(variable, Constant): return type(variable.value) elif isinstance(variable, Variable): @@ -50,7 +51,7 @@ if cell: return cell.knowntype else: - return None + return object else: raise TypeError, ("Variable or Constant instance expected, " "got %r" % (variable,)) @@ -60,6 +61,8 @@ def addpendingblock(self, block, cells): """Register an entry point into block with the given input cells.""" + for a in cells: + assert isinstance(a, annmodel.SomeObject) self.pendingblocks.append((block, cells)) def complete(self): @@ -109,13 +112,15 @@ # Variable that just happens to be bound to the given SomeValue. # A typical example would be if the tuple of arguments was created # from another basic block or even another function. Well I guess - # there is no clean solution. - constvalue = self.heap.get(ANN.const, cell) - if constvalue is not mostgeneralvalue: - return Constant(constvalue) + # there is no clean solution, short of making the transformations + # more syntactic (e.g. replacing a specific sequence of SpaceOperations + # with another one). This is a real hack because we have to use + # the identity of 'cell'. + if cell.is_constant(): + return Constant(cell.const) else: for v in known_variables: - if self.heap.isshared(self.bindings[v], cell): + if self.bindings[v] is cell: return v else: raise CannotSimplify @@ -192,13 +197,18 @@ def getfactory(self, factorycls): try: - return self.creationpoints[self.curblockpos] + factory = self.creationpoints[self.curblockpos] except KeyError: block = self.curblockpos[0] factory = factorycls() factory.block = block self.creationpoints[self.curblockpos] = factory - return factory + # self.curblockpos is an arbitrary key that identifies a specific + # position, so that asking twice for a factory from the same position + # returns the same factory object. Because we can ask for several + # factories in the same operation, we change self.curblockpos here + self.curblockpos = self.curblockpos, 'bis' + return factory #___ creating the annotations based on operations ______ @@ -227,44 +237,52 @@ """ % (opname, opname) del opname + def consider_op_newtuple(self, *args): + return annmodel.SomeTuple(items = args) + def consider_op_newlist(self, *args): factory = self.getfactory(ListFactory) for a in args: factory.generalize(a) return factory.create() -## 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)] + def decode_simple_call(self, s_varargs, s_varkwds): + s_nbargs = s_varargs.len() + if not s_nbargs.is_constant(): + return None + nbargs = s_nbargs.const + arg_cells = [pair(s_varargs, annmodel.immutablevalue(j)).getitem() + 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 + return arg_cells -## def consider_op_call(self, func, varargs, kwargs): -## ... -## func = self.heap.get(ANN.const, func) + 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: -## 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: 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): + return annmodel.valueoftype(func) ## # XXX flow into __init__/__new__ -## self.heap.settype(result,func) ## if func.__module__ != '__builtin__': ## self.userclasses.setdefault(func, {}) -## return result + return annmodel.SomeObject() ## def consider_op_setattr(self,obj,attr,newval): @@ -362,24 +380,6 @@ ## consider_op_gt = consider_op_lt ## consider_op_ge = consider_op_lt -## def consider_op_newtuple(self, *args): -## result = SomeValue() -## self.heap.settype(result, tuple) -## self.heap.set(ANN.len, result, len(args)) -## for i in range(len(args)): -## self.heap.set(ANN.tupleitem[i], result, args[i]) -## return result - -## def consider_op_newlist(self, *args): -## result = SomeValue() -## self.heap.settype(result, list) -## self.heap.set(ANN.len, result, len(args)) -## item_cell = impossiblevalue -## for a in args: -## item_cell = self.heap.merge(item_cell, a) -## self.heap.set(ANN.listitems, result, item_cell) -## return result - ## def consider_op_newslice(self, *args): ## result = SomeValue() ## self.heap.settype(result, slice) From arigo at codespeak.net Mon May 3 20:54:05 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 3 May 2004 20:54:05 +0200 (MEST) Subject: [pypy-svn] r4264 - in pypy/branch/typeinference/pypy: annotation translator translator/test Message-ID: <20040503185405.BDA6A5A164@thoth.codespeak.net> Author: arigo Date: Mon May 3 20:54:05 2004 New Revision: 4264 Added: pypy/branch/typeinference/pypy/annotation/unaryop.py Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py pypy/branch/typeinference/pypy/annotation/model.py pypy/branch/typeinference/pypy/translator/annrpython.py pypy/branch/typeinference/pypy/translator/test/test_annrpython.py Log: Most tests not involving user classes are passing. Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/binaryop.py (original) +++ pypy/branch/typeinference/pypy/annotation/binaryop.py Mon May 3 20:54:05 2004 @@ -6,31 +6,24 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue +from pypy.annotation.model import set, setunion, missing_operation from pypy.annotation.factory import NeedGeneralization -def setunion(d1, d2): - "Union of two sets represented as dictionaries." - d = d1.copy() - d.update(d2) - return d - -def set(it): - "Turn an iterable into a set." - d = {} - for x in it: - d[x] = True - return d - - +# XXX unify this with ObjSpace.MethodTable BINARY_OPERATIONS = set(['add', 'sub', 'mul', 'getitem', 'setitem', + 'inplace_add', + 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'union']) -def _defaultcase((obj1, obj2), *args): - return SomeObject() +for opname in BINARY_OPERATIONS: + missing_operation(pairtype(SomeObject, SomeObject), opname) + + +class __extend__(pairtype(SomeObject, SomeObject)): -for name in BINARY_OPERATIONS: - setattr(pairtype(SomeObject, SomeObject), name, _defaultcase) + def union((obj1, obj2)): + return SomeObject() class __extend__(pairtype(SomeInteger, SomeInteger)): @@ -41,9 +34,18 @@ def add((int1, int2)): return SomeInteger(nonneg = int1.nonneg and int2.nonneg) + mul = add + def sub((int1, int2)): return SomeInteger() + 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)): @@ -68,6 +70,9 @@ add = union + def inplace_add((lst1, lst2)): + pair(lst1, SomeInteger()).setitem(lst2.s_item) + class __extend__(pairtype(SomeTuple, SomeTuple)): Modified: pypy/branch/typeinference/pypy/annotation/model.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/model.py (original) +++ pypy/branch/typeinference/pypy/annotation/model.py Mon May 3 20:54:05 2004 @@ -28,12 +28,13 @@ # -from pypy.annotation.pairtype import pair +from pypy.annotation.pairtype import pair, extendabletype class SomeObject: """The set of all objects. Each instance stands for an arbitrary object about which nothing is known.""" + __metaclass__ = extendabletype knowntype = object def __eq__(self, other): return (self.__class__ is other.__class__ and @@ -47,9 +48,6 @@ return pair(self, other).union() == self def is_constant(self): return hasattr(self, 'const') - # non-binary default methods - def len(self): - return SomeInteger(nonneg=True) class SomeInteger(SomeObject): "Stands for an object which is known to be an integer." @@ -117,5 +115,29 @@ return SomeObject() -# this has the side-effect of registering the binary operations +# ____________________________________________________________ +# internal + +def setunion(d1, d2): + "Union of two sets represented as dictionaries." + d = d1.copy() + d.update(d2) + return d + +def set(it): + "Turn an iterable into a set." + d = {} + for x in it: + d[x] = True + return d + +def missing_operation(cls, name): + def default_op(*args): + print '* warning, no type available for %s(%s)' % ( + name, ', '.join([repr(a) for a in args])) + return SomeObject() + setattr(cls, name, default_op) + +# 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 Added: pypy/branch/typeinference/pypy/annotation/unaryop.py ============================================================================== --- (empty file) +++ pypy/branch/typeinference/pypy/annotation/unaryop.py Mon May 3 20:54:05 2004 @@ -0,0 +1,24 @@ +""" +Unary operations on SomeValues. +""" + +from pypy.annotation.pairtype import pair, pairtype +from pypy.annotation.model import SomeObject, SomeInteger, SomeBool +from pypy.annotation.model import SomeString, SomeList +from pypy.annotation.model import SomeTuple +from pypy.annotation.model import set, setunion, missing_operation + + +UNARY_OPERATIONS = set(['len', 'is_true']) + +for opname in UNARY_OPERATIONS: + missing_operation(SomeObject, opname) + + +class __extend__(SomeObject): + + def len(obj): + return SomeInteger(nonneg=True) + + def is_true(obj): + return SomeBool() Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Mon May 3 20:54:05 2004 @@ -229,13 +229,22 @@ def default_consider_op(self, *args): return annmodel.SomeObject() - # All binary operations - for opname in annmodel.BINARY_OPERATIONS: - exec """ + def _registeroperations(loc): + # All unary operations + for opname in annmodel.UNARY_OPERATIONS: + exec """ +def consider_op_%s(self, arg, *args): + return arg.%s(*args) +""" % (opname, opname) in globals(), loc + # All binary operations + for opname in annmodel.BINARY_OPERATIONS: + exec """ def consider_op_%s(self, arg1, arg2, *args): return pair(arg1,arg2).%s(*args) -""" % (opname, opname) - del opname +""" % (opname, opname) in globals(), loc + + _registeroperations(locals()) + del _registeroperations def consider_op_newtuple(self, *args): return annmodel.SomeTuple(items = args) Modified: pypy/branch/typeinference/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/test/test_annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/test/test_annrpython.py Mon May 3 20:54:05 2004 @@ -3,7 +3,7 @@ from pypy.tool import testit from pypy.tool.udir import udir -from pypy.translator.annrpython import RPythonAnnotator, ANN +from pypy.translator.annrpython import RPythonAnnotator, annmodel from pypy.translator.translator import Translator from pypy.objspace.flow.model import * @@ -124,9 +124,7 @@ # result should be a list of integers self.assertEquals(a.gettype(fun.getreturnvar()), list) end_cell = a.binding(fun.getreturnvar()) - item_cell = a.heap.get(ANN.listitems, end_cell) - self.assert_(item_cell) - self.assertEquals(a.heap.get(ANN.type, item_cell), int) + self.assertEquals(end_cell.s_item.knowntype, int) def test_factorial(self): translator = Translator(snippet.factorial) From arigo at codespeak.net Tue May 4 11:12:12 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 4 May 2004 11:12:12 +0200 (MEST) Subject: [pypy-svn] r4269 - pypy/branch/typeinference/pypy/translator Message-ID: <20040504091212.233DF5A164@thoth.codespeak.net> Author: arigo Date: Tue May 4 11:12:09 2004 New Revision: 4269 Modified: pypy/branch/typeinference/pypy/translator/annrpython.py Log: We don't seem to need the delayedblocks list any more, after all. Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Tue May 4 11:12:09 2004 @@ -19,7 +19,6 @@ def __init__(self, translator=None): self.pendingblocks = [] # list of (block, list-of-SomeValues-args) - self.delayedblocks = [] # list of blocked blocks self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen self.creationpoints = {} # map positions-in-blocks to Factories @@ -71,16 +70,10 @@ # 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. block, cells = self.pendingblocks.pop() - if self.processblock(block, cells): - # When flowin succeeds, i.e. when the analysis progress, - # we can tentatively re-schedule the delayed blocks. - delay = [(block, None) for block in self.delayedblocks] - delay.reverse() - self.pendingblocks[:0] = delay - del self.delayedblocks[:] - if self.delayedblocks: - raise AnnotatorError('%d block(s) are still blocked' % - len(delayedblocks)) + self.processblock(block, cells) + if False in self.annotated.values(): + raise AnnotatorError('%d blocks are still blocked' % + len(self.annotated.values().count(False))) def binding(self, arg): "Gives the SomeValue corresponding to the given Variable or Constant." @@ -157,7 +150,6 @@ self.flowin(block) except BlockedInference, e: self.annotated[block] = False # failed, hopefully temporarily - self.delayedblocks.append(block) for factory in e.invalidatefactories: self.reflowpendingblock(factory.block) else: From hpk at codespeak.net Tue May 4 16:50:26 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 4 May 2004 16:50:26 +0200 (MEST) Subject: [pypy-svn] r4271 - pypy/branch/typeinference/pypy/translator/tool Message-ID: <20040504145026.EE4EF5A164@thoth.codespeak.net> Author: hpk Date: Tue May 4 16:50:26 2004 New Revision: 4271 Modified: pypy/branch/typeinference/pypy/translator/tool/buildpyxmodule.py Log: write out the original python function that gets translated into function_name.py Modified: pypy/branch/typeinference/pypy/translator/tool/buildpyxmodule.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/tool/buildpyxmodule.py (original) +++ pypy/branch/typeinference/pypy/translator/tool/buildpyxmodule.py Tue May 4 16:50:26 2004 @@ -106,6 +106,10 @@ name = func.func_name funcgraph = space.build_flow(func) + if not inputargtypes: + source = inspect.getsource(func) + base = udir.join(name).newext('.py').write(source) + if dot: from pypy.translator.tool.make_dot import DotGen dotgen = DotGen() From arigo at codespeak.net Thu May 6 16:39:01 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 6 May 2004 16:39:01 +0200 (MEST) Subject: [pypy-svn] r4293 - in pypy/branch/typeinference/pypy: annotation translator translator/test Message-ID: <20040506143901.88DDC5A686@thoth.codespeak.net> Author: arigo Date: Thu May 6 16:39:00 2004 New Revision: 4293 Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py pypy/branch/typeinference/pypy/annotation/factory.py pypy/branch/typeinference/pypy/annotation/model.py pypy/branch/typeinference/pypy/annotation/unaryop.py pypy/branch/typeinference/pypy/translator/annrpython.py pypy/branch/typeinference/pypy/translator/genpyrex.py pypy/branch/typeinference/pypy/translator/test/snippet.py pypy/branch/typeinference/pypy/translator/test/test_annrpython.py Log: The class/instance model. Hopefully the last round of changes all over the files. More tests pass, including two new tests with inheritance. Modified: pypy/branch/typeinference/pypy/annotation/binaryop.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/binaryop.py (original) +++ pypy/branch/typeinference/pypy/annotation/binaryop.py Thu May 6 16:39:00 2004 @@ -6,8 +6,9 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue +from pypy.annotation.model import SomeInstance from pypy.annotation.model import set, setunion, missing_operation -from pypy.annotation.factory import NeedGeneralization +from pypy.annotation.factory import BlockedInference # XXX unify this with ObjSpace.MethodTable @@ -107,9 +108,11 @@ def getitem((lst1, int2)): return lst1.s_item - def setitem((lst1, int2), value): - if not lst1.s_item.contains(value): - raise NeedGeneralization(lst1, value) + def setitem((lst1, int2), s_value): + if not lst1.s_item.contains(s_value): + for factory in lst1.factories: + factory.generalize(s_value) + raise BlockedInference(lst1.factories) class __extend__(pairtype(SomeInteger, SomeList)): @@ -118,6 +121,13 @@ return lst2 +class __extend__(pairtype(SomeInstance, SomeInstance)): + + def union((ins1, ins2)): + basedef = ins1.classdef.commonbase(ins2.classdef) + return SomeInstance(basedef) + + class __extend__(pairtype(SomeImpossibleValue, SomeObject)): def union((imp1, obj2)): return obj2 Modified: pypy/branch/typeinference/pypy/annotation/factory.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/factory.py (original) +++ pypy/branch/typeinference/pypy/annotation/factory.py Thu May 6 16:39:00 2004 @@ -6,24 +6,19 @@ """ +from __future__ import generators from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeImpossibleValue, SomeList +from pypy.annotation.model import SomeObject, SomeInstance class BlockedInference(Exception): """This exception signals the type inference engine that the situation is currently blocked, and that it should try to progress elsewhere.""" - invalidatefactories = () # factories that need to be invalidated -class NeedGeneralization(BlockedInference): - """The mutable object s_mutable requires generalization. - The *args are passed to the generalize() method of the factory.""" - - def __init__(self, s_mutable, *args): - BlockedInference.__init__(self, s_mutable, *args) - for factory in s_mutable.factories: - factory.generalize(*args) - self.invalidatefactories = s_mutable.factories + def __init__(self, factories = ()): + # factories that need to be invalidated + self.invalidatefactories = factories # @@ -38,3 +33,86 @@ def generalize(self, s_new_item): self.s_item = pair(self.s_item, s_new_item).union() + + +class InstanceFactory: + + def __init__(self, cls, userclasses): + self.classdef = getclassdef(cls, userclasses) + self.classdef.instancefactories[self] = True + + def create(self): + return SomeInstance(self.classdef) + + +class ClassDef: + "Wraps a user class." + + def __init__(self, cls, userclasses): + self.attrs = {} # attrs is updated with new information + self.revision = 0 # which increases the revision number + self.instancefactories = {} + self.cls = cls + self.subdefs = {} + assert len(cls.__bases__) <= 1, "single inheritance only right now" + if cls.__bases__: + base = cls.__bases__[0] + else: + base = object + self.basedef = getclassdef(base, userclasses) + if self.basedef: + self.basedef.subdefs[cls] = self + + 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 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 getallfactories(self): + factories = {} + for clsdef in self.getallsubdefs(): + factories.update(clsdef.instancefactories) + return factories + + def generalize(self, attr, s_value): + # we make sure that an attribute never appears both in a class + # and in some subclass, in two steps: + # (1) assert that the attribute is in no superclass + for clsdef in self.getmro(): + assert clsdef is self or attr not in clsdef.attrs + # (2) remove the attribute from subclasses + for subdef in self.getallsubdefs(): + if attr in subdef.attrs: + s_value = pair(s_value, subdef.attrs[attr]).union() + del subdef.attrs[attr] + # bump the revision number of this class and all subclasses + subdef.revision += 1 + self.attrs[attr] = s_value + + +def getclassdef(cls, cache): + if cls is object: + return None + try: + return cache[cls] + except KeyError: + cache[cls] = ClassDef(cls, cache) + return cache[cls] Modified: pypy/branch/typeinference/pypy/annotation/model.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/model.py (original) +++ pypy/branch/typeinference/pypy/annotation/model.py Thu May 6 16:39:00 2004 @@ -45,7 +45,7 @@ kwds = ', '.join(['%s=%r' % item for item in self.__dict__.items()]) return '%s(%s)' % (self.__class__.__name__, kwds) def contains(self, other): - return pair(self, other).union() == self + return self == other or pair(self, other).union() == self def is_constant(self): return hasattr(self, 'const') @@ -81,6 +81,13 @@ def len(self): return immutablevalue(len(self.items)) +class SomeInstance(SomeObject): + "Stands for an instance of a (user-defined) class." + def __init__(self, classdef): + self.classdef = classdef + self.knowntype = classdef.cls + self.revision = classdef.revision + 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/branch/typeinference/pypy/annotation/unaryop.py ============================================================================== --- pypy/branch/typeinference/pypy/annotation/unaryop.py (original) +++ pypy/branch/typeinference/pypy/annotation/unaryop.py Thu May 6 16:39:00 2004 @@ -5,11 +5,13 @@ from pypy.annotation.pairtype import pair, pairtype from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList -from pypy.annotation.model import SomeTuple +from pypy.annotation.model import SomeTuple, SomeImpossibleValue +from pypy.annotation.model import SomeInstance from pypy.annotation.model import set, setunion, missing_operation +from pypy.annotation.factory import BlockedInference -UNARY_OPERATIONS = set(['len', 'is_true']) +UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr']) for opname in UNARY_OPERATIONS: missing_operation(SomeObject, opname) @@ -22,3 +24,43 @@ def is_true(obj): return SomeBool() + + +class __extend__(SomeInstance): + + def currentdef(ins): + if ins.revision != ins.classdef.revision: + print ins.revision, ins.classdef.revision + raise BlockedInference() + return ins.classdef + + def getattr(ins, attr): + if attr.is_constant() and isinstance(attr.const, str): + attr = attr.const + # 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, SomeImpossibleValue()) + raise BlockedInference(clsdef.getallfactories()) + return SomeObject() + + def setattr(ins, attr, s_value): + if attr.is_constant() and isinstance(attr.const, str): + attr = 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): + return # already general enough, nothing to do + break + else: + # 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) + raise BlockedInference(clsdef.getallfactories()) + return SomeObject() Modified: pypy/branch/typeinference/pypy/translator/annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/annrpython.py Thu May 6 16:39:00 2004 @@ -1,10 +1,10 @@ from __future__ import generators -from types import FunctionType +from types import FunctionType, ClassType from pypy.annotation import model as annmodel from pypy.annotation.model import pair -from pypy.annotation.factory import ListFactory -from pypy.annotation.factory import BlockedInference, NeedGeneralization +from pypy.annotation.factory import ListFactory, InstanceFactory +from pypy.annotation.factory import BlockedInference from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation @@ -23,6 +23,7 @@ self.annotated = {} # set of blocks already seen self.creationpoints = {} # map positions-in-blocks to Factories self.translator = translator + self.userclasses = {} # set of user classes #___ convenience high-level interface __________________ @@ -55,6 +56,18 @@ raise TypeError, ("Variable or Constant instance expected, " "got %r" % (variable,)) + def getuserclasses(self): + """Return a set of known user classes.""" + return self.userclasses + + def getuserattributes(self, cls): + """Enumerate the attributes of the given user class, as Variable()s.""" + clsdef = self.userclasses[cls] + for attr, s_value in clsdef.attrs.items(): + v = Variable(name=attr) + self.bindings[v] = s_value + yield v + #___ medium-level interface ____________________________ @@ -73,7 +86,7 @@ self.processblock(block, cells) if False in self.annotated.values(): raise AnnotatorError('%d blocks are still blocked' % - len(self.annotated.values().count(False))) + self.annotated.values().count(False)) def binding(self, arg): "Gives the SomeValue corresponding to the given Variable or Constant." @@ -86,10 +99,6 @@ else: raise TypeError, 'Variable or Constant expected, got %r' % (arg,) - def constant(self, value): - "Turn a value into a SomeValue with the proper annotations." - return annmodel.immutablevalue(arg.value) - #___ simplification (should be moved elsewhere?) _______ @@ -149,12 +158,13 @@ try: self.flowin(block) except BlockedInference, e: + #print '_'*60 + #print 'Blocked at %r:' % (self.curblockpos,) + #import traceback, sys + #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily for factory in e.invalidatefactories: self.reflowpendingblock(factory.block) - else: - return True # progressed - return False def reflowpendingblock(self, block): self.pendingblocks.append((block, None)) @@ -178,21 +188,19 @@ def flowin(self, block): #print 'Flowing', block, [self.binding(a) for a in block.inputargs] - if block.operations: - for i in range(len(block.operations)): - self.curblockpos = block, i - self.consider_op(block.operations[i]) - del self.curblockpos + for i in range(len(block.operations)): + self.curblockpos = block, i + self.consider_op(block.operations[i]) for link in block.exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(link.target, cells) - def getfactory(self, factorycls): + def getfactory(self, factorycls, *factoryargs): try: factory = self.creationpoints[self.curblockpos] except KeyError: block = self.curblockpos[0] - factory = factorycls() + factory = factorycls(*factoryargs) factory.block = block self.creationpoints[self.curblockpos] = factory # self.curblockpos is an arbitrary key that identifies a specific @@ -278,11 +286,13 @@ 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) -## # XXX flow into __init__/__new__ -## if func.__module__ != '__builtin__': -## self.userclasses.setdefault(func, {}) return annmodel.SomeObject() Modified: pypy/branch/typeinference/pypy/translator/genpyrex.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/genpyrex.py (original) +++ pypy/branch/typeinference/pypy/translator/genpyrex.py Thu May 6 16:39:00 2004 @@ -225,8 +225,8 @@ vartype = self.get_type(var) if vartype in (int, bool): prefix = "i_" - #elif self.annotator and vartype in self.annotator.getuserclasses(): - # prefix = "p_" + elif self.annotator and vartype in self.annotator.getuserclasses(): + prefix = "p_" else: prefix = "" return prefix + var.name @@ -235,8 +235,8 @@ vartype = self.get_type(var) if vartype in (int, bool): ctype = "int" - #elif self.annotator and vartype in self.annotator.getuserclasses(): - # ctype = self.get_classname(vartype) + elif self.annotator and vartype in self.annotator.getuserclasses(): + ctype = self.get_classname(vartype) else: ctype = "object" @@ -332,20 +332,20 @@ if self.annotator: self.lines = [] self.indent = 0 -## for cls in self.annotator.getuserclasses(): -## self.putline("cdef class %s:" % self.get_classname(cls)) -## self.indent += 1 -## empty = True -## for var in self.annotator.getuserattributes(cls): -## vartype, varname = self._paramvardecl(var) -## varname = var.name # no 'i_' prefix -## self.putline("cdef %s %s" % (vartype, varname)) -## empty = False -## else: -## if empty: -## self.putline("pass") -## self.indent -= 1 -## self.putline("") + for cls in self.annotator.getuserclasses(): + self.putline("cdef class %s:" % self.get_classname(cls)) + self.indent += 1 + empty = True + for var in self.annotator.getuserattributes(cls): + vartype, varname = self._paramvardecl(var) + varname = var.name # no 'i_' prefix + self.putline("cdef %s %s" % (vartype, varname)) + empty = False + else: + if empty: + self.putline("pass") + self.indent -= 1 + self.putline("") return '\n'.join(self.lines) else: return '' Modified: pypy/branch/typeinference/pypy/translator/test/snippet.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/test/snippet.py (original) +++ pypy/branch/typeinference/pypy/translator/test/snippet.py Thu May 6 16:39:00 2004 @@ -287,3 +287,22 @@ c.a = 1 c.a = 2 return c.a + +class D(C): pass +class E(C): pass + +def inheritance1(): + d = D() + d.stuff = () + e = E() + e.stuff = -12 + e.stuff = 3 + lst = [d, e] + return d.stuff, e.stuff + +def inheritance2(): + d = D() + d.stuff = (-12, -12) + e = E() + e.stuff = (3, "world") + return C().stuff Modified: pypy/branch/typeinference/pypy/translator/test/test_annrpython.py ============================================================================== --- pypy/branch/typeinference/pypy/translator/test/test_annrpython.py (original) +++ pypy/branch/typeinference/pypy/translator/test/test_annrpython.py Thu May 6 16:39:00 2004 @@ -150,6 +150,29 @@ # result should be an integer self.assertEquals(a.gettype(graph.getreturnvar()), int) + def test_inheritance1(self): + translator = Translator(snippet.inheritance1) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be exactly: + self.assertEquals(a.binding(graph.getreturnvar()), + annmodel.SomeTuple([ + annmodel.SomeTuple([]), + annmodel.SomeInteger() + ])) + + def test_inheritance2(self): + translator = Translator(snippet.inheritance2) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be exactly: + self.assertEquals(a.binding(graph.getreturnvar()), + annmodel.SomeTuple([ + annmodel.SomeInteger(), + annmodel.SomeObject() + ])) def g(n): From arigo at codespeak.net Fri May 7 00:06:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 7 May 2004 00:06:09 +0200 (MEST) Subject: [pypy-svn] r4295 - pypy/trunk/src/pypy/interpreter Message-ID: <20040506220609.BE7E25A27C@thoth.codespeak.net> Author: arigo Date: Fri May 7 00:06:07 2004 New Revision: 4295 Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py Log: Added LIST_APPEND from Python 2.4. Modified: pypy/trunk/src/pypy/interpreter/pyopcode.py ============================================================================== --- pypy/trunk/src/pypy/interpreter/pyopcode.py (original) +++ pypy/trunk/src/pypy/interpreter/pyopcode.py Fri May 7 00:06:07 2004 @@ -732,6 +732,11 @@ w_slice = f.space.newslice(w_start, w_end, w_step) f.valuestack.push(w_slice) + def LIST_APPEND(f): + w = f.valuestack.pop() + v = f.valuestack.pop() + f.space.call_method(v, 'append', w) + def SET_LINENO(f, lineno): pass From arigo at codespeak.net Fri May 7 00:09:57 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 7 May 2004 00:09:57 +0200 (MEST) Subject: [pypy-svn] r4296 - pypy/trunk/src/pypy/appspace Message-ID: <20040506220957.7D39F5A686@thoth.codespeak.net> Author: arigo Date: Fri May 7 00:09:56 2004 New Revision: 4296 Modified: pypy/trunk/src/pypy/appspace/sre_parse.py (props changed) Log: fixeol. From arigo at codespeak.net Fri May 7 00:24:00 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 7 May 2004 00:24:00 +0200 (MEST) Subject: [pypy-svn] r4297 - in pypy/trunk/src/pypy: annotation annotation/test translator translator/test translator/tool Message-ID: <20040506222400.DAE715A686@thoth.codespeak.net> Author: arigo Date: Fri May 7 00:24:00 2004 New Revision: 4297 Added: pypy/trunk/src/pypy/annotation/binaryop.py (props changed) - copied unchanged from r4295, pypy/branch/typeinference/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py (props changed) - copied unchanged from r4295, pypy/branch/typeinference/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/pairtype.py (props changed) - copied unchanged from r4295, pypy/branch/typeinference/pypy/annotation/pairtype.py pypy/trunk/src/pypy/annotation/test/test_model.py (props changed) - copied unchanged from r4295, pypy/branch/typeinference/pypy/annotation/test/test_model.py pypy/trunk/src/pypy/annotation/unaryop.py (props changed) - copied unchanged from r4295, pypy/branch/typeinference/pypy/annotation/unaryop.py Removed: pypy/trunk/src/pypy/annotation/annset.py pypy/trunk/src/pypy/annotation/test/test_annset.py Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py pypy/trunk/src/pypy/translator/transform.py pypy/trunk/src/pypy/translator/translator.py Log: Merged typeinference branch back to the trunk. -r 4208:4294 Deleted: /pypy/trunk/src/pypy/annotation/annset.py ============================================================================== --- /pypy/trunk/src/pypy/annotation/annset.py Fri May 7 00:24:00 2004 +++ (empty file) @@ -1,209 +0,0 @@ -from __future__ import generators -import types -from model import SomeValue, ANN, immutable_types - - -class MostGeneralValue: - def __nonzero__(self): - return False -mostgeneralvalue = MostGeneralValue() - -class ImpossibleValue(Exception): - pass -impossiblevalue = ImpossibleValue() - - -class About: - def __init__(self): - # 'annotations' maps Predicates to tuples - # (SomeValue, {set-of-blocks-depending-on-this-annotation}) - self.annotations = {} - self.subjects = {} # set of SomeValues we are about - def __repr__(self): # debugging - subjs = [repr(c) for c in self.subjects] - subjs.sort() - lines = ['About %s:' % ' and '.join(subjs)] - annotations = [(str(pred), value) - for pred, (value, deps) in self.annotations.items()] - annotations.sort() - for name, somevalue in annotations: - lines.append('%15s --> %r' % (name, somevalue)) - return '\n'.join(lines) - - -class AnnotationSet: - """An annotation set is a (large) family of annotations.""" - - # This is basically a mapping {SomeValue(): About()} - # with convenient methods. - - def __init__(self): - self.about = {} - self.inblock = None - - def enter(self, block, callback): - self.inblock = block - self.callback = callback - - def leave(self): - self.inblock = None - - def isshared(self, val1, val2): - return self.about.get(val1, val1) == self.about.get(val2, val2) - - def __repr__(self): # debugging - lines = ['===== AnnotationSet ====='] - abouts = [(repr(somevalue), about) - for somevalue, about in self.about.items()] - abouts.sort() - alreadyseen = {} - for name, about in abouts: - if about not in alreadyseen: - if about.annotations: # ignore empty Abouts - lines.append(repr(about)) - alreadyseen[about] = True - return '\n'.join(lines) - - def get(self, predicate, subject): - if subject is not mostgeneralvalue: - about = self._about(subject) - result = about.annotations.get(predicate) - if result: - answer, dependencies = result - if self.inblock: - dependencies[self.inblock] = True - return answer - return mostgeneralvalue - - def _about(self, somevalue): - try: - return self.about[somevalue] - except KeyError: - if somevalue is mostgeneralvalue: - raise ValueError, "Unexpected mostgeneralvalue" - if isinstance(somevalue, ImpossibleValue): - raise somevalue - about = self.about[somevalue] = About() - about.subjects[somevalue] = True - return about - - def set(self, predicate, subject, answer): - about = self._about(subject) - if predicate in about.annotations: - raise ValueError, "There is already an annotation for %r" % subject - if answer is not mostgeneralvalue: - about.annotations[predicate] = answer, {} - - def kill(self, predicate, subject): - about = self._about(subject) - if predicate in about.annotations: - someval, deps = about.annotations[predicate] - del about.annotations[predicate] - # perform invalidations - for block in deps: - self.callback(block) - - def generalize(self, predicate, subject, otherpossibleanswer): - """Generalize the given annotation to also account for the given - answer.""" - # We shouldn't record a dependency so - # we can't just do 'oldanswer = self.get(predicate, subject)' - oldanswer = mostgeneralvalue - if subject is not mostgeneralvalue: - about = self._about(subject) - old = about.annotations.get(predicate) - if old: - oldanswer, dependencies = old - newanswer = self.merge(oldanswer, otherpossibleanswer) - if not self.isshared(oldanswer, newanswer): - self.kill(predicate, subject) - self.set(predicate, subject, newanswer) - - def set_or_generalize(self, predicate, subject, otherpossibleanswer): - """This is a hack. Do not use for SomeValues that could be merged.""" - about = self._about(subject) - if predicate in about.annotations: - self.generalize(predicate, subject, otherpossibleanswer) - else: - self.set(predicate, subject, otherpossibleanswer) - - def merge(self, oldvalue, newvalue): - """Update the heap to account for the merging of oldvalue and newvalue. - Return the merged somevalue.""" - if isinstance(newvalue, ImpossibleValue): - return oldvalue - if isinstance(oldvalue, ImpossibleValue): - return newvalue - if newvalue is mostgeneralvalue or oldvalue is mostgeneralvalue: - return mostgeneralvalue - if self.isshared(oldvalue, newvalue): - return oldvalue - - if not (isinstance(oldvalue, SomeValue) and - isinstance(newvalue, SomeValue)): - return mostgeneralvalue - - # build an About set that is the intersection of the two incoming ones - about1 = self._about(oldvalue) - about2 = self._about(newvalue) - about3 = About() - for pred in about1.annotations: - if pred in about2.annotations: - someval1, dep1 = about1.annotations[pred] - someval2, dep2 = about2.annotations[pred] - if someval1 == someval2: - someval3 = someval1 - else: - someval3 = self.merge(someval1, someval2) - if someval3 is mostgeneralvalue: - continue # annotation not in common - dep3 = dep1.copy() - dep3.update(dep2) - about3.annotations[pred] = someval3, dep3 - - # if 'oldvalue' or 'newvalue' is immutable, we should not - # modify the annotations about it. If one of them is mutable, - # then we must replace its About set with 'about3'. - invalidatedblocks = {} - for about in [about1, about2]: - # find all annotations that are removed or generalized - removedannotations = [] - for pred, (someval, deps) in about.annotations.items(): - if (pred in about3.annotations and - self.isshared(about3.annotations[pred][0], someval)): - continue # unmodified annotation - removedannotations.append(deps) - # if the existing 'value' is mutable, or if nothing has been - # removed, then we identify (by sharing) the 'value' and the - # new 'about3'. - if not removedannotations or ANN.immutable not in about.annotations: - # patch 'value' to use the new 'about3'. - for sharedvalue in about.subjects: # this includes 'value' - self.about[sharedvalue] = about3 - about3.subjects[sharedvalue] = True - for deps in removedannotations: - invalidatedblocks.update(deps) - - if not about3.subjects: - value3 = SomeValue() - self.about[value3] = about3 - about3.subjects[value3] = True - - # perform invalidations - for block in invalidatedblocks: - self.callback(block) - - return about3.subjects.iterkeys().next() - - def checktype(self, someval, checktype): - knowntype = self.get(ANN.type, someval) - return knowntype and issubclass(knowntype, checktype) - - def settype(self, someval, knowntype): - self.set(ANN.type, someval, knowntype) - if knowntype in immutable_types: - self.set(ANN.immutable, someval, True) - - def copytype(self, oldcell, newcell): - self.set(ANN.type, newcell, self.get(ANN.type, oldcell)) - self.set(ANN.immutable, newcell, self.get(ANN.immutable, oldcell)) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri May 7 00:24:00 2004 @@ -1,52 +1,150 @@ -import types +""" +This file defines the 'subset' SomeValue classes. -class SomeValue: +An instance of a SomeValue class stands for a Python object that has some +known properties, for example that is known to be a list of non-negative +integers. Each instance can be considered as an object that is only +'partially defined'. Another point of view is that each instance is a +generic element in some specific subset of the set of all objects. + +""" + +# Old terminology still in use here and there: +# SomeValue means one of the SomeXxx classes in this file. +# Cell is an instance of one of these classes. +# +# Think about cells as potato-shaped circles in a diagram: +# ______________________________________________________ +# / SomeObject() \ +# / ___________________________ ______________ \ +# | / SomeInteger(nonneg=False) \____ / SomeString() \ \ +# | / __________________________ \ | | | +# | | / SomeInteger(nonneg=True) \ | | "hello" | | +# | | | 0 42 _________/ | \______________/ | +# | \ -3 \________________/ / | +# \ \ -5 _____/ / +# \ \________________________/ 3.1416 / +# \_____________________________________________________/ +# + + +from pypy.annotation.pairtype import pair, extendabletype + + +class SomeObject: + """The set of all objects. Each instance stands + for an arbitrary object about which nothing is known.""" + __metaclass__ = extendabletype + knowntype = object + def __eq__(self, other): + return (self.__class__ is other.__class__ and + self.__dict__ == other.__dict__) + def __ne__(self, other): + return not (self == other) def __repr__(self): - return debugname(self, 'SV') - -class Predicate: - def __init__(self, debugname): - self.debugname = debugname - def __str__(self): - return self.debugname - -class PredicateFamily: - def __init__(self, familyname): - self.familyname = familyname - self.instances = {} - def __getitem__(self, index): - try: - return self.instances[index] - except KeyError: - name = '%s[%r]' % (self.familyname, index) - pred = self.instances[index] = Predicate(name) - return pred - -class ANN: - len = Predicate('len') - listitems = Predicate('listitems') - tupleitem = PredicateFamily('tupleitem') - const = Predicate('const') - type = Predicate('type') - immutable = Predicate('immutable') - instanceattr = PredicateFamily('instanceattr') - - -def debugname(someval, prefix, _seen = {}): - """ return a simple name for a SomeValue. """ - try: - return _seen[id(someval)] - except KeyError: - name = "%s%d" % (prefix, len(_seen)) - _seen[id(someval)] = name - return name - -immutable_types = { - int: 'int', - long: 'long', - tuple: 'tuple', - str: 'str', - bool: 'bool', - slice: 'slice', - types.FunctionType: 'function', - } + kwds = ', '.join(['%s=%r' % item for item in self.__dict__.items()]) + return '%s(%s)' % (self.__class__.__name__, kwds) + def contains(self, other): + return self == other or pair(self, other).union() == self + def is_constant(self): + return hasattr(self, 'const') + +class SomeInteger(SomeObject): + "Stands for an object which is known to be an integer." + knowntype = int + def __init__(self, nonneg=False): + self.nonneg = nonneg + +class SomeBool(SomeInteger): + "Stands for true or false." + knowntype = bool + nonneg = True + def __init__(self): + pass + +class SomeString(SomeObject): + "Stands for an object which is known to be a string." + knowntype = str + +class SomeList(SomeObject): + "Stands for a homogenous list of any length." + knowntype = list + def __init__(self, factories, s_item=SomeObject()): + 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 + def __init__(self, items): + self.items = tuple(items) # tuple of s_xxx elements + def len(self): + return immutablevalue(len(self.items)) + +class SomeInstance(SomeObject): + "Stands for an instance of a (user-defined) class." + def __init__(self, classdef): + self.classdef = classdef + self.knowntype = classdef.cls + self.revision = classdef.revision + +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.""" + + +def immutablevalue(x): + "The most precise SomeValue instance that contains the immutable value x." + if isinstance(bool, type) and isinstance(x, bool): + result = SomeBool() + elif isinstance(x, int): + result = SomeInteger(nonneg = x>=0) + elif isinstance(x, str): + result = SomeString() + elif isinstance(x, tuple): + result = SomeTuple(items = [immutablevalue(e) for e in x]) + else: + result = SomeObject() + result.const = x + return result + +def valueoftype(t): + "The most precise SomeValue instance that contains all objects of type t." + if isinstance(bool, type) and issubclass(t, bool): + return SomeBool() + elif issubclass(t, int): + return SomeInteger() + elif issubclass(t, str): + return SomeString() + elif issubclass(t, list): + return SomeList(factories={}) + else: + return SomeObject() + + +# ____________________________________________________________ +# internal + +def setunion(d1, d2): + "Union of two sets represented as dictionaries." + d = d1.copy() + d.update(d2) + return d + +def set(it): + "Turn an iterable into a set." + d = {} + for x in it: + d[x] = True + return d + +def missing_operation(cls, name): + def default_op(*args): + print '* warning, no type available for %s(%s)' % ( + name, ', '.join([repr(a) for a in args])) + return SomeObject() + setattr(cls, name, default_op) + +# 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 Deleted: /pypy/trunk/src/pypy/annotation/test/test_annset.py ============================================================================== --- /pypy/trunk/src/pypy/annotation/test/test_annset.py Fri May 7 00:24:00 2004 +++ (empty file) @@ -1,229 +0,0 @@ - -import autopath -from pypy.tool import testit - -from pypy.annotation.model import SomeValue, ANN, Predicate -from pypy.annotation.annset import AnnotationSet, mostgeneralvalue,impossiblevalue - - -c1,c2,c3,c4 = SomeValue(), SomeValue(), SomeValue(), SomeValue() -c5,c6,c7,c8 = SomeValue(), SomeValue(), SomeValue(), SomeValue() - -def annset(*args, **kwds): - "This constructor is just a convenient hack for the tests." - annset = AnnotationSet() - groups = [] - for a in args: - if isinstance(a, Predicate): - groups.append([a]) - else: - groups[-1].append(a) # hack hack hack - for args in groups: - if len(args) == 2: - args = args + [True] # " " " - annset.set(*args) - if 'links' in kwds: - links = kwds['links'] - for i in range(0, len(links), 2): - if annset.about.get(links[i]) != annset.about.get(links[i+1]): - assert links[i] not in annset.about - about = annset.about[links[i]] = annset.about[links[i+1]] - about.subjects[links[i]] = True - return annset - - -class TestAnnotationSet(testit.IntTestCase): - - def assertSameSet(self, annset1, annset2): - self.assertEquals(repr(annset1), repr(annset2)) - - def assertSameCells(self, annset, firstcell, *cells): - for cell in cells: - self.assert_(annset.isshared(firstcell, cell)) - - def test_trivial(self): - a1 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - a2 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - self.assertSameSet(a1, a2) - - def test_get(self): - a1 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - self.assertEquals(a1.get(ANN.len, c1), c2) - self.assertEquals(a1.get(ANN.len, c2), mostgeneralvalue) - - def test_set(self): - a1 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - a1.set(ANN.len, c2, c3) - self.assertSameSet(a1, - annset(ANN.len, c1, c2, - ANN.type, c2, int, - ANN.len, c2, c3)) - - def test_kill(self): - a1 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - for i in range(2): - a1.kill(ANN.len, c1) - self.assertSameSet(a1, - annset(ANN.type, c2, int)) - - def test_merge_mostgeneralvalue(self): - a1 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - a2 = annset(ANN.len, c1, c2, - ANN.type, c2, int) - # (c3) inter (mostgeneralvalue) == (mostgeneralvalue) - c = a1.merge(c3, mostgeneralvalue) - self.assertEquals(c, mostgeneralvalue) - self.assertSameSet(a1, a2) - - def test_merge_mutable1(self): - a1 = annset(ANN.len, c1, c2, - ANN.len, c3, c2) - a2 = annset(ANN.len, c1, c2, links=[c3,c1]) - # (c1) inter (c3) == (c1 shared with c3) - c = a1.merge(c1, c3) - self.assertSameCells(a1, c, c1, c3) - self.assertSameSet(a1, a2) - - def test_merge_mutable2(self): - a1 = annset(ANN.len, c1, c2, - ANN.len, c3, c2, - ANN.type, c1, list, - ANN.type, c2, str) - a2 = annset(ANN.len, c1, c2, - ANN.type, c2, str, - links=[c3,c1]) - # (c1) inter (c3) == (c1 shared with c3) - c = a1.merge(c1, c3) - self.assertSameCells(a1, c, c1, c3) - self.assertSameSet(a1, a2) - - def test_merge_same_immutables(self): - a1 = annset(ANN.len, c1, c2, - ANN.immutable, c1, - ANN.len, c3, c2, - ANN.immutable, c3) - # (c1) inter (c3) == (c1 and c3) - c = a1.merge(c1, c3) - self.assertSameCells(a1, c, c1, c3) - a2 = annset(ANN.len, c, c2, - ANN.immutable, c, - links=[c1,c,c3,c]) - self.assertSameSet(a1, a2) - - def test_merge_generalize_one_immutable(self): - a1 = annset(ANN.len, c1, c2, - ANN.immutable, c1, - ANN.type, c1, list, - ANN.len, c3, c2, - ANN.immutable, c3, - ANN.type, c2, str) - # (c1) inter (c3) == (c3) - c = a1.merge(c1, c3) - self.assertSameCells(a1, c, c3) - a2 = annset(ANN.len, c1, c2, - ANN.immutable, c1, - ANN.type, c1, list, - ANN.len, c, c2, - ANN.immutable, c, - ANN.type, c2, str, - links=[c3,c]) - self.assertSameSet(a1, a2) - - def test_level2_merge_w_impossible(self): - a1 = annset(ANN.type, c1, list, - ANN.listitems, c1, impossiblevalue, - ANN.type, c2, list, - ANN.listitems, c2, c3, - ANN.type, c3, int) - c = a1.merge(c1,c2) - a2 = annset(ANN.type, c , list, - ANN.listitems, c, c3, - ANN.type, c3, int, - links=[c1,c]) - self.assertSameSet(a1,a2) - - def test_merge_generalize_both_immutables(self): - a1 = annset(ANN.len, c1, c2, - ANN.immutable, c1, - ANN.type, c1, list, - ANN.len, c3, c2, - ANN.immutable, c3, - ANN.type, c3, tuple, - ANN.type, c2, str) - # (c1) inter (c3) == (a more general c) - c = a1.merge(c1, c3) - a2 = annset(ANN.len, c1, c2, - ANN.immutable, c1, - ANN.type, c1, list, - ANN.len, c3, c2, - ANN.immutable, c3, - ANN.type, c3, tuple, - ANN.len, c, c2, - ANN.immutable, c, - ANN.type, c2, str) - self.assertSameSet(a1, a2) - - def test_recursive_merge(self): - a1 = annset(ANN.tupleitem[2], c1, c2, - ANN.immutable, c1, - ANN.type, c2, list, - ANN.listitems, c2, c3, - ANN.type, c3, int, - ANN.immutable, c3, - ANN.tupleitem[2], c5, c6, - ANN.immutable, c5, - ANN.type, c6, list, - ANN.listitems, c6, c7, - ANN.type, c7, float, - ANN.immutable, c7) - c9 = a1.merge(c1, c5) - c10 = a1.get(ANN.tupleitem[2], c9) - c11 = a1.get(ANN.listitems, c10) - self.assertSameCells(a1, c1, c5, c9) - self.assertSameCells(a1, c2, c6, c10) - - a2 = annset(ANN.tupleitem[2], c9, c10, - ANN.immutable, c9, - ANN.type, c10, list, - ANN.listitems, c10, c11, - ANN.immutable, c11, - # old remaining stuff - ANN.type, c3, int, - ANN.immutable, c3, - ANN.type, c7, float, - ANN.immutable, c7, - links=[c1,c9, c5,c9, c2,c10, c6,c10]) - self.assertSameSet(a1, a2) - - def test_settype(self): - a = annset() - a.settype(c1, int) - a.settype(c2, list) - self.assertSameSet(a, - annset(ANN.type, c1, int, - ANN.immutable, c1, - ANN.type, c2, list)) - - def test_copytype(self): - a = annset(ANN.type, c1, int, - ANN.immutable, c1, - ANN.type, c2, list) - a.copytype(c1, c3) - a.copytype(c2, c4) - self.assertSameSet(a, - annset(ANN.type, c1, int, - ANN.immutable, c1, - ANN.type, c2, list, - ANN.type, c3, int, - ANN.immutable, c3, - ANN.type, c4, list)) - - -if __name__ == '__main__': - testit.main() Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri May 7 00:24:00 2004 @@ -1,9 +1,10 @@ from __future__ import generators -from types import FunctionType -from pypy.annotation.model import SomeValue, ANN -from pypy.annotation.annset import AnnotationSet -from pypy.annotation.annset import impossiblevalue, mostgeneralvalue +from types import FunctionType, ClassType +from pypy.annotation import model as annmodel +from pypy.annotation.model import pair +from pypy.annotation.factory import ListFactory, InstanceFactory +from pypy.annotation.factory import BlockedInference from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation @@ -11,34 +12,29 @@ class AnnotatorError(Exception): pass -intvalue = SomeValue() -boolvalue = SomeValue() - class RPythonAnnotator: """Block annotator for RPython. See description in doc/transation/annotation.txt.""" def __init__(self, translator=None): - self.heap = AnnotationSet() - self.heap.settype(intvalue, int) - self.heap.settype(boolvalue, bool) self.pendingblocks = [] # list of (block, list-of-SomeValues-args) - self.delayedblocks = [] # list of blocked blocks - self.bindings = {} # map Variables/Constants to SomeValues + self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen + self.creationpoints = {} # map positions-in-blocks to Factories self.translator = translator - self.userclasses = {} # set of user classes discovered, - # mapped to sets of instance attributes + self.userclasses = {} # set of user classes #___ convenience high-level interface __________________ def build_types(self, flowgraph, input_arg_types): """Recursively build annotations about the specific entry point.""" # make input arguments and set their type - inputcells = [SomeValue() for arg in flowgraph.getargs()] - for cell, arg_type in zip(inputcells, input_arg_types): - self.heap.settype(cell, arg_type) + input_arg_types = list(input_arg_types) + nbarg = len(flowgraph.getargs()) + while len(input_arg_types) < nbarg: + input_arg_types.append(object) + inputcells = [annmodel.valueoftype(t) for t in input_arg_types] # register the entry point self.addpendingblock(flowgraph.startblock, inputcells) @@ -46,16 +42,16 @@ self.complete() def gettype(self, variable): - """Return the known type of a control flow graph variable, or None.""" + """Return the known type of a control flow graph variable, + defaulting to 'object'.""" if isinstance(variable, Constant): return type(variable.value) elif isinstance(variable, Variable): cell = self.bindings.get(variable) if cell: - cell = self.heap.get(ANN.type, cell) - if cell: - return cell - return None + return cell.knowntype + else: + return object else: raise TypeError, ("Variable or Constant instance expected, " "got %r" % (variable,)) @@ -66,11 +62,10 @@ def getuserattributes(self, cls): """Enumerate the attributes of the given user class, as Variable()s.""" - for attr in self.userclasses[cls]: - clscell = self.constant(cls) - attrcell = self.heap.get(ANN.instanceattr[attr], clscell) + clsdef = self.userclasses[cls] + for attr, s_value in clsdef.attrs.items(): v = Variable(name=attr) - self.bindings[v] = attrcell + self.bindings[v] = s_value yield v @@ -78,37 +73,31 @@ def addpendingblock(self, block, cells): """Register an entry point into block with the given input cells.""" + for a in cells: + assert isinstance(a, annmodel.SomeObject) self.pendingblocks.append((block, cells)) 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. - # let's do it breadth-first and pop from the head (oldest first). - # that's more stacklessy. - block, cells = self.pendingblocks.pop(0) + # but suspect from the tail is better in the new Factory model. + block, cells = self.pendingblocks.pop() self.processblock(block, cells) - if self.delayedblocks: - raise AnnotatorError('%d block(s) are still blocked' % - len(delayedblocks)) + if False in self.annotated.values(): + raise AnnotatorError('%d blocks are still blocked' % + self.annotated.values().count(False)) def binding(self, arg): "Gives the SomeValue corresponding to the given Variable or Constant." - try: + if isinstance(arg, Variable): return self.bindings[arg] - except KeyError: - if not isinstance(arg, Constant): - raise # propagate missing bindings for Variables - if isinstance(arg, UndefinedConstant): - result = impossiblevalue # undefined local variables - else: - result = self.consider_const(arg.value) - self.bindings[arg] = result - return result - - def constant(self, value): - "Turn a value into a SomeValue with the proper annotations." - return self.binding(Constant(value)) + elif isinstance(arg, UndefinedConstant): # undefined local variables + return annmodel.SomeImpossibleValue() + elif isinstance(arg, Constant): + return annmodel.immutablevalue(arg.value) + else: + raise TypeError, 'Variable or Constant expected, got %r' % (arg,) #___ simplification (should be moved elsewhere?) _______ @@ -125,13 +114,15 @@ # Variable that just happens to be bound to the given SomeValue. # A typical example would be if the tuple of arguments was created # from another basic block or even another function. Well I guess - # there is no clean solution. - constvalue = self.heap.get(ANN.const, cell) - if constvalue is not mostgeneralvalue: - return Constant(constvalue) + # there is no clean solution, short of making the transformations + # more syntactic (e.g. replacing a specific sequence of SpaceOperations + # with another one). This is a real hack because we have to use + # the identity of 'cell'. + if cell.is_constant(): + return Constant(cell.const) else: for v in known_variables: - if self.heap.isshared(self.bindings[v], cell): + if self.bindings[v] is cell: return v else: raise CannotSimplify @@ -166,15 +157,14 @@ self.annotated[block] = True try: self.flowin(block) - except DelayAnnotation: + except BlockedInference, e: + #print '_'*60 + #print 'Blocked at %r:' % (self.curblockpos,) + #import traceback, sys + #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily - self.delayedblocks.append(block) - else: - # When flowin succeeds, i.e. when the analysis progress, - # we can tentatively re-schedlue the delayed blocks. - for block in self.delayedblocks: - self.addpendingblock(block, None) - del self.delayedblocks[:] + for factory in e.invalidatefactories: + self.reflowpendingblock(factory.block) def reflowpendingblock(self, block): self.pendingblocks.append((block, None)) @@ -190,29 +180,36 @@ def mergeinputargs(self, block, inputcells): # Merge the new 'cells' with each of the block's existing input # variables. - oldcells = [] - newcells = [] - for a, cell2 in zip(block.inputargs, inputcells): - cell1 = self.bindings[a] # old binding - oldcells.append(cell1) - newcells.append(self.heap.merge(cell1, cell2)) + oldcells = [self.binding(a) for a in block.inputargs] + unions = [pair(c1,c2).union() for c1, c2 in zip(oldcells, inputcells)] # if the merged cells changed, we must redo the analysis - #print '** oldcells = ', oldcells - #print '** newcells = ', newcells - for cell1, cell2 in zip(oldcells, newcells): - if not self.heap.isshared(cell1, cell2): - self.bindinputargs(block, newcells) - return + if unions != oldcells: + self.bindinputargs(block, unions) def flowin(self, block): - self.heap.enter(block, self.reflowpendingblock) - for op in block.operations: - self.consider_op(op) - self.heap.leave() + #print 'Flowing', block, [self.binding(a) for a in block.inputargs] + for i in range(len(block.operations)): + self.curblockpos = block, i + self.consider_op(block.operations[i]) for link in block.exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(link.target, cells) + def getfactory(self, factorycls, *factoryargs): + try: + factory = self.creationpoints[self.curblockpos] + except KeyError: + block = self.curblockpos[0] + factory = factorycls(*factoryargs) + factory.block = block + self.creationpoints[self.curblockpos] = factory + # self.curblockpos is an arbitrary key that identifies a specific + # position, so that asking twice for a factory from the same position + # returns the same factory object. Because we can ask for several + # factories in the same operation, we change self.curblockpos here + self.curblockpos = self.curblockpos, 'bis' + return factory + #___ creating the annotations based on operations ______ @@ -221,199 +218,247 @@ consider_meth = getattr(self,'consider_op_'+op.opname, self.default_consider_op) resultcell = consider_meth(*argcells) - if resultcell is impossiblevalue: - raise DelayAnnotation # the operation cannot succeed - assert isinstance(resultcell, (SomeValue, type(mostgeneralvalue))) + if resultcell is None: + resultcell = annmodel.SomeImpossibleValue() # no return value + elif resultcell == annmodel.SomeImpossibleValue(): + raise BlockedInference # the operation cannot succeed + assert isinstance(resultcell, annmodel.SomeObject) assert isinstance(op.result, Variable) self.bindings[op.result] = resultcell # bind resultcell to op.result - 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 default_consider_op(self, *args): - return mostgeneralvalue + return annmodel.SomeObject() - 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 _registeroperations(loc): + # All unary operations + for opname in annmodel.UNARY_OPERATIONS: + exec """ +def consider_op_%s(self, arg, *args): + return arg.%s(*args) +""" % (opname, opname) in globals(), loc + # All binary operations + for opname in annmodel.BINARY_OPERATIONS: + exec """ +def consider_op_%s(self, arg1, arg2, *args): + return pair(arg1,arg2).%s(*args) +""" % (opname, opname) in globals(), loc - 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 + _registeroperations(locals()) + del _registeroperations def consider_op_newtuple(self, *args): - result = SomeValue() - self.heap.settype(result, tuple) - self.heap.set(ANN.len, result, len(args)) - for i in range(len(args)): - self.heap.set(ANN.tupleitem[i], result, args[i]) - return result + return annmodel.SomeTuple(items = args) def consider_op_newlist(self, *args): - result = SomeValue() - self.heap.settype(result, list) - self.heap.set(ANN.len, result, len(args)) - item_cell = impossiblevalue + factory = self.getfactory(ListFactory) for a in args: - item_cell = self.heap.merge(item_cell, a) - self.heap.set(ANN.listitems, result, item_cell) - return result - - 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: + factory.generalize(a) + return factory.create() + + def decode_simple_call(self, s_varargs, s_varkwds): + s_nbargs = s_varargs.len() + if not s_nbargs.is_constant(): return None - arg_cells = [self.heap.get(ANN.tupleitem[j], varargs_cell) + nbargs = s_nbargs.const + arg_cells = [pair(s_varargs, annmodel.immutablevalue(j)).getitem() 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 +## 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) + 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: - self.heap.settype(result, list) + factory = self.getfactory(ListFactory) + factory.generalize(annmodel.SomeInteger()) # XXX nonneg=... + return factory.create() elif func is pow: - args = self.decode_simple_call(varargs, kwargs) + args = self.decode_simple_call(s_varargs, s_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) + 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(varargs, kwargs) + args = self.decode_simple_call(s_varargs, s_kwargs) return self.translator.consider_call(self, func, args) - elif isinstance(func,type): + elif (isinstance(func, (type, ClassType)) and + func.__module__ != '__builtin__'): # 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 + factory = self.getfactory(InstanceFactory, func, self.userclasses) + return factory.create() + elif isinstance(func,type): + return annmodel.valueoftype(func) + return annmodel.SomeObject() -class CannotSimplify(Exception): - pass +## 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 + -class DelayAnnotation(Exception): +## 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 Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Fri May 7 00:24:00 2004 @@ -328,8 +328,7 @@ self.gen_block(block) def globaldeclarations(self): - """Static method to generate the global class declaration for a - group of functions.""" + """Generate the global class declaration for a group of functions.""" if self.annotator: self.lines = [] self.indent = 0 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 May 7 00:24:00 2004 @@ -287,3 +287,22 @@ c.a = 1 c.a = 2 return c.a + +class D(C): pass +class E(C): pass + +def inheritance1(): + d = D() + d.stuff = () + e = E() + e.stuff = -12 + e.stuff = 3 + lst = [d, e] + return d.stuff, e.stuff + +def inheritance2(): + d = D() + d.stuff = (-12, -12) + e = E() + e.stuff = (3, "world") + return C().stuff 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 May 7 00:24:00 2004 @@ -3,7 +3,7 @@ from pypy.tool import testit from pypy.tool.udir import udir -from pypy.translator.annrpython import RPythonAnnotator, ANN +from pypy.translator.annrpython import RPythonAnnotator, annmodel from pypy.translator.translator import Translator from pypy.objspace.flow.model import * @@ -124,9 +124,7 @@ # result should be a list of integers self.assertEquals(a.gettype(fun.getreturnvar()), list) end_cell = a.binding(fun.getreturnvar()) - item_cell = a.heap.get(ANN.listitems, end_cell) - self.assert_(item_cell) - self.assertEquals(a.heap.get(ANN.type, item_cell), int) + self.assertEquals(end_cell.s_item.knowntype, int) def test_factorial(self): translator = Translator(snippet.factorial) @@ -152,6 +150,29 @@ # result should be an integer self.assertEquals(a.gettype(graph.getreturnvar()), int) + def test_inheritance1(self): + translator = Translator(snippet.inheritance1) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be exactly: + self.assertEquals(a.binding(graph.getreturnvar()), + annmodel.SomeTuple([ + annmodel.SomeTuple([]), + annmodel.SomeInteger() + ])) + + def test_inheritance2(self): + translator = Translator(snippet.inheritance2) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, []) + # result should be exactly: + self.assertEquals(a.binding(graph.getreturnvar()), + annmodel.SomeTuple([ + annmodel.SomeInteger(), + annmodel.SomeObject() + ])) def g(n): 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 May 7 00:24:00 2004 @@ -106,6 +106,10 @@ name = func.func_name funcgraph = space.build_flow(func) + if not inputargtypes: + source = inspect.getsource(func) + base = udir.join(name).newext('.py').write(source) + if dot: from pypy.translator.tool.make_dot import DotGen dotgen = DotGen() Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Fri May 7 00:24:00 2004 @@ -6,7 +6,6 @@ import types from pypy.objspace.flow.model import SpaceOperation -from pypy.annotation.model import SomeValue from pypy.translator.annrpython import CannotSimplify # XXX: Lots of duplicated codes. Fix this! Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Fri May 7 00:24:00 2004 @@ -32,7 +32,6 @@ from pypy.objspace.flow.model import * from pypy.annotation.model import * -from pypy.annotation.annset import * from pypy.translator.annrpython import RPythonAnnotator from pypy.translator.simplify import simplify_graph from pypy.translator.genpyrex import GenPyrex From arigo at codespeak.net Fri May 7 11:41:43 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 7 May 2004 11:41:43 +0200 (MEST) Subject: [pypy-svn] r4300 - pypy/trunk/src/pypy/translator/test Message-ID: <20040507094143.A72745A27C@thoth.codespeak.net> Author: arigo Date: Fri May 7 11:41:43 2004 New Revision: 4300 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: An extra test. 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 May 7 11:41:43 2004 @@ -288,6 +288,14 @@ c.a = 2 return c.a +def merge_setattr(x): + if x: + c = C() + c.a = 1 + else: + c = C() + return c.a + class D(C): pass class E(C): 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 Fri May 7 11:41:43 2004 @@ -150,6 +150,14 @@ # result should be an integer self.assertEquals(a.gettype(graph.getreturnvar()), int) + def test_merge_setattr(self): + translator = Translator(snippet.merge_setattr) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, [int]) + # result should be an integer + self.assertEquals(a.gettype(graph.getreturnvar()), int) + def test_inheritance1(self): translator = Translator(snippet.inheritance1) graph = translator.getflowgraph() From arigo at codespeak.net Fri May 7 18:22:26 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 7 May 2004 18:22:26 +0200 (MEST) Subject: [pypy-svn] r4315 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20040507162226.2E6765AC87@thoth.codespeak.net> Author: arigo Date: Fri May 7 18:22:25 2004 New Revision: 4315 Added: pypy/trunk/src/pypy/annotation/builtin.py (contents, props changed) Modified: 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: Added support for built-in functions and methods. This involved some clean-up and the creation of a new class Bookkeeper where choices are remembered for the next reflow. One test now fails, because I broke the ability for the analysis to process calls to other Python functions. Added: pypy/trunk/src/pypy/annotation/builtin.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/annotation/builtin.py Fri May 7 18:22:25 2004 @@ -0,0 +1,30 @@ +""" +Built-in functions. +""" + +from pypy.annotation.model import SomeInteger, SomeObject +from pypy.annotation.factory import ListFactory, getbookkeeper + + +def builtin_len(s_obj): + return s_obj.len() + +def builtin_range(*args): + factory = getbookkeeper().getfactory(ListFactory) + factory.generalize(SomeInteger()) # XXX nonneg=... + return factory.create() + +def builtin_pow(s_base, s_exponent, *args): + if s_base.knowntype is s_exponent.knowntype is int: + return SomeInteger() + else: + return SomeObject() + + +# collect all functions +import __builtin__ +BUILTIN_FUNCTIONS = {} +for name, value in globals().items(): + if name.startswith('builtin_'): + original = getattr(__builtin__, name[8:]) + BUILTIN_FUNCTIONS[original] = value Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Fri May 7 18:22:25 2004 @@ -10,6 +10,7 @@ from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeImpossibleValue, SomeList from pypy.annotation.model import SomeObject, SomeInstance +from pypy.interpreter.miscutils import getthreadlocals class BlockedInference(Exception): @@ -19,6 +20,71 @@ def __init__(self, factories = ()): # factories that need to be invalidated self.invalidatefactories = factories + self.position_key = getattr(getbookkeeper(), 'position_key', None) + + +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): + self.creationpoints = {} # map positions-in-blocks to Factories + self.userclasses = {} # map classes to ClassDefs + + def enter(self, position_key): + """Start of an operation. + The operation is uniquely identified by the given key.""" + self.position_key = position_key + self.choice_id = 0 + getthreadlocals().bookkeeper = self + + def leave(self): + """End of an operation.""" + del getthreadlocals().bookkeeper + del self.position_key + del self.choice_id + + def nextchoice(self): + """Get the next choice key. The keys are unique, but they follow + the same sequence while reflowing.""" + # 'position_key' is an arbitrary key that identifies a specific + # operation, but calling nextchoice() several times during the same + # operation returns a different choice key. + key = self.position_key, self.choice_id + self.choice_id += 1 + return key + + def getfactory(self, factorycls, *factoryargs): + """Get the Factory associated with the current position, + or if it doesn't exist yet build it with factorycls(*factoryargs).""" + key = self.nextchoice() + try: + return self.creationpoints[key] + except KeyError: + factory = factorycls(*factoryargs) + factory.position_key = self.position_key + self.creationpoints[key] = factory + 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: + self.userclasses[cls] = ClassDef(cls, self) + return self.userclasses[cls] + + +def getbookkeeper(): + """Get the current Bookkeeper. + Only works during the analysis of an operation.""" + return getthreadlocals().bookkeeper # @@ -37,8 +103,8 @@ class InstanceFactory: - def __init__(self, cls, userclasses): - self.classdef = getclassdef(cls, userclasses) + def __init__(self, classdef): + self.classdef = classdef self.classdef.instancefactories[self] = True def create(self): @@ -48,7 +114,7 @@ class ClassDef: "Wraps a user class." - def __init__(self, cls, userclasses): + def __init__(self, cls, bookkeeper): self.attrs = {} # attrs is updated with new information self.revision = 0 # which increases the revision number self.instancefactories = {} @@ -59,7 +125,7 @@ base = cls.__bases__[0] else: base = object - self.basedef = getclassdef(base, userclasses) + self.basedef = bookkeeper.getclassdef(base) if self.basedef: self.basedef.subdefs[cls] = self @@ -106,13 +172,3 @@ # bump the revision number of this class and all subclasses subdef.revision += 1 self.attrs[attr] = s_value - - -def getclassdef(cls, cache): - if cls is object: - return None - try: - return cache[cls] - except KeyError: - cache[cls] = ClassDef(cls, cache) - return cache[cls] Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Fri May 7 18:22:25 2004 @@ -28,6 +28,7 @@ # +from types import ClassType, BuiltinFunctionType from pypy.annotation.pairtype import pair, extendabletype @@ -78,8 +79,13 @@ knowntype = tuple def __init__(self, items): self.items = tuple(items) # tuple of s_xxx elements - def len(self): - return immutablevalue(len(self.items)) + +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." @@ -88,6 +94,12 @@ self.knowntype = classdef.cls self.revision = classdef.revision +class SomeBuiltin(SomeObject): + "Stands for a built-in function or method with special-cased analysis." + knowntype = BuiltinFunctionType # == BuiltinMethodType + def __init__(self, analyser): + self.analyser = analyser + 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.""" @@ -103,6 +115,10 @@ result = SomeString() elif isinstance(x, tuple): result = SomeTuple(items = [immutablevalue(e) for e in x]) + elif x in BUILTIN_FUNCTIONS: + result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) + elif isinstance(x, (type, ClassType)) and x.__module__ != '__builtin__': + result = SomeClass(x) else: result = SomeObject() result.const = x @@ -121,6 +137,18 @@ else: return SomeObject() +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)] +## nbkwds = self.heap.get(ANN.len, varkwds_cell) +## if nbkwds != 0: +## return None # XXX deal with dictionaries with constant keys + return arglist + # ____________________________________________________________ # internal @@ -140,11 +168,12 @@ def missing_operation(cls, name): def default_op(*args): - print '* warning, no type available for %s(%s)' % ( - name, ', '.join([repr(a) for a in args])) + #print '* warning, no type available for %s(%s)' % ( + # name, ', '.join([repr(a) for a in args])) return SomeObject() setattr(cls, name, default_op) # this has the side-effect of registering the unary and binary operations -from pypy.annotation.unaryop import UNARY_OPERATIONS +from pypy.annotation.unaryop import UNARY_OPERATIONS from pypy.annotation.binaryop import BINARY_OPERATIONS +from pypy.annotation.builtin import BUILTIN_FUNCTIONS Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Fri May 7 18:22:25 2004 @@ -6,12 +6,14 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance +from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass +from pypy.annotation.model import immutablevalue, decode_simple_call from pypy.annotation.model import set, setunion, missing_operation from pypy.annotation.factory import BlockedInference +from pypy.annotation.factory import InstanceFactory, getbookkeeper -UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr']) +UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'call']) for opname in UNARY_OPERATIONS: missing_operation(SomeObject, opname) @@ -25,6 +27,26 @@ def is_true(obj): return SomeBool() + def getattr(obj, attr): + # get a SomeBuiltin if the object has a corresponding method + if attr.is_constant() and isinstance(attr.const, str): + attr = attr.const + if hasattr(obj, 'method_' + attr): + return SomeBuiltin(getattr(obj, 'method_' + attr)) + return SomeObject() + + +class __extend__(SomeTuple): + + def len(tup): + return immutablevalue(len(tup.items)) + + +class __extend__(SomeList): + + def method_append(lst, s_item): + pair(lst, SomeInteger()).setitem(s_item) + class __extend__(SomeInstance): @@ -64,3 +86,24 @@ clsdef.generalize(attr, s_value) raise BlockedInference(clsdef.getallfactories()) return SomeObject() + + +class __extend__(SomeBuiltin): + + def call(meth, args, kwds): + # decode the arguments and forward the analysis of this builtin + arglist = decode_simple_call(args, kwds) + if arglist is not None: + return meth.analyser(*arglist) + else: + return SomeObject() + + +class __extend__(SomeClass): + + def call(cls, args, kwds): + # XXX flow into __init__ + bookkeeper = getbookkeeper() + classdef = bookkeeper.getclassdef(cls.cls) + factory = bookkeeper.getfactory(InstanceFactory, classdef) + return factory.create() Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Fri May 7 18:22:25 2004 @@ -4,7 +4,7 @@ from pypy.annotation import model as annmodel from pypy.annotation.model import pair from pypy.annotation.factory import ListFactory, InstanceFactory -from pypy.annotation.factory import BlockedInference +from pypy.annotation.factory import BlockedInference, Bookkeeper from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation @@ -21,9 +21,8 @@ self.pendingblocks = [] # list of (block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen - self.creationpoints = {} # map positions-in-blocks to Factories + self.bookkeeper = Bookkeeper() self.translator = translator - self.userclasses = {} # set of user classes #___ convenience high-level interface __________________ @@ -58,11 +57,11 @@ def getuserclasses(self): """Return a set of known user classes.""" - return self.userclasses + return self.bookkeeper.userclasses def getuserattributes(self, cls): """Enumerate the attributes of the given user class, as Variable()s.""" - clsdef = self.userclasses[cls] + clsdef = self.bookkeeper.userclasses[cls] for attr, s_value in clsdef.attrs.items(): v = Variable(name=attr) self.bindings[v] = s_value @@ -159,12 +158,13 @@ self.flowin(block) except BlockedInference, e: #print '_'*60 - #print 'Blocked at %r:' % (self.curblockpos,) + #print 'Blocked at %r:' % (e.position_key,) #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily for factory in e.invalidatefactories: - self.reflowpendingblock(factory.block) + oldblock, oldindex = factory.position_key + self.reflowpendingblock(oldblock) def reflowpendingblock(self, block): self.pendingblocks.append((block, None)) @@ -189,27 +189,15 @@ def flowin(self, block): #print 'Flowing', block, [self.binding(a) for a in block.inputargs] for i in range(len(block.operations)): - self.curblockpos = block, i - self.consider_op(block.operations[i]) + try: + self.bookkeeper.enter((block, i)) + self.consider_op(block.operations[i]) + finally: + self.bookkeeper.leave() for link in block.exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(link.target, cells) - def getfactory(self, factorycls, *factoryargs): - try: - factory = self.creationpoints[self.curblockpos] - except KeyError: - block = self.curblockpos[0] - factory = factorycls(*factoryargs) - factory.block = block - self.creationpoints[self.curblockpos] = factory - # self.curblockpos is an arbitrary key that identifies a specific - # position, so that asking twice for a factory from the same position - # returns the same factory object. Because we can ask for several - # factories in the same operation, we change self.curblockpos here - self.curblockpos = self.curblockpos, 'bis' - return factory - #___ creating the annotations based on operations ______ @@ -250,50 +238,42 @@ return annmodel.SomeTuple(items = args) def consider_op_newlist(self, *args): - factory = self.getfactory(ListFactory) + factory = self.bookkeeper.getfactory(ListFactory) for a in args: factory.generalize(a) return factory.create() def decode_simple_call(self, s_varargs, s_varkwds): - s_nbargs = s_varargs.len() - if not s_nbargs.is_constant(): - return None - nbargs = s_nbargs.const - arg_cells = [pair(s_varargs, annmodel.immutablevalue(j)).getitem() - 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 + # 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 +## 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() +## # 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): 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 May 7 18:22:25 2004 @@ -182,6 +182,16 @@ annmodel.SomeObject() ])) + def test_poor_man_range(self): + translator = Translator(snippet.poor_man_range) + graph = translator.getflowgraph() + a = RPythonAnnotator(translator) + a.build_types(graph, [int]) + # result should be a list of integers + self.assertEquals(a.gettype(graph.getreturnvar()), list) + end_cell = a.binding(graph.getreturnvar()) + self.assertEquals(end_cell.s_item.knowntype, int) + def g(n): return [0,1,2,n] From arigo at codespeak.net Sat May 8 00:59:52 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 00:59:52 +0200 (MEST) Subject: [pypy-svn] r4322 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20040507225952.553715A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 00:59:51 2004 New Revision: 4322 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/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/translator.py Log: Python functions can call other Python functions. Now RPythonAnnotator is independant on the Translator class; the caching of flow graphs is done by the Bookkeeper. It also makes using RPythonAnnotator easier: the tests in translator/test/test_annrpython.py are simplified. Untestedly, it should also support finite unions of functions, i.e. code like fn = dispatcher_list[index] fn(args) Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat May 8 00:59:51 2004 @@ -6,7 +6,7 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance +from pypy.annotation.model import SomeInstance, SomeFunction from pypy.annotation.model import set, setunion, missing_operation from pypy.annotation.factory import BlockedInference @@ -26,6 +26,9 @@ def union((obj1, obj2)): return SomeObject() + def inplace_add((obj1, obj2)): + return pair(obj1, obj2).add() # default + class __extend__(pairtype(SomeInteger, SomeInteger)): @@ -128,6 +131,12 @@ return SomeInstance(basedef) +class __extend__(pairtype(SomeFunction, SomeFunction)): + + def union((fun1, fun2)): + return SomeFunction(setunion(fun1.funcs, fun2.funcs)) + + 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 May 8 00:59:51 2004 @@ -20,7 +20,10 @@ def __init__(self, factories = ()): # factories that need to be invalidated self.invalidatefactories = factories - self.position_key = getattr(getbookkeeper(), 'position_key', None) + try: + self.break_at = getbookkeeper().position_key + except AttributeError: + self.break_at = None class Bookkeeper: @@ -31,9 +34,11 @@ Currently used for factories and user-defined classes.""" - def __init__(self): + def __init__(self, annotator): + self.annotator = annotator self.creationpoints = {} # map positions-in-blocks to Factories self.userclasses = {} # map classes to ClassDefs + self.flowgraphs = {} # map functions to flow graphs def enter(self, position_key): """Start of an operation. @@ -80,6 +85,14 @@ self.userclasses[cls] = ClassDef(cls, self) return self.userclasses[cls] + def getflowgraph(self, func): + """Get the flow graph associated with the given Python func.""" + try: + return self.flowgraphs[func] + except KeyError: + self.flowgraphs[func] = self.annotator.buildflowgraph(func) + return self.flowgraphs[func] + def getbookkeeper(): """Get the current Bookkeeper. @@ -101,10 +114,20 @@ self.s_item = pair(self.s_item, s_new_item).union() +class FuncCallFactory: + + def pycall(self, func, arglist): + bookkeeper = getbookkeeper() + graph = bookkeeper.getflowgraph(func) + graph.funccallfactories[self] = True + bookkeeper.annotator.generalizeinputargs(graph, arglist) + return bookkeeper.annotator.getoutputvalue(graph) + + class InstanceFactory: - def __init__(self, classdef): - self.classdef = classdef + def __init__(self, cls): + self.classdef = getbookkeeper().getclassdef(cls) self.classdef.instancefactories[self] = True def create(self): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat May 8 00:59:51 2004 @@ -28,7 +28,7 @@ # -from types import ClassType, BuiltinFunctionType +from types import ClassType, BuiltinFunctionType, FunctionType from pypy.annotation.pairtype import pair, extendabletype @@ -100,6 +100,12 @@ def __init__(self, analyser): self.analyser = analyser +class SomeFunction(SomeObject): + "Stands for a Python function (or some function out of a list)." + knowntype = FunctionType + def __init__(self, funcs): + self.funcs = funcs # set of functions that this one may be + 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.""" @@ -119,6 +125,8 @@ result = SomeBuiltin(BUILTIN_FUNCTIONS[x]) elif isinstance(x, (type, ClassType)) and x.__module__ != '__builtin__': result = SomeClass(x) + elif isinstance(x, FunctionType): + result = SomeFunction({x: True}) 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 Sat May 8 00:59:51 2004 @@ -7,10 +7,11 @@ from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass +from pypy.annotation.model import SomeFunction from pypy.annotation.model import immutablevalue, decode_simple_call from pypy.annotation.model import set, setunion, missing_operation -from pypy.annotation.factory import BlockedInference -from pypy.annotation.factory import InstanceFactory, getbookkeeper +from pypy.annotation.factory import BlockedInference, getbookkeeper +from pypy.annotation.factory import InstanceFactory, FuncCallFactory UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'call']) @@ -52,7 +53,7 @@ def currentdef(ins): if ins.revision != ins.classdef.revision: - print ins.revision, ins.classdef.revision + #print ins.revision, ins.classdef.revision raise BlockedInference() return ins.classdef @@ -103,7 +104,18 @@ def call(cls, args, kwds): # XXX flow into __init__ - bookkeeper = getbookkeeper() - classdef = bookkeeper.getclassdef(cls.cls) - factory = bookkeeper.getfactory(InstanceFactory, classdef) + factory = getbookkeeper().getfactory(InstanceFactory, cls.cls) return factory.create() + + +class __extend__(SomeFunction): + + def call(fun, args, kwds): + arglist = decode_simple_call(args, kwds) + assert arglist is not None + factory = getbookkeeper().getfactory(FuncCallFactory) + s_result = SomeImpossibleValue() + for func in fun.funcs: + s_next_result = factory.pycall(func, arglist) + s_result = pair(s_result, s_next_result).union() + return s_result Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat May 8 00:59:51 2004 @@ -5,8 +5,9 @@ from pypy.annotation.model import pair from pypy.annotation.factory import ListFactory, InstanceFactory from pypy.annotation.factory import BlockedInference, Bookkeeper +from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant -from pypy.objspace.flow.model import SpaceOperation +from pypy.objspace.flow.model import SpaceOperation, FunctionGraph class AnnotatorError(Exception): @@ -17,28 +18,37 @@ """Block annotator for RPython. See description in doc/transation/annotation.txt.""" - def __init__(self, translator=None): + def __init__(self): self.pendingblocks = [] # list of (block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen - self.bookkeeper = Bookkeeper() - self.translator = translator + self.notify = {} # {block: {factory-to-invalidate-when-done}} + self.bookkeeper = Bookkeeper(self) #___ convenience high-level interface __________________ - def build_types(self, flowgraph, input_arg_types): + def build_types(self, func, input_arg_types): """Recursively build annotations about the specific entry point.""" + if not isinstance(func, FunctionGraph): + flowgraph = self.bookkeeper.getflowgraph(func) + else: + flowgraph = func # make input arguments and set their type input_arg_types = list(input_arg_types) nbarg = len(flowgraph.getargs()) while len(input_arg_types) < nbarg: input_arg_types.append(object) - inputcells = [annmodel.valueoftype(t) for t in input_arg_types] + inputcells = [] + for t in input_arg_types: + if not isinstance(t, annmodel.SomeObject): + t = annmodel.valueoftype(t) + inputcells.append(t) # register the entry point self.addpendingblock(flowgraph.startblock, inputcells) # recursively proceed until no more pending block is left self.complete() + return self.binding(flowgraph.getreturnvar()) def gettype(self, variable): """Return the known type of a control flow graph variable, @@ -99,6 +109,24 @@ raise TypeError, 'Variable or Constant expected, got %r' % (arg,) + #___ interface for annotator.factory _______ + + def buildflowgraph(self, func): + space = FlowObjSpace() + graph = space.build_flow(func) + self.notify[graph.returnblock] = graph.funccallfactories = {} + return graph + + def generalizeinputargs(self, flowgraph, inputcells): + block = flowgraph.startblock + assert len(inputcells) == len(block.inputargs) + self.addpendingblock(block, inputcells) + + def getoutputvalue(self, flowgraph): + v = flowgraph.getreturnvar() + return self.bindings.get(v, annmodel.SomeImpossibleValue()) + + #___ simplification (should be moved elsewhere?) _______ # it should be! @@ -158,7 +186,7 @@ self.flowin(block) except BlockedInference, e: #print '_'*60 - #print 'Blocked at %r:' % (e.position_key,) + #print 'Blocked at %r:' % (e.break_at,) #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily @@ -197,6 +225,13 @@ for link in block.exits: cells = [self.binding(a) for a in link.args] self.addpendingblock(link.target, cells) + if block in self.notify: + # invalidate some factories when this block is done + factories = self.notify[block].keys() + self.notify[block].clear() # don't del: the dict can be re-populated + for factory in factories: + oldblock, oldindex = factory.position_key + self.reflowpendingblock(oldblock) #___ creating the annotations based on operations ______ 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 May 8 00:59:51 2004 @@ -267,6 +267,12 @@ else: return n * factorial(n-1) +def factorial2(n): # analysed in a different order + if n > 1: + return n * factorial(n-1) + else: + return 1 + def append_five(lst): lst += [5] 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 May 8 00:59:51 2004 @@ -109,13 +109,11 @@ a.build_types(fun, [int]) self.assertEquals(a.gettype(fun.getreturnvar()), int) - #def test_simplify_calls(self): - # fun = self.make_fun(f_calls_g) - # a = RPythonAnnotator() - # a.build_types(fun, [int]) - # a.simplify_calls() - # #self.reallyshow(fun) - # XXX write test_transform.py + def test_f_calls_g(self): + a = RPythonAnnotator() + s = a.build_types(f_calls_g, [int]) + # result should be an integer + self.assertEquals(s.knowntype, int) def test_lists(self): fun = self.make_fun(snippet.poor_man_rev_range) @@ -127,70 +125,59 @@ self.assertEquals(end_cell.s_item.knowntype, int) def test_factorial(self): - translator = Translator(snippet.factorial) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, [int]) + a = RPythonAnnotator() + s = a.build_types(snippet.factorial, [int]) # result should be an integer - self.assertEquals(a.gettype(graph.getreturnvar()), int) + self.assertEquals(s.knowntype, int) + + def test_factorial2(self): + a = RPythonAnnotator() + s = a.build_types(snippet.factorial2, [int]) + # result should be an integer + self.assertEquals(s.knowntype, int) def test_build_instance(self): - translator = Translator(snippet.build_instance) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, []) + a = RPythonAnnotator() + s = a.build_types(snippet.build_instance, []) # result should be a snippet.C instance - self.assertEquals(a.gettype(graph.getreturnvar()), snippet.C) + self.assertEquals(s.knowntype, snippet.C) def test_set_attr(self): - translator = Translator(snippet.set_attr) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, []) + a = RPythonAnnotator() + s = a.build_types(snippet.set_attr, []) # result should be an integer - self.assertEquals(a.gettype(graph.getreturnvar()), int) + self.assertEquals(s.knowntype, int) def test_merge_setattr(self): - translator = Translator(snippet.merge_setattr) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, [int]) + a = RPythonAnnotator() + s = a.build_types(snippet.merge_setattr, [int]) # result should be an integer - self.assertEquals(a.gettype(graph.getreturnvar()), int) + self.assertEquals(s.knowntype, int) def test_inheritance1(self): - translator = Translator(snippet.inheritance1) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, []) + a = RPythonAnnotator() + s = a.build_types(snippet.inheritance1, []) # result should be exactly: - self.assertEquals(a.binding(graph.getreturnvar()), - annmodel.SomeTuple([ - annmodel.SomeTuple([]), - annmodel.SomeInteger() - ])) + self.assertEquals(s, annmodel.SomeTuple([ + annmodel.SomeTuple([]), + annmodel.SomeInteger() + ])) def test_inheritance2(self): - translator = Translator(snippet.inheritance2) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, []) + a = RPythonAnnotator() + s = a.build_types(snippet.inheritance2, []) # result should be exactly: - self.assertEquals(a.binding(graph.getreturnvar()), - annmodel.SomeTuple([ - annmodel.SomeInteger(), - annmodel.SomeObject() - ])) + self.assertEquals(s, annmodel.SomeTuple([ + annmodel.SomeInteger(), + annmodel.SomeObject() + ])) def test_poor_man_range(self): - translator = Translator(snippet.poor_man_range) - graph = translator.getflowgraph() - a = RPythonAnnotator(translator) - a.build_types(graph, [int]) + a = RPythonAnnotator() + s = a.build_types(snippet.poor_man_range, [int]) # result should be a list of integers - self.assertEquals(a.gettype(graph.getreturnvar()), list) - end_cell = a.binding(graph.getreturnvar()) - self.assertEquals(end_cell.s_item.knowntype, int) + self.assertEquals(s.knowntype, list) + self.assertEquals(s.s_item.knowntype, int) def g(n): @@ -198,8 +185,11 @@ def f_calls_g(n): total = 0 - for i in g(n): + lst = g(n) + i = 0 + while i < len(lst): total += i + i += 1 return total Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sat May 8 00:59:51 2004 @@ -104,7 +104,7 @@ """ func = func or self.entrypoint if self.annotator is None: - self.annotator = RPythonAnnotator(self) + self.annotator = RPythonAnnotator() graph = self.getflowgraph(func) self.annotator.build_types(graph, input_args_types) return self.annotator @@ -141,7 +141,7 @@ if input_arg_types is None: ann = self.annotator else: - ann = RPythonAnnotator(self) + ann = RPythonAnnotator() if func is None: codes = [self.generatecode1(gencls, input_arg_types, self.entrypoint, ann)] @@ -192,16 +192,16 @@ from dis import dis dis(func or self.entrypoint) - def consider_call(self, ann, func, args): - graph = self.getflowgraph(func) - ann.addpendingblock(graph.startblock, args) - result_var = graph.getreturnvar() - try: - return ann.binding(result_var) - except KeyError: - # typical case for the 1st call, because addpendingblock() did - # not actually start the analysis of the called function yet. - return impossiblevalue +## def consider_call(self, ann, func, args): +## graph = self.getflowgraph(func) +## ann.addpendingblock(graph.startblock, args) +## result_var = graph.getreturnvar() +## try: +## return ann.binding(result_var) +## except KeyError: +## # typical case for the 1st call, because addpendingblock() did +## # not actually start the analysis of the called function yet. +## return impossiblevalue if __name__ == '__main__': From arigo at codespeak.net Sat May 8 13:24:36 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 13:24:36 +0200 (MEST) Subject: [pypy-svn] r4324 - in pypy/trunk/src/pypy: annotation annotation/test translator Message-ID: <20040508112436.BE9A55A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 13:24:36 2004 New Revision: 4324 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/test/test_model.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py Log: Added a generally useful function unionof(*somevalues). Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat May 8 13:24:36 2004 @@ -7,7 +7,7 @@ from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction -from pypy.annotation.model import set, setunion, missing_operation +from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference @@ -70,7 +70,7 @@ def union((lst1, lst2)): return SomeList(setunion(lst1.factories, lst2.factories), - s_item = pair(lst1.s_item, lst2.s_item).union()) + s_item = unionof(lst1.s_item, lst2.s_item)) add = union @@ -84,7 +84,7 @@ if len(tup1.items) != len(tup2.items): return SomeObject() else: - unions = [pair(x,y).union() for x,y in zip(tup1.items, tup2.items)] + unions = [unionof(x,y) for x,y in zip(tup1.items, tup2.items)] return SomeTuple(items = unions) def add((tup1, tup2)): @@ -97,10 +97,7 @@ if int2.is_constant(): return tup1.items[int2.const] else: - result = SomeImpossibleValue() - for a in tup1.items: - result = pair(result, a).union() - return result + return unionof(*tup1.items) class __extend__(pairtype(SomeList, SomeInteger)): Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat May 8 13:24:36 2004 @@ -10,6 +10,7 @@ from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeImpossibleValue, SomeList from pypy.annotation.model import SomeObject, SomeInstance +from pypy.annotation.model import unionof from pypy.interpreter.miscutils import getthreadlocals @@ -111,7 +112,7 @@ return SomeList(factories = {self: True}, s_item = self.s_item) def generalize(self, s_new_item): - self.s_item = pair(self.s_item, s_new_item).union() + self.s_item = unionof(self.s_item, s_new_item) class FuncCallFactory: @@ -188,10 +189,11 @@ for clsdef in self.getmro(): assert clsdef is self or attr not in clsdef.attrs # (2) remove the attribute from subclasses + subclass_values = [] for subdef in self.getallsubdefs(): if attr in subdef.attrs: - s_value = pair(s_value, subdef.attrs[attr]).union() + subclass_values.append(subdef.attrs[attr]) del subdef.attrs[attr] # bump the revision number of this class and all subclasses subdef.revision += 1 - self.attrs[attr] = s_value + self.attrs[attr] = unionof(s_value, *subclass_values) Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat May 8 13:24:36 2004 @@ -111,6 +111,14 @@ will never show up at run-time, e.g. elements of an empty list.""" +def unionof(*somevalues): + "The most precise SomeValue instance that contains all the values." + s1 = SomeImpossibleValue() + for s2 in somevalues: + if s1 != s2: + s1 = pair(s1, s2).union() + return s1 + def immutablevalue(x): "The most precise SomeValue instance that contains the immutable value x." if isinstance(bool, type) and isinstance(x, bool): 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 May 8 13:24:36 2004 @@ -30,7 +30,7 @@ (s6,s6)]) def test_union(): - assert ([pair(s,t).union() for s in slist for t in slist] == + assert ([unionof(s,t) for s in slist for t in slist] == [s1, s1, s1, s1, s1, s1, s1, s2, s3, s1, s1, s2, s1, s3, s3, s1, s1, s3, Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Sat May 8 13:24:36 2004 @@ -9,7 +9,7 @@ from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass from pypy.annotation.model import SomeFunction from pypy.annotation.model import immutablevalue, decode_simple_call -from pypy.annotation.model import set, setunion, missing_operation +from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper from pypy.annotation.factory import InstanceFactory, FuncCallFactory @@ -28,10 +28,11 @@ def is_true(obj): return SomeBool() - def getattr(obj, attr): - # get a SomeBuiltin if the object has a corresponding method - if attr.is_constant() and isinstance(attr.const, str): - attr = attr.const + 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 if hasattr(obj, 'method_' + attr): return SomeBuiltin(getattr(obj, 'method_' + attr)) return SomeObject() @@ -57,9 +58,9 @@ raise BlockedInference() return ins.classdef - def getattr(ins, attr): - if attr.is_constant() and isinstance(attr.const, str): - attr = attr.const + def getattr(ins, s_attr): + if s_attr.is_constant() and isinstance(s_attr.const, str): + attr = s_attr.const # look for the attribute in the MRO order for clsdef in ins.currentdef().getmro(): if attr in clsdef.attrs: @@ -70,9 +71,9 @@ raise BlockedInference(clsdef.getallfactories()) return SomeObject() - def setattr(ins, attr, s_value): - if attr.is_constant() and isinstance(attr.const, str): - attr = attr.const + 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 @@ -114,8 +115,5 @@ arglist = decode_simple_call(args, kwds) assert arglist is not None factory = getbookkeeper().getfactory(FuncCallFactory) - s_result = SomeImpossibleValue() - for func in fun.funcs: - s_next_result = factory.pycall(func, arglist) - s_result = pair(s_result, s_next_result).union() - return s_result + results = [factory.pycall(func, arglist) for func in fun.funcs] + return unionof(*results) Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat May 8 13:24:36 2004 @@ -209,7 +209,7 @@ # Merge the new 'cells' with each of the block's existing input # variables. oldcells = [self.binding(a) for a in block.inputargs] - unions = [pair(c1,c2).union() for c1, c2 in zip(oldcells, inputcells)] + 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) From arigo at codespeak.net Sat May 8 14:12:06 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 14:12:06 +0200 (MEST) Subject: [pypy-svn] r4325 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20040508121206.0731C5A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 14:12:06 2004 New Revision: 4325 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/annrpython.py Log: More small changes. No longer use the BlockedInference exception for both stopping the inference and invalidating other blocks; there is now a dedicated interface to invalidate other blocks. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat May 8 14:12:06 2004 @@ -8,7 +8,7 @@ from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction from pypy.annotation.model import unionof, set, setunion, missing_operation -from pypy.annotation.factory import BlockedInference +from pypy.annotation.factory import BlockedInference, getbookkeeper # XXX unify this with ObjSpace.MethodTable @@ -110,9 +110,9 @@ def setitem((lst1, int2), s_value): if not lst1.s_item.contains(s_value): + bookkeeper = getbookkeeper() for factory in lst1.factories: - factory.generalize(s_value) - raise BlockedInference(lst1.factories) + factory.generalize(s_value, bookkeeper) class __extend__(pairtype(SomeInteger, SomeList)): Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat May 8 14:12:06 2004 @@ -18,9 +18,7 @@ """This exception signals the type inference engine that the situation is currently blocked, and that it should try to progress elsewhere.""" - def __init__(self, factories = ()): - # factories that need to be invalidated - self.invalidatefactories = factories + def __init__(self): try: self.break_at = getbookkeeper().position_key except AttributeError: @@ -111,8 +109,10 @@ def create(self): return SomeList(factories = {self: True}, s_item = self.s_item) - def generalize(self, s_new_item): + def generalize(self, s_new_item, bookkeeper=None): self.s_item = unionof(self.s_item, s_new_item) + if bookkeeper: + bookkeeper.annotator.reflowfromposition(self.position_key) class FuncCallFactory: @@ -182,7 +182,7 @@ factories.update(clsdef.instancefactories) return factories - def generalize(self, attr, s_value): + def generalize(self, attr, s_value, bookkeeper=None): # we make sure that an attribute never appears both in a class # and in some subclass, in two steps: # (1) assert that the attribute is in no superclass @@ -197,3 +197,7 @@ # bump the revision number of this class and all subclasses subdef.revision += 1 self.attrs[attr] = unionof(s_value, *subclass_values) + # reflow from all factories + if bookkeeper: + for factory in self.getallfactories(): + bookkeeper.annotator.reflowfromposition(factory.position_key) Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Sat May 8 14:12:06 2004 @@ -55,7 +55,7 @@ def currentdef(ins): if ins.revision != ins.classdef.revision: #print ins.revision, ins.classdef.revision - raise BlockedInference() + raise BlockedInference return ins.classdef def getattr(ins, s_attr): @@ -67,8 +67,8 @@ return clsdef.attrs[attr] # maybe the attribute exists in some subclass? if so, lift it clsdef = ins.classdef - clsdef.generalize(attr, SomeImpossibleValue()) - raise BlockedInference(clsdef.getallfactories()) + clsdef.generalize(attr, SomeImpossibleValue(), getbookkeeper()) + raise BlockedInference return SomeObject() def setattr(ins, s_attr, s_value): @@ -85,8 +85,8 @@ # 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) - raise BlockedInference(clsdef.getallfactories()) + clsdef.generalize(attr, s_value, getbookkeeper()) + raise BlockedInference return SomeObject() Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sat May 8 14:12:06 2004 @@ -114,7 +114,13 @@ def buildflowgraph(self, func): space = FlowObjSpace() graph = space.build_flow(func) - self.notify[graph.returnblock] = graph.funccallfactories = {} + # the dictionary of all FuncCallFactories (call points to this func) + # is populated via graph.funccallfactories in pypy.annotation.factory + # and read via self.notify[graph.returnblock] whenever the return block + # of this graph has been analysed. + callfactories = {} + graph.funccallfactories = callfactories + self.notify[graph.returnblock] = callfactories return graph def generalizeinputargs(self, flowgraph, inputcells): @@ -126,6 +132,10 @@ v = flowgraph.getreturnvar() return self.bindings.get(v, annmodel.SomeImpossibleValue()) + def reflowfromposition(self, position_key): + block, index = position_key + self.reflowpendingblock(block) + #___ simplification (should be moved elsewhere?) _______ @@ -190,9 +200,6 @@ #import traceback, sys #traceback.print_tb(sys.exc_info()[2]) self.annotated[block] = False # failed, hopefully temporarily - for factory in e.invalidatefactories: - oldblock, oldindex = factory.position_key - self.reflowpendingblock(oldblock) def reflowpendingblock(self, block): self.pendingblocks.append((block, None)) @@ -227,11 +234,8 @@ self.addpendingblock(link.target, cells) if block in self.notify: # invalidate some factories when this block is done - factories = self.notify[block].keys() - self.notify[block].clear() # don't del: the dict can be re-populated - for factory in factories: - oldblock, oldindex = factory.position_key - self.reflowpendingblock(oldblock) + for factory in self.notify[block]: + self.reflowfromposition(factory.position_key) #___ creating the annotations based on operations ______ From arigo at codespeak.net Sat May 8 14:55:55 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 14:55:55 +0200 (MEST) Subject: [pypy-svn] r4326 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20040508125555.2D0875A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 14:55:54 2004 New Revision: 4326 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/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Method calls seem to work reasonably well. There is no corresponding support in the code generators, though. This will probably require some more work to be able to tell the difference between instance and class attributes. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat May 8 14:55:54 2004 @@ -6,7 +6,7 @@ from pypy.annotation.model import SomeObject, SomeInteger, SomeBool from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue -from pypy.annotation.model import SomeInstance, SomeFunction +from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -134,6 +134,19 @@ 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: unionof(met1[func], met2[func])} + d = met1.meths.copy() + for func, s_self in met2.meths.items(): + if func in d: + s_self = unionof(d[func], s_self) + d[func] = s_self + return SomeMethod(d) + + 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 May 8 14:55:54 2004 @@ -7,10 +7,11 @@ """ from __future__ import generators +from types import FunctionType from pypy.annotation.pairtype import pair from pypy.annotation.model import SomeImpossibleValue, SomeList from pypy.annotation.model import SomeObject, SomeInstance -from pypy.annotation.model import unionof +from pypy.annotation.model import unionof, immutablevalue from pypy.interpreter.miscutils import getthreadlocals @@ -152,6 +153,17 @@ self.basedef = bookkeeper.getclassdef(base) 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): + continue + # 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) + self.generalize(name, s_value, bookkeeper) def __repr__(self): return '' % (self.cls.__module__, self.cls.__name__) @@ -185,9 +197,11 @@ def generalize(self, attr, s_value, bookkeeper=None): # we make sure that an attribute never appears both in a class # and in some subclass, in two steps: - # (1) assert that the attribute is in no superclass + # (1) check if the attribute is already in a superclass for clsdef in self.getmro(): - assert clsdef is self or attr not in clsdef.attrs + if attr in clsdef.attrs: + self = clsdef # generalize the parent class instead + break # (2) remove the attribute from subclasses subclass_values = [] for subdef in self.getallsubdefs(): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat May 8 14:55:54 2004 @@ -28,7 +28,7 @@ # -from types import ClassType, BuiltinFunctionType, FunctionType +from types import ClassType, BuiltinFunctionType, FunctionType, MethodType from pypy.annotation.pairtype import pair, extendabletype @@ -106,6 +106,12 @@ def __init__(self, funcs): self.funcs = funcs # set of functions that this one may be +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: s_self} + 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 Sat May 8 14:55:54 2004 @@ -7,7 +7,7 @@ from pypy.annotation.model import SomeString, SomeList from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass -from pypy.annotation.model import SomeFunction +from pypy.annotation.model import SomeFunction, SomeMethod from pypy.annotation.model import immutablevalue, decode_simple_call from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -37,6 +37,9 @@ return SomeBuiltin(getattr(obj, 'method_' + attr)) return SomeObject() + def get(obj, s_self): + return obj # default __get__ implementation + class __extend__(SomeTuple): @@ -61,10 +64,14 @@ def getattr(ins, s_attr): 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] + # 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].get(ins) # maybe the attribute exists in some subclass? if so, lift it clsdef = ins.classdef clsdef.generalize(attr, SomeImpossibleValue(), getbookkeeper()) @@ -117,3 +124,21 @@ factory = getbookkeeper().getfactory(FuncCallFactory) results = [factory.pycall(func, arglist) for func in fun.funcs] return unionof(*results) + + def get(fun, s_self): # function -> bound method + d = {} + for func in fun.funcs: + d[func] = s_self + return SomeMethod(d) + + +class __extend__(SomeMethod): + + def call(met, args, kwds): + arglist = decode_simple_call(args, kwds) + #print 'methodcall:', met, arglist + assert arglist is not None + factory = getbookkeeper().getfactory(FuncCallFactory) + results = [factory.pycall(func, [s_self] + arglist) + for func, s_self in met.meths.items()] + return unionof(*results) 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 May 8 14:55:54 2004 @@ -320,3 +320,21 @@ e = E() e.stuff = (3, "world") return C().stuff + +class F: + pass +class G(F): + def m(self, x): + return self.m2(x) + def m2(self, x): + return D(), x +class H(F): + def m(self, y): + return E(), y + +def methodcall1(cond): + if cond: + x = G() + else: + x = H() + return x.m(42) 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 May 8 14:55:54 2004 @@ -179,6 +179,16 @@ self.assertEquals(s.knowntype, list) self.assertEquals(s.s_item.knowntype, int) + def test_methodcall1(self): + a = RPythonAnnotator() + s = a.build_types(snippet.methodcall1, [int]) + # result should be a tuple of (C, positive_int) + self.assertEquals(s.knowntype, tuple) + self.assertEquals(len(s.items), 2) + self.assertEquals(s.items[0].knowntype, snippet.C) + self.assertEquals(s.items[1].knowntype, int) + self.assertEquals(s.items[1].nonneg, True) + def g(n): return [0,1,2,n] From arigo at codespeak.net Sat May 8 19:01:56 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 19:01:56 +0200 (MEST) Subject: [pypy-svn] r4329 - pypy/trunk/src/pypy/annotation Message-ID: <20040508170156.74FC55A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 19:01:55 2004 New Revision: 4329 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 Log: Fixed SomeMethod to record the class of their 'self' argument instead of a specific s_self = SomeInstance(). This allows SomeMethods to be created in advance when the classdef is created. SomeMethod unions can then retain all the necessary precision. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Sat May 8 19:01:55 2004 @@ -138,12 +138,14 @@ def union((met1, met2)): # the union of the two meths dictionaries is a dictionary - # {func: unionof(met1[func], met2[func])} + # {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, s_self in met2.meths.items(): + for func, classdef in met2.meths.items(): if func in d: - s_self = unionof(d[func], s_self) - d[func] = s_self + classdef = classdef.commonbase(d[func]) + d[func] = classdef return SomeMethod(d) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sat May 8 19:01:55 2004 @@ -163,6 +163,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) self.generalize(name, s_value, bookkeeper) def __repr__(self): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Sat May 8 19:01:55 2004 @@ -110,7 +110,7 @@ "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: s_self} + self.meths = meths # map {python_function: classdef} class SomeImpossibleValue(SomeObject): """The empty set. Instances are placeholders for objects that Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Sat May 8 19:01:55 2004 @@ -37,8 +37,8 @@ return SomeBuiltin(getattr(obj, 'method_' + attr)) return SomeObject() - def get(obj, s_self): - return obj # default __get__ implementation + def classattribute(obj, classdef): + return obj # default unbound __get__ implementation class __extend__(SomeTuple): @@ -71,7 +71,7 @@ # 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].get(ins) + return clsdef.attrs[attr] # maybe the attribute exists in some subclass? if so, lift it clsdef = ins.classdef clsdef.generalize(attr, SomeImpossibleValue(), getbookkeeper()) @@ -125,10 +125,10 @@ results = [factory.pycall(func, arglist) for func in fun.funcs] return unionof(*results) - def get(fun, s_self): # function -> bound method + def classattribute(fun, classdef): # function -> unbound method d = {} for func in fun.funcs: - d[func] = s_self + d[func] = classdef return SomeMethod(d) @@ -139,6 +139,6 @@ #print 'methodcall:', met, arglist assert arglist is not None factory = getbookkeeper().getfactory(FuncCallFactory) - results = [factory.pycall(func, [s_self] + arglist) - for func, s_self in met.meths.items()] + results = [factory.pycall(func, [SomeInstance(classdef)]+arglist) + for func, classdef in met.meths.items()] return unionof(*results) From arigo at codespeak.net Sat May 8 19:23:09 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 19:23:09 +0200 (MEST) Subject: [pypy-svn] r4330 - in pypy/trunk/src/pypy: annotation translator/test Message-ID: <20040508172309.BB1045A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 19:23:09 2004 New Revision: 4330 Modified: pypy/trunk/src/pypy/annotation/unaryop.py pypy/trunk/src/pypy/translator/test/snippet.py Log: Bug found by Samuele, with a test and a fix. Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Sat May 8 19:23:09 2004 @@ -139,6 +139,11 @@ #print 'methodcall:', met, arglist assert arglist is not None factory = getbookkeeper().getfactory(FuncCallFactory) - results = [factory.pycall(func, [SomeInstance(classdef)]+arglist) - for func, classdef in met.meths.items()] + 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]+arglist)) return unionof(*results) 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 May 8 19:23:09 2004 @@ -330,6 +330,7 @@ return D(), x class H(F): def m(self, y): + self.attr = 1 return E(), y def methodcall1(cond): From arigo at codespeak.net Sat May 8 19:28:42 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 19:28:42 +0200 (MEST) Subject: [pypy-svn] r4331 - pypy/trunk/src/pypy/translator/test Message-ID: <20040508172842.D4A335A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 19:28:42 2004 New Revision: 4331 Modified: pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: More precise test, to ensure that the correct classes get the correct attributes. 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 May 8 19:28:42 2004 @@ -189,6 +189,15 @@ self.assertEquals(s.items[1].knowntype, int) self.assertEquals(s.items[1].nonneg, True) + def test_classes_methodcall1(self): + a = RPythonAnnotator() + a.build_types(snippet.methodcall1, [int]) + # the user classes should have the following attributes: + 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)}) def g(n): return [0,1,2,n] From arigo at codespeak.net Sat May 8 22:03:15 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 8 May 2004 22:03:15 +0200 (MEST) Subject: [pypy-svn] r4340 - in pypy/trunk/src: . Pyrex Pyrex/Compiler pypy/toolpypy/translator/tool Message-ID: <20040508200315.D13665A27C@thoth.codespeak.net> Author: arigo Date: Sat May 8 22:03:14 2004 New Revision: 4340 Added: pypy/trunk/src/Pyrex/ - copied from r4339, vendor/Pyrex/current/Pyrex/ pypy/trunk/src/pypy/tool/pyrexc - copied, changed from r4339, vendor/Pyrex/current/bin/pyrexc Modified: pypy/trunk/src/ (props changed) pypy/trunk/src/Pyrex/Compiler/Nodes.py pypy/trunk/src/Pyrex/Compiler/Parsing.py pypy/trunk/src/Pyrex/Compiler/Scanning.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py Log: Switched to Pyrex 0.9.2.1. Pyrex is now tracked in http://codespeak.net/svn/vendor/Pyrex/. It is copied from there and modified as needed for PyPy. The original files are: A Pyrex http://codespeak.net/svn/vendor/Pyrex/Pyrex-0.9.2.1/Pyrex/ A pypy/tool/pyrexc http://codespeak.net/svn/vendor/Pyrex/Pyrex-0.9.2.1/bin/pyrexc The external links to Pyrex and Plex have been removed. Note that Plex is a subdirectory of Pyrex in this new version. I guess you will have to delete your Plex directory manually; removing the svn:externals isn't enough for svn up to delete it for you. Modified: pypy/trunk/src/Pyrex/Compiler/Nodes.py ============================================================================== --- vendor/Pyrex/current/Pyrex/Compiler/Nodes.py (original) +++ pypy/trunk/src/Pyrex/Compiler/Nodes.py Sat May 8 22:03:14 2004 @@ -1289,6 +1289,20 @@ self.__class__.__name__) +class InlineStatNode(StatNode): + + def analyse_declarations(self, env): + pass + + def analyse_expressions(self, env): + pass + + def generate_execution_code(self, code): + code.putln(str(self.string.value)) + #raise InternalError("generate_code not implemented for %s" % \ + # self.__class__.__name__) + + class CDefExternNode(StatNode): # include_file string or None # body StatNode Modified: pypy/trunk/src/Pyrex/Compiler/Parsing.py ============================================================================== --- vendor/Pyrex/current/Pyrex/Compiler/Parsing.py (original) +++ pypy/trunk/src/Pyrex/Compiler/Parsing.py Sat May 8 22:03:14 2004 @@ -798,6 +798,14 @@ stats.append(stat) return Nodes.StatListNode(pos, stats = stats) +def p_cinline_statement(s): + # s.sy == 'cinline' + pos = s.position() + kind = s.sy + s.next() + string = p_simple_expr(s) + return Nodes.InlineStatNode(pos, string=string) + def p_from_import_statement(s): # s.sy == 'from' pos = s.position() @@ -1067,6 +1075,8 @@ node = p_raise_statement(s) elif s.sy in ('import', 'cimport'): node = p_import_statement(s) + elif s.sy == 'cinline': + node = p_cinline_statement(s) elif s.sy == 'from': node = p_from_import_statement(s) elif s.sy == 'assert': Modified: pypy/trunk/src/Pyrex/Compiler/Scanning.py ============================================================================== --- vendor/Pyrex/current/Pyrex/Compiler/Scanning.py (original) +++ pypy/trunk/src/Pyrex/Compiler/Scanning.py Sat May 8 22:03:14 2004 @@ -139,7 +139,7 @@ "raise", "import", "exec", "try", "except", "finally", "while", "if", "elif", "else", "for", "in", "assert", "and", "or", "not", "is", "in", "lambda", "from", - "NULL", "cimport" + "NULL", "cimport", "cinline" ] class Method: Copied: pypy/trunk/src/pypy/tool/pyrexc (from r4339, vendor/Pyrex/current/bin/pyrexc) ============================================================================== --- vendor/Pyrex/current/bin/pyrexc (original) +++ pypy/trunk/src/pypy/tool/pyrexc Sat May 8 22:03:14 2004 @@ -4,5 +4,6 @@ # Pyrex -- Main Program, Unix # +import autopath from Pyrex.Compiler.Main import main main(command_line = 1) 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 Sat May 8 22:03:14 2004 @@ -78,9 +78,10 @@ try: options = CompilationOptions(show_version = 0, use_listing_file = 0, + c_only = 1, output_file = None) context = Context(options.include_path) - result = context.compile(str(pyxfile), options, c_only = 1) + result = context.compile(str(pyxfile), options) if result.num_errors > 0: raise ValueError, "failure %s" % result except PyrexError, e: From arigo at codespeak.net Sun May 9 19:42:25 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sun, 9 May 2004 19:42:25 +0200 (MEST) Subject: [pypy-svn] r4346 - in pypy/trunk/src/pypy: annotation translator Message-ID: <20040509174225.4F18E5A971@thoth.codespeak.net> Author: arigo Date: Sun May 9 19:42:24 2004 New Revision: 4346 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/translator.py Log: Found out that we can cleanly use Translator.flowgraphs to record the flow graphs of the annotated functions, instead of having this dict duplicated into Bookkeeper. This makes the whole annotator/ subdirectory unaware of flow graphs and only dependent on two methods in translator/annrpython, which in turn relies on translator/translator to build and collect flow graphs. Now the Translator.pyrex() method will again generate code for several functions if they call each other. (with name conflicts, however; all methods 'm' of various classes are generated as plain functions called 'm'.) Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Sun May 9 19:42:24 2004 @@ -38,7 +38,6 @@ self.annotator = annotator self.creationpoints = {} # map positions-in-blocks to Factories self.userclasses = {} # map classes to ClassDefs - self.flowgraphs = {} # map functions to flow graphs def enter(self, position_key): """Start of an operation. @@ -85,14 +84,6 @@ self.userclasses[cls] = ClassDef(cls, self) return self.userclasses[cls] - def getflowgraph(self, func): - """Get the flow graph associated with the given Python func.""" - try: - return self.flowgraphs[func] - except KeyError: - self.flowgraphs[func] = self.annotator.buildflowgraph(func) - return self.flowgraphs[func] - def getbookkeeper(): """Get the current Bookkeeper. @@ -119,11 +110,7 @@ class FuncCallFactory: def pycall(self, func, arglist): - bookkeeper = getbookkeeper() - graph = bookkeeper.getflowgraph(func) - graph.funccallfactories[self] = True - bookkeeper.annotator.generalizeinputargs(graph, arglist) - return bookkeeper.annotator.getoutputvalue(graph) + return getbookkeeper().annotator.recursivecall(func, arglist, self) class InstanceFactory: Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Sun May 9 19:42:24 2004 @@ -5,7 +5,6 @@ from pypy.annotation.model import pair from pypy.annotation.factory import ListFactory, InstanceFactory from pypy.annotation.factory import BlockedInference, Bookkeeper -from pypy.objspace.flow import FlowObjSpace from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation, FunctionGraph @@ -18,7 +17,8 @@ """Block annotator for RPython. See description in doc/transation/annotation.txt.""" - def __init__(self): + def __init__(self, translator=None): + self.translator = translator self.pendingblocks = [] # list of (block, list-of-SomeValues-args) self.bindings = {} # map Variables to SomeValues self.annotated = {} # set of blocks already seen @@ -27,12 +27,15 @@ #___ convenience high-level interface __________________ - def build_types(self, func, input_arg_types): + def build_types(self, func_or_flowgraph, input_arg_types): """Recursively build annotations about the specific entry point.""" - if not isinstance(func, FunctionGraph): - flowgraph = self.bookkeeper.getflowgraph(func) + if isinstance(func_or_flowgraph, FunctionGraph): + flowgraph = func_or_flowgraph else: - flowgraph = func + if self.translator is None: + from pypy.translator.translator import Translator + self.translator = Translator(func_or_flowgraph) + flowgraph = self.translator.getflowgraph(func_or_flowgraph) # make input arguments and set their type input_arg_types = list(input_arg_types) nbarg = len(flowgraph.getargs()) @@ -111,25 +114,19 @@ #___ interface for annotator.factory _______ - def buildflowgraph(self, func): - space = FlowObjSpace() - graph = space.build_flow(func) - # the dictionary of all FuncCallFactories (call points to this func) - # is populated via graph.funccallfactories in pypy.annotation.factory - # and read via self.notify[graph.returnblock] whenever the return block - # of this graph has been analysed. - callfactories = {} - graph.funccallfactories = callfactories - self.notify[graph.returnblock] = callfactories - return graph - - def generalizeinputargs(self, flowgraph, inputcells): - block = flowgraph.startblock + def recursivecall(self, func, inputcells, factory): + graph = self.translator.getflowgraph(func) + # 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 + # generalize the function's input arguments + block = graph.startblock assert len(inputcells) == len(block.inputargs) self.addpendingblock(block, inputcells) - - def getoutputvalue(self, flowgraph): - v = flowgraph.getreturnvar() + # get the (current) return value + v = graph.getreturnvar() return self.bindings.get(v, annmodel.SomeImpossibleValue()) def reflowfromposition(self, position_key): Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Sun May 9 19:42:24 2004 @@ -41,8 +41,6 @@ class Translator: - # XXX this class should handle recursive analysis of functions called - # by the entry point function. def __init__(self, func): self.entrypoint = func @@ -104,7 +102,7 @@ """ func = func or self.entrypoint if self.annotator is None: - self.annotator = RPythonAnnotator() + self.annotator = RPythonAnnotator(self) graph = self.getflowgraph(func) self.annotator.build_types(graph, input_args_types) return self.annotator @@ -141,7 +139,7 @@ if input_arg_types is None: ann = self.annotator else: - ann = RPythonAnnotator() + ann = RPythonAnnotator(self) if func is None: codes = [self.generatecode1(gencls, input_arg_types, self.entrypoint, ann)] From arigo at codespeak.net Tue May 11 16:50:08 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 11 May 2004 16:50:08 +0200 (MEST) Subject: [pypy-svn] r4370 - pypy/trunk/src/pypy/translator Message-ID: <20040511145008.6DC2E5A971@thoth.codespeak.net> Author: arigo Date: Tue May 11 16:50:07 2004 New Revision: 4370 Modified: pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/transform.py Log: A new transformation (dead operation elimination). Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue May 11 16:50:07 2004 @@ -164,7 +164,7 @@ def simplify(self): # Generic simpliciations from pypy.translator import transform - transform.transform_simple_call(self) + transform.transform_graph(self) #___ 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 Tue May 11 16:50:07 2004 @@ -96,8 +96,32 @@ block.operations = operations +def transform_dead_operations(self): + """Remove dead operations.""" + # the set of operations that can safely be removed (no side effects) + CanRemove = {'newtuple': True, + 'newlist': True, + 'newdict': True} + for block in self.annotated: + # figure out which variables are ever read + read_vars = {} + for op in block.operations: + for arg in op.args: + read_vars[arg] = True + for link in block.exits: + for arg in link.args: + read_vars[arg] = True + # 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] + def transform_graph(ann): """Apply set of transformations available.""" transform_allocate(ann) transform_slice(ann) transform_simple_call(ann) + # do this last, after the previous transformations had a + # chance to remove dependency on certain variables + transform_dead_operations(ann) From arigo at codespeak.net Tue May 11 17:11:57 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 11 May 2004 17:11:57 +0200 (MEST) Subject: [pypy-svn] r4371 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20040511151157.BFB895A971@thoth.codespeak.net> Author: arigo Date: Tue May 11 17:11:56 2004 New Revision: 4371 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/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Dictionaries with known keys. Now decode_simple_call can properly check that there is no keyword argument. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Tue May 11 17:11:56 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 +from pypy.annotation.model import SomeString, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod from pypy.annotation.model import unionof, set, setunion, missing_operation @@ -91,6 +91,35 @@ return SomeTuple(items = tup1.items + tup2.items) +class __extend__(pairtype(SomeDict, SomeDict)): + + def union((dic1, dic2)): + result = dic1.items.copy() + for key, s_value in dic2.items.items(): + if key in result: + result[key] = unionof(result[key], s_value) + else: + result[key] = s_value + return SomeDict(setunion(dic1.factories, dic2.factories), result) + + +class __extend__(pairtype(SomeDict, SomeObject)): + + def getitem((dic1, obj2)): + if obj2.is_constant(): + return dic1.items.get(obj2.const, SomeImpossibleValue()) + else: + return SomeObject() + + def setitem((dic1, obj2), s_value): + assert obj2.is_constant() + key = obj2.const + if key not in dic1.items or not dic1.items[key].contains(s_value): + bookkeeper = getbookkeeper() + for factory in dic1.factories: + factory.generalize(key, s_value, bookkeeper) + + class __extend__(pairtype(SomeTuple, SomeInteger)): def getitem((tup1, int2)): Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Tue May 11 17:11:56 2004 @@ -9,7 +9,7 @@ from __future__ import generators from types import FunctionType from pypy.annotation.pairtype import pair -from pypy.annotation.model import SomeImpossibleValue, SomeList +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 @@ -107,6 +107,23 @@ bookkeeper.annotator.reflowfromposition(self.position_key) +class DictFactory: + items = {} + + def create(self): + return SomeDict(factories = {self: True}, items = self.items) + + def generalize(self, key, s_new_value, bookkeeper=None): + result = self.items.copy() + if key in result: + result[key] = unionof(result[key], s_new_value) + else: + result[key] = s_new_value + self.items = result + if bookkeeper: + bookkeeper.annotator.reflowfromposition(self.position_key) + + class FuncCallFactory: def pycall(self, func, arglist): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Tue May 11 17:11:56 2004 @@ -80,6 +80,13 @@ def __init__(self, items): self.items = tuple(items) # tuple of s_xxx elements +class SomeDict(SomeObject): + "Stands for a dict with known keys." + knowntype = dict + def __init__(self, factories, items): + self.factories = factories + self.items = items # dict {realkey: s_value} + class SomeClass(SomeObject): "Stands for a user-defined class object." # only used when the class object is loaded in a variable @@ -166,9 +173,9 @@ nbargs = s_nbargs.const arglist = [pair(s_args, immutablevalue(j)).getitem() 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 + 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 Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Tue May 11 17:11:56 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 +from pypy.annotation.model import SomeString, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass from pypy.annotation.model import SomeFunction, SomeMethod @@ -47,6 +47,12 @@ return immutablevalue(len(tup.items)) +class __extend__(SomeDict): + + def len(dic): + return immutablevalue(len(dic.items)) + + class __extend__(SomeList): def method_append(lst, s_item): Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Tue May 11 17:11:56 2004 @@ -4,6 +4,7 @@ from pypy.annotation import model as annmodel from pypy.annotation.model import pair from pypy.annotation.factory import ListFactory, InstanceFactory +from pypy.annotation.factory import DictFactory from pypy.annotation.factory import BlockedInference, Bookkeeper from pypy.objspace.flow.model import Variable, Constant, UndefinedConstant from pypy.objspace.flow.model import SpaceOperation, FunctionGraph @@ -279,6 +280,11 @@ factory.generalize(a) return factory.create() + def consider_op_newdict(self, *args): + assert not args, "XXX only supports newdict([])" + 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) 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 May 11 17:11:56 2004 @@ -339,3 +339,12 @@ else: x = H() return x.m(42) + +def knownkeysdict(b): + if b: + d = {'a': 0} + d['b'] = b + d['c'] = 'world' + else: + d = {'b': -123} + return d['b'] 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 May 11 17:11:56 2004 @@ -199,6 +199,12 @@ self.assertEquals(classes[snippet.H].attrs, {'attr': annmodel.immutablevalue(1)}) + def test_knownkeysdict(self): + a = RPythonAnnotator() + s = a.build_types(snippet.knownkeysdict, [int]) + # result should be an integer + self.assertEquals(s.knowntype, int) + def g(n): return [0,1,2,n] From arigo at codespeak.net Tue May 11 21:53:36 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Tue, 11 May 2004 21:53:36 +0200 (MEST) Subject: [pypy-svn] r4372 - in pypy/trunk/src/pypy/translator/tool: . pygame Message-ID: <20040511195336.639735A98D@thoth.codespeak.net> Author: arigo Date: Tue May 11 21:53:33 2004 New Revision: 4372 Added: pypy/trunk/src/pypy/translator/tool/pygame/ (props changed) pypy/trunk/src/pypy/translator/tool/pygame/VeraMoBd.ttf pypy/trunk/src/pypy/translator/tool/pygame/autopath.py - copied unchanged from r4369, pypy/trunk/src/pypy/translator/tool/autopath.py pypy/trunk/src/pypy/translator/tool/pygame/cyrvetic.ttf (contents, props changed) pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py (contents, props changed) Modified: pypy/trunk/src/pypy/translator/tool/make_dot.py Log: Pygame-based graph browser. Shows the inferred annotations when the mouse hovers above a variable name. Click and drag to view other parts of the 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 Tue May 11 21:53:33 2004 @@ -175,4 +175,4 @@ space = Space() graph = space.build_flow(f) - make_dot(graph, udir.dirname()) + make_dot('f', graph) Added: pypy/trunk/src/pypy/translator/tool/pygame/VeraMoBd.ttf ============================================================================== Files (empty file) and pypy/trunk/src/pypy/translator/tool/pygame/VeraMoBd.ttf Tue May 11 21:53:33 2004 differ Added: pypy/trunk/src/pypy/translator/tool/pygame/cyrvetic.ttf ============================================================================== Binary file. No diff available. Added: pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py Tue May 11 21:53:33 2004 @@ -0,0 +1,245 @@ +import autopath +import sys, re +import pygame +from pygame.locals import * + + +class Display: + + def __init__(self, (w,h)=(700,600)): + pygame.init() + self.resize((w,h)) + + def resize(self, (w,h)): + self.width = w + self.height = h + self.screen = pygame.display.set_mode((w, h), HWSURFACE|RESIZABLE) + +class GraphViewer: + FONT = 'cyrvetic.ttf' + xscale = 1 + yscale = 1 + offsetx = 0 + offsety = 0 + + def __init__(self, xdotfile, pngfile): + pygame.init() + g = open(str(pngfile), 'rb') + try: + self.bkgnd = pygame.image.load(pngfile) + except Exception, e: + print >> sys.stderr, '* Pygame cannot load "%s":' % pngfile + print >> sys.stderr, '* %s: %s' % (e.__class__.__name__, e) + print >> sys.stderr, '* Trying with pngtopnm.' + import os + g = os.popen("pngtopnm '%s'" % pngfile, 'r') + w, h, data = decodepixmap(g) + g.close() + self.bkgnd = pygame.image.fromstring(data, (w, h), "RGB") + self.width, self.height = self.bkgnd.get_size() + self.font = pygame.font.Font(self.FONT, 18) + + # compute a list of (rect, originalw, text, name) + # where text is some text from the graph, + # rect is its position on the screen, + # originalw is its real (dot-computed) size on the screen, + # and name is XXX + self.positions = [] + g = open(xdotfile, 'rb') + lines = g.readlines() + g.close() + self.parse_xdot_output(lines) + + def render(self, dpy): + ox = -self.offsetx + oy = -self.offsety + dpy.screen.blit(self.bkgnd, (ox, oy)) + # gray off-bkgnd areas + gray = (128, 128, 128) + if ox > 0: + dpy.screen.fill(gray, (0, 0, ox, dpy.height)) + if oy > 0: + dpy.screen.fill(gray, (0, 0, dpy.width, oy)) + w = dpy.width - (ox + self.width) + if w > 0: + dpy.screen.fill(gray, (dpy.width-w, 0, w, dpy.height)) + h = dpy.height - (oy + self.height) + if h > 0: + dpy.screen.fill(gray, (0, dpy.height-h, dpy.width, h)) + + def at_position(self, (x, y), re_nonword=re.compile(r'(\W+)')): + """Compute (word, text, name) where word is the word under the cursor, + text is the complete line, and name is XXX. All three are None + if no text is under the cursor.""" + x += self.offsetx + y += self.offsety + for (rx,ry,rw,rh), originalw, text, name in self.positions: + if rx <= x < rx+originalw and ry <= y < ry+rh: + dx = x - rx + # scale dx to account for small font mismatches + dx = int(float(dx) * rw / originalw) + words = [s for s in re_nonword.split(text) if s] + segment = '' + word = '' + for word in words: + segment += word + img = self.font.render(segment, 1, (255, 0, 0)) + w, h = img.get_size() + if dx < w: + break + return word, text, name + return None, None, None + + def parse_xdot_output(self, lines): + for i in range(len(lines)): + if lines[i].endswith('\\\n'): + lines[i+1] = lines[i][:-2] + lines[i+1] + lines[i] = '' + for line in lines: + self.parse_xdot_line(line) + + def parse_xdot_line(self, line, + re_bb = re.compile(r'\s*graph\s+[[]bb=["]0,0,(\d+),(\d+)["][]]'), + re_text = re.compile(r"\s*T" + 5*r"\s+(-?\d+)" + r"\s+-"), + matchtext = ' _ldraw_="'): + match = re_bb.match(line) + if match: + self.xscale = float(self.width-12) / int(match.group(1)) + self.yscale = float(self.height-12) / int(match.group(2)) + return + p = line.find(matchtext) + if p < 0: + return + p += len(matchtext) + line = line[p:] + while 1: + match = re_text.match(line) + if not match: + break + x = 10+int(float(match.group(1)) * self.xscale) + y = self.height-2-int(float(match.group(2)) * self.yscale) + n = int(match.group(5)) + end = len(match.group()) + text = line[end:end+n] + line = line[end+n:] + if text: + img = self.font.render(text, 1, (255, 0, 0)) + w, h = img.get_size() + align = int(match.group(3)) + if align == 0: + x -= w//2 + elif align > 0: + x -= w + rect = x, y-h, w, h + originalw = int(float(match.group(4)) * self.xscale) + self.positions.append((rect, originalw, text, 'XXX')) + + + +def decodepixmap(f): + sig = f.readline().strip() + assert sig == "P6" + while 1: + line = f.readline().strip() + if not line.startswith('#'): + break + wh = line.split() + w, h = map(int, wh) + sig = f.readline().strip() + assert sig == "255" + data = f.read() + f.close() + return w, h, data + + +if __name__ == '__main__': + from pypy.translator.translator import Translator + from pypy.translator.test import snippet + from pypy.translator.tool.make_dot import make_dot_graphs + + t = Translator(snippet.poor_man_range) + t.simplify() + a = t.annotate([int]) + a.simplify() + + variables_by_name = {} + for var in a.bindings: + variables_by_name[var.name] = var + + graphs = [] + for func in t.functions: + graph = t.getflowgraph(func) + graphs.append((graph.name, graph)) + xdotfile = make_dot_graphs(t.entrypoint.__name__, graphs, target='xdot') + pngfile = make_dot_graphs(t.entrypoint.__name__, graphs, target='png') + + viewer = GraphViewer(str(xdotfile), str(pngfile)) + + dpy = Display() + viewer.render(dpy) + dragging = None + + font = pygame.font.Font('VeraMoBd.ttf', 16) + + def setstatusbar(text, fgcolor=(255,255,80), bgcolor=(128,0,0)): + words = text.split(' ') + lines = [] + totalh = 0 + 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 > dpy.width: + break + words.pop(0) + line = longerline + img = longerimg + lines.append(img) + w, h = img.get_size() + totalh += h + + y = dpy.height - totalh + viewer.render(dpy) + dpy.screen.fill(bgcolor, (0, y-16, dpy.width, totalh+16)) + for img in lines: + w, h = img.get_size() + dpy.screen.blit(img, ((dpy.width-w)//2, y-8)) + y += h + + def setmousepos(pos): + word, text, name = viewer.at_position(event.pos) + if word in variables_by_name: + var = variables_by_name[word] + s_value = a.binding(var) + info = '%s: %s' % (var.name, s_value) + setstatusbar(info) + + while 1: + event = pygame.event.wait() + if event.type == MOUSEMOTION: + # short-circuit if there are more motion events pending + if pygame.event.peek([MOUSEMOTION]): + continue + if dragging: + viewer.offsetx -= (event.pos[0] - dragging[0]) + viewer.offsety -= (event.pos[1] - dragging[1]) + dragging = event.pos + viewer.render(dpy) + else: + setmousepos(event.pos) + if event.type == MOUSEBUTTONDOWN: + dragging = event.pos + pygame.event.set_grab(True) + if event.type == MOUSEBUTTONUP: + dragging = None + pygame.event.set_grab(False) + setmousepos(event.pos) + if event.type == VIDEORESIZE: + dpy.resize(event.size) + viewer.render(dpy) + if event.type == QUIT: + break + pygame.display.flip() From arigo at codespeak.net Fri May 21 20:30:20 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 21 May 2004 20:30:20 +0200 (MEST) Subject: [pypy-svn] r4491 - pypy/trunk/src/pypy/objspace/flow Message-ID: <20040521183020.BCA325A28A@thoth.codespeak.net> Author: arigo Date: Fri May 21 20:30:18 2004 New Revision: 4491 Modified: pypy/trunk/src/pypy/objspace/flow/flowcontext.py pypy/trunk/src/pypy/objspace/flow/framestate.py pypy/trunk/src/pypy/objspace/flow/objspace.py Log: Bootstrapping details. 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 May 21 20:30:18 2004 @@ -69,7 +69,7 @@ ExecutionContext.__init__(self, space) self.code = code self.w_globals = w_globals = space.wrap(globals) - frame = code.create_frame(space, w_globals) + frame = self.create_frame() formalargcount = code.getformalargcount() dummy = UndefinedConstant() arg_list = ([Variable() for i in range(formalargcount)] + @@ -82,6 +82,12 @@ self.pendingblocks = [initialblock] self.graph = FunctionGraph(code.co_name, initialblock) + def create_frame(self): + # create an empty frame suitable for the code object + # while ignoring any operation like the creation of the locals dict + self.crnt_ops = [] + return self.code.create_frame(self.space, self.w_globals) + def bytecode_trace(self, frame): if isinstance(self.crnt_ops, ReplayList): return @@ -148,7 +154,7 @@ def build_flow(self): while self.pendingblocks: block = self.pendingblocks.pop(0) - frame = self.code.create_frame(self.space, self.w_globals) + frame = self.create_frame() try: block.patchframe(frame, self) except ExitFrame: 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 Fri May 21 20:30:18 2004 @@ -11,6 +11,7 @@ state.blockstack.items[:], state.last_exception, state.next_instr, + state.w_locals, ) elif isinstance(state, tuple): self.mergeable, self.nonmergeable = state @@ -27,6 +28,7 @@ frame.blockstack.items[:], frame.last_exception, frame.next_instr, + frame.w_locals, ) = self.nonmergeable else: raise TypeError("can't set framestate for %r" % 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 May 21 20:30:18 2004 @@ -85,7 +85,8 @@ # ____________________________________________________________ def do_operation(self, name, *args_w): spaceop = SpaceOperation(name, args_w, Variable()) - self.executioncontext.crnt_ops.append(spaceop) + if hasattr(self, 'executioncontext'): # not here during bootstrapping + self.executioncontext.crnt_ops.append(spaceop) return spaceop.result def is_true(self, w_obj): From arigo at codespeak.net Fri May 21 23:24:23 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 21 May 2004 23:24:23 +0200 (MEST) Subject: [pypy-svn] r4492 - pypy/trunk/src/pypy/translator/tool/pygame Message-ID: <20040521212423.6DC2A5A28A@thoth.codespeak.net> Author: arigo Date: Fri May 21 23:24:22 2004 New Revision: 4492 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py Log: Increased a bit the size of the window. Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py Fri May 21 23:24:22 2004 @@ -6,7 +6,7 @@ class Display: - def __init__(self, (w,h)=(700,600)): + def __init__(self, (w,h)=(800,740)): pygame.init() self.resize((w,h)) From arigo at codespeak.net Fri May 21 23:30:41 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 21 May 2004 23:30:41 +0200 (MEST) Subject: [pypy-svn] r4493 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20040521213041.6C9F55A28A@thoth.codespeak.net> Author: arigo Date: Fri May 21 23:30:40 2004 New Revision: 4493 Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py pypy/trunk/src/pypy/objspace/std/default.py pypy/trunk/src/pypy/objspace/std/objecttype.py pypy/trunk/src/pypy/objspace/std/objspace.py pypy/trunk/src/pypy/objspace/std/sliceobject.py pypy/trunk/src/pypy/objspace/std/test/test_userobject.py pypy/trunk/src/pypy/objspace/std/typeobject.py Log: Hack support for __getattr__ in user-defined classes. Modified: pypy/trunk/src/pypy/objspace/std/cpythonobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/cpythonobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/cpythonobject.py Fri May 21 23:30:40 2004 @@ -216,6 +216,7 @@ raise ValueError, '_arity too large' arglist = [W_CPythonObject] + [W_ANY]*(_arity-1) + if _name == 'getattr': _name = 'getattribute' # XXX hack multimethod = getattr(StdObjSpace, _name) multimethod.register(cpython_f, *arglist) Modified: pypy/trunk/src/pypy/objspace/std/default.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/default.py (original) +++ pypy/trunk/src/pypy/objspace/std/default.py Fri May 21 23:30:40 2004 @@ -45,7 +45,7 @@ # give objects some default attributes and a default way to complain # about missing attributes -def getattr__Object_ANY(space, w_obj, w_attr): +def getattribute__Object_ANY(space, w_obj, w_attr): # XXX build a nicer error message along these lines: #w_type = space.type(w_obj) #w_typename = space.getattr(w_type, space.wrap('__name__')) Modified: pypy/trunk/src/pypy/objspace/std/objecttype.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/objecttype.py (original) +++ pypy/trunk/src/pypy/objspace/std/objecttype.py Fri May 21 23:30:40 2004 @@ -12,7 +12,7 @@ # all multimethods that we want to be visible as object.__xxx__ # should be defined here. - object_getattr = StdObjSpace.getattr + object_getattr = StdObjSpace.getattribute object_setattr = StdObjSpace.setattr object_delattr = StdObjSpace.delattr object_type = StdObjSpace.type 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 May 21 23:30:40 2004 @@ -258,6 +258,28 @@ getdict = MultiMethod('getdict', 1, []) # get '.__dict__' attribute next = MultiMethod('next', 1, []) # iterator interface call = MultiMethod('call', 3, [], varargs=True, keywords=True) + getattribute = MultiMethod('getattr', 2, ['__getattribute__']) # XXX hack + usergetattr = MultiMethod('usergetattr', 2, ['__getattr__']) # XXX hack + + def getattr(self, w_obj, w_attr): + try: + return self.getattribute(w_obj, w_attr) + except OperationError, e: + if not e.match(self, self.w_AttributeError): + raise + result = self.getattr_try_harder(w_obj, w_attr) + if result is None: + raise + return result + + def getattr_try_harder(self, *args_w): + # this needs to be in another function so that the exception caught + # here doesn't prevent the bare 'raise' in self.getattr() to + # re-raise the previous OperationError with correct traceback. + try: + return self.usergetattr.perform_call(args_w) + except FailedToImplement: + return None def is_(self, w_one, w_two): # XXX a bit of hacking to gain more speed Modified: pypy/trunk/src/pypy/objspace/std/sliceobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/sliceobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/sliceobject.py Fri May 21 23:30:40 2004 @@ -21,7 +21,7 @@ registerimplementation(W_SliceObject) -def getattr__Slice_ANY(space, w_slice, w_attr): +def getattribute__Slice_ANY(space, w_slice, w_attr): if space.is_true(space.eq(w_attr, space.wrap('start'))): if w_slice.w_start is None: return space.w_None Modified: pypy/trunk/src/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Fri May 21 23:30:40 2004 @@ -97,5 +97,23 @@ self.assertEquals(c1(5), (5,)) self.assertEquals(c1("hello", "world"), ("hello", "world")) + def test_getattribute(self): + class C: + def __getattribute__(self, name): + return '->' + name + c1 = C() + self.assertEquals(c1.a, '->a') + c1.a = 5 + self.assertEquals(c1.a, '->a') + + def test_getattr(self): + class C: + def __getattr__(self, name): + return '->' + name + c1 = C() + self.assertEquals(c1.a, '->a') + c1.a = 5 + self.assertEquals(c1.a, 5) + if __name__ == '__main__': testit.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 Fri May 21 23:30:40 2004 @@ -210,7 +210,7 @@ def repr__Type(space, w_obj): return space.wrap("" % w_obj.typename) # XXX remove 'pypy' -def getattr__Type_ANY(space, w_type, w_attr): +def getattribute__Type_ANY(space, w_type, w_attr): # XXX mwh doubts this is the Right Way to do this... if space.is_true(space.eq(w_attr, space.wrap('__name__'))): return w_type.w_tpname From arigo at codespeak.net Sat May 22 00:15:11 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Sat, 22 May 2004 00:15:11 +0200 (MEST) Subject: [pypy-svn] r4494 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20040521221511.D3AA55A28A@thoth.codespeak.net> Author: arigo Date: Sat May 22 00:15:11 2004 New Revision: 4494 Modified: pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Log: Test methods and unbound methods. Modified: pypy/trunk/src/pypy/objspace/std/test/test_userobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_userobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_userobject.py Sat May 22 00:15:11 2004 @@ -12,6 +12,20 @@ inst.attr=23 self.assertEquals(inst.attr,23) + def test_method(self): + class A: + def f(self, v): + return v*42 + a = A() + self.assertEquals(a.f('?'), '??????????????????????????????????????????') + + def test_unboundmethod(self): + class A: + def f(self, v): + return v*17 + a = A() + self.assertEquals(A.f(a, '!'), '!!!!!!!!!!!!!!!!!') + def test_subclassing(self): for base in tuple, list, dict, str, int, float: try: From hpk at codespeak.net Tue May 25 14:43:13 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Tue, 25 May 2004 14:43:13 +0200 (MEST) Subject: [pypy-svn] r4570 - pypy/trunk/src/pypy Message-ID: <20040525124313.1F7FE5A1B5@thoth.codespeak.net> Author: hpk Date: Tue May 25 14:43:12 2004 New Revision: 4570 Modified: pypy/trunk/src/pypy/TODO Log: small corrections in the TODO file Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Tue May 25 14:43:12 2004 @@ -10,8 +10,8 @@ * (documentation) generate a nice dot-graph from the structure of PyPy -* trash the standard unittest framework/enhance it (there already - is some new version-in-progress in tool/newtest.py) +* port pypy's testing framework to std.utest (probably a sprint topic, + as some discussion how to do it is required) * (documentation) remove/retire all web-pages referencing e.g. AnnSpace or other deprecated stuff @@ -24,7 +24,7 @@ and try to apply the same technique for the application level type definitions (types.py) -* review, +* review whatever you like * clear out and do a clean implementation of multimethod delegation. The idea is to give 'kinds' to arguments according to their use, From arigo at codespeak.net Thu May 27 14:03:26 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 27 May 2004 14:03:26 +0200 (MEST) Subject: [pypy-svn] r4673 - in pypy/trunk/src/pypy/translator: . test tool/pygame Message-ID: <20040527120326.F06F15A6E7@thoth.codespeak.net> Author: arigo Date: Thu May 27 14:03:26 2004 New Revision: 4673 Added: pypy/trunk/src/pypy/translator/tool/pygame/__init__.py - copied unchanged from r4671, pypy/trunk/src/pypy/translator/tool/__init__.py Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py pypy/trunk/src/pypy/translator/translator.py Log: Integrated graphviewer with translator.py. Type 't.view()' to view the control flow graph, with annotation if they have been computed before. 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 May 27 14:03:26 2004 @@ -348,3 +348,6 @@ else: d = {'b': -123} return d['b'] + +def prime(n): + return len([i for i in range(1,n+1) if n%i==0]) == 2 Modified: pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py (original) +++ pypy/trunk/src/pypy/translator/tool/pygame/graphviewer.py Thu May 27 14:03:26 2004 @@ -1,10 +1,11 @@ import autopath -import sys, re +import sys, os, re import pygame from pygame.locals import * +from pypy.translator.tool.make_dot import make_dot_graphs -class Display: +class Display(object): def __init__(self, (w,h)=(800,740)): pygame.init() @@ -15,8 +16,8 @@ self.height = h self.screen = pygame.display.set_mode((w, h), HWSURFACE|RESIZABLE) -class GraphViewer: - FONT = 'cyrvetic.ttf' +class GraphViewer(object): + FONT = os.path.join(autopath.this_dir, 'cyrvetic.ttf') xscale = 1 yscale = 1 offsetx = 0 @@ -152,47 +153,50 @@ return w, h, data -if __name__ == '__main__': - from pypy.translator.translator import Translator - from pypy.translator.test import snippet - from pypy.translator.tool.make_dot import make_dot_graphs - - t = Translator(snippet.poor_man_range) - t.simplify() - a = t.annotate([int]) - a.simplify() - - variables_by_name = {} - for var in a.bindings: - variables_by_name[var.name] = var - - graphs = [] - for func in t.functions: - graph = t.getflowgraph(func) - graphs.append((graph.name, graph)) - xdotfile = make_dot_graphs(t.entrypoint.__name__, graphs, target='xdot') - pngfile = make_dot_graphs(t.entrypoint.__name__, graphs, target='png') - - viewer = GraphViewer(str(xdotfile), str(pngfile)) +class GraphDisplay(Display): + STATUSBARFONT = os.path.join(autopath.this_dir, 'VeraMoBd.ttf') - dpy = Display() - viewer.render(dpy) - dragging = None + def __init__(self, translator): + super(GraphDisplay, self).__init__() + self.translator = translator + self.annotator = translator.annotator + self.font = pygame.font.Font(self.STATUSBARFONT, 16) + + self.variables_by_name = {} + if self.annotator: + for var in self.annotator.bindings: + self.variables_by_name[var.name] = var + + graphs = [] + for func in self.translator.functions: + graph = self.translator.getflowgraph(func) + graphs.append((graph.name, graph)) + xdotfile = make_dot_graphs(self.translator.entrypoint.__name__, graphs, target='xdot') + pngfile = make_dot_graphs(self.translator.entrypoint.__name__, graphs, target='png') + self.viewer = GraphViewer(str(xdotfile), str(pngfile)) + self.viewer.offsetx = (self.viewer.width - self.width) // 2 + self.statusbarinfo = None + self.must_redraw = True + + def setstatusbar(self, text, fgcolor=(255,255,80), bgcolor=(128,0,0)): + info = (text, fgcolor, bgcolor) + if info != self.statusbarinfo: + self.statusbarinfo = info + self.must_redraw = True - font = pygame.font.Font('VeraMoBd.ttf', 16) - - def setstatusbar(text, fgcolor=(255,255,80), bgcolor=(128,0,0)): + def drawstatusbar(self): + text, fgcolor, bgcolor = self.statusbarinfo words = text.split(' ') lines = [] totalh = 0 while words: line = words.pop(0) - img = font.render(line, 1, fgcolor) + img = self.font.render(line, 1, fgcolor) while words: longerline = line + ' ' + words[0] - longerimg = font.render(longerline, 1, fgcolor) + longerimg = self.font.render(longerline, 1, fgcolor) w, h = longerimg.get_size() - if w > dpy.width: + if w > self.width: break words.pop(0) line = longerline @@ -201,45 +205,67 @@ w, h = img.get_size() totalh += h - y = dpy.height - totalh - viewer.render(dpy) - dpy.screen.fill(bgcolor, (0, y-16, dpy.width, totalh+16)) + y = self.height - totalh + self.screen.fill(bgcolor, (0, y-16, self.width, totalh+16)) for img in lines: w, h = img.get_size() - dpy.screen.blit(img, ((dpy.width-w)//2, y-8)) + self.screen.blit(img, ((self.width-w)//2, y-8)) y += h - def setmousepos(pos): - word, text, name = viewer.at_position(event.pos) - if word in variables_by_name: - var = variables_by_name[word] - s_value = a.binding(var) + def notifymousepos(self, pos): + word, text, name = self.viewer.at_position(pos) + if word in self.variables_by_name: + var = self.variables_by_name[word] + s_value = self.annotator.binding(var) info = '%s: %s' % (var.name, s_value) - setstatusbar(info) + self.setstatusbar(info) - while 1: - event = pygame.event.wait() - if event.type == MOUSEMOTION: - # short-circuit if there are more motion events pending - if pygame.event.peek([MOUSEMOTION]): - continue - if dragging: - viewer.offsetx -= (event.pos[0] - dragging[0]) - viewer.offsety -= (event.pos[1] - dragging[1]) + def run(self): + dragging = None + while 1: + if self.must_redraw: + self.viewer.render(self) + if self.statusbarinfo: + self.drawstatusbar() + pygame.display.flip() + self.must_redraw = False + + event = pygame.event.wait() + if event.type == MOUSEMOTION: + # short-circuit if there are more motion events pending + if pygame.event.peek([MOUSEMOTION]): + continue + if dragging: + self.viewer.offsetx -= (event.pos[0] - dragging[0]) + self.viewer.offsety -= (event.pos[1] - dragging[1]) + dragging = event.pos + self.must_redraw = True + else: + self.notifymousepos(event.pos) + if event.type == MOUSEBUTTONDOWN: dragging = event.pos - viewer.render(dpy) - else: - setmousepos(event.pos) - if event.type == MOUSEBUTTONDOWN: - dragging = event.pos - pygame.event.set_grab(True) - if event.type == MOUSEBUTTONUP: - dragging = None - pygame.event.set_grab(False) - setmousepos(event.pos) - if event.type == VIDEORESIZE: - dpy.resize(event.size) - viewer.render(dpy) - if event.type == QUIT: - break - pygame.display.flip() + pygame.event.set_grab(True) + if event.type == MOUSEBUTTONUP: + dragging = None + pygame.event.set_grab(False) + self.notifymousepos(event.pos) + if event.type == VIDEORESIZE: + # short-circuit if there are more resize events pending + if pygame.event.peek([VIDEORESIZE]): + continue + self.resize(event.size) + self.must_redraw = True + if event.type == QUIT: + break + pygame.display.quit() + + +if __name__ == '__main__': + from pypy.translator.translator import Translator + from pypy.translator.test import snippet + + t = Translator(snippet.poor_man_range) + t.simplify() + a = t.annotate([int]) + a.simplify() + GraphDisplay(t).run() Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Thu May 27 14:03:26 2004 @@ -8,7 +8,7 @@ Example: t = Translator(func) - t.gv() # control flow graph + t.view() # control flow graph print t.source() # original source print t.pyrex() # pyrex translation @@ -17,6 +17,7 @@ t.simplify() # flow graph simplification a = t.annotate([int]) # pass the list of args types a.simplify() # simplification by annotator + t.view() # graph + annotations under the mouse t.call(arg) # call original function t.dis() # bytecode disassemble @@ -86,6 +87,12 @@ dest = make_dot(graph.name, graph) os.system('gv %s' % str(dest)) + def view(self): + """Shows the control flow graph with annotations if computed. + Requires 'dot' and pygame.""" + from pypy.translator.tool.pygame.graphviewer import GraphDisplay + GraphDisplay(self).run() + def simplify(self, func=None): """Simplifies the control flow graph (default: for all functions).""" if func is None: From arigo at codespeak.net Thu May 27 14:15:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 27 May 2004 14:15:58 +0200 (MEST) Subject: [pypy-svn] r4675 - pypy/trunk/src/pypy/annotation Message-ID: <20040527121558.E7D015A6E7@thoth.codespeak.net> Author: arigo Date: Thu May 27 14:15:58 2004 New Revision: 4675 Modified: pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Simple iterators. Now 'for i in range(...)' is correctly analysed. Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Thu May 27 14:15:58 2004 @@ -87,6 +87,12 @@ 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 Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Thu May 27 14:15:58 2004 @@ -7,14 +7,15 @@ from pypy.annotation.model import SomeString, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeBuiltin, SomeClass -from pypy.annotation.model import SomeFunction, SomeMethod +from pypy.annotation.model import SomeFunction, SomeMethod, SomeIterator from pypy.annotation.model import immutablevalue, decode_simple_call from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper from pypy.annotation.factory import InstanceFactory, FuncCallFactory -UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'call']) +UNARY_OPERATIONS = set(['len', 'is_true', 'getattr', 'setattr', 'call', + 'iter', 'next']) for opname in UNARY_OPERATIONS: missing_operation(SomeObject, opname) @@ -58,6 +59,15 @@ def method_append(lst, s_item): pair(lst, SomeInteger()).setitem(s_item) + def iter(lst): + return SomeIterator(lst.s_item) + + +class __extend__(SomeIterator): + + def next(itr): + return itr.s_item + class __extend__(SomeInstance): From arigo at codespeak.net Thu May 27 14:16:11 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 27 May 2004 14:16:11 +0200 (MEST) Subject: [pypy-svn] r4676 - pypy/trunk/src/pypy/annotation Message-ID: <20040527121611.DE2285A6E7@thoth.codespeak.net> Author: arigo Date: Thu May 27 14:16:11 2004 New Revision: 4676 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: A few more integer operators. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Thu May 27 14:16:11 2004 @@ -12,8 +12,9 @@ # XXX unify this with ObjSpace.MethodTable -BINARY_OPERATIONS = set(['add', 'sub', 'mul', 'getitem', 'setitem', - 'inplace_add', +BINARY_OPERATIONS = set(['add', 'sub', 'mul', 'div', 'mod', + 'getitem', 'setitem', + 'inplace_add', 'inplace_sub', 'lt', 'le', 'eq', 'ne', 'gt', 'ge', 'union']) @@ -29,6 +30,9 @@ def inplace_add((obj1, obj2)): return pair(obj1, obj2).add() # default + def inplace_sub((obj1, obj2)): + return pair(obj1, obj2).sub() # default + class __extend__(pairtype(SomeInteger, SomeInteger)): @@ -38,7 +42,7 @@ def add((int1, int2)): return SomeInteger(nonneg = int1.nonneg and int2.nonneg) - mul = add + mul = div = mod = add def sub((int1, int2)): return SomeInteger() From arigo at codespeak.net Thu May 27 14:57:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 27 May 2004 14:57:18 +0200 (MEST) Subject: [pypy-svn] r4681 - in pypy/trunk/src/pypy: objspace/flow translator Message-ID: <20040527125718.85F395A6E7@thoth.codespeak.net> Author: arigo Date: Thu May 27 14:57:17 2004 New Revision: 4681 Modified: pypy/trunk/src/pypy/objspace/flow/model.py pypy/trunk/src/pypy/translator/simplify.py pypy/trunk/src/pypy/translator/transform.py Log: Dead variable analysis, to reduce these really long lists of variables passed around on each link. 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 May 27 14:57:17 2004 @@ -9,6 +9,7 @@ def __init__(self, name, startblock, return_var=None): self.name = name # function name (possibly mangled already) self.startblock = startblock + self.startblock.isstartblock = True # build default returnblock self.returnblock = Block([return_var or Variable()]) self.returnblock.operations = () @@ -40,6 +41,8 @@ self.prevblock = None # the block this Link is an exit of class Block: + isstartblock = False + def __init__(self, inputargs): self.inputargs = inputargs # mixed list of variable/const self.operations = [] # list of SpaceOperation(s) Modified: pypy/trunk/src/pypy/translator/simplify.py ============================================================================== --- pypy/trunk/src/pypy/translator/simplify.py (original) +++ pypy/trunk/src/pypy/translator/simplify.py Thu May 27 14:57:17 2004 @@ -62,6 +62,10 @@ traverse(visit, graph) def remove_implicit_exceptions(graph): + """An exception that is marked implicit (see implicitexc) and not + caught in the block is entierely removed. This gets rid for example + of possible ValueErrors upon tuple unpacking, assuming they cannot + happen unless there is an exception handler in the same function.""" def visit(link): if isinstance(link, Link) and link in link.prevblock.exits: if (isinstance(link.exitcase, type(Exception)) and Modified: pypy/trunk/src/pypy/translator/transform.py ============================================================================== --- pypy/trunk/src/pypy/translator/transform.py (original) +++ pypy/trunk/src/pypy/translator/transform.py Thu May 27 14:57:17 2004 @@ -96,26 +96,77 @@ block.operations = operations -def transform_dead_operations(self): - """Remove dead operations.""" +def transform_dead_op_vars(self): + """Remove dead operations and variables that are passed over a link + but not used in the target block.""" # the set of operations that can safely be removed (no side effects) CanRemove = {'newtuple': True, 'newlist': True, 'newdict': True} + read_vars = {} # set of variables really used + variable_flow = {} # map {Var: list-of-Vars-it-depends-on} + + # compute variable_flow and an initial read_vars for block in self.annotated: # figure out which variables are ever read - read_vars = {} for op in block.operations: - for arg in op.args: - read_vars[arg] = True - for link in block.exits: - for arg in link.args: + if op.opname not in CanRemove: # mark the inputs as really needed + for arg in op.args: + read_vars[arg] = True + else: + # if CanRemove, only mark dependencies of the result + # on the input variables + deps = variable_flow.setdefault(op.result, []) + deps.extend(op.args) + + 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) + else: + # return blocks implicitely use their single input variable + assert len(block.inputargs) == 1 + read_vars[block.inputargs[0]] = 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: + for arg in block.inputargs: read_vars[arg] = True + + # flow read_vars backwards so that any variable on which a read_vars + # depends is also included in read_vars + pending = list(read_vars) + for var in pending: + for prevvar in variable_flow.get(var, []): + if prevvar not in read_vars: + read_vars[prevvar] = True + pending.append(prevvar) + + 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] if op.opname in CanRemove and op.result not in read_vars: 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! + # Otherwise the link.args get out of sync with the + # link.target.inputargs. + for link in block.exits: + for i in range(len(link.args)-1, -1, -1): + if link.target.inputargs[i] not in read_vars: + del link.args[i] + + 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): + if block.inputargs[i] not in read_vars: + del block.inputargs[i] def transform_graph(ann): """Apply set of transformations available.""" @@ -124,4 +175,4 @@ transform_simple_call(ann) # do this last, after the previous transformations had a # chance to remove dependency on certain variables - transform_dead_operations(ann) + transform_dead_op_vars(ann) From hpk at codespeak.net Thu May 27 15:37:43 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Thu, 27 May 2004 15:37:43 +0200 (MEST) Subject: [pypy-svn] r4685 - in pypy/trunk/doc: . devel funding funding/negotiations irclog objspace sprintinfo translation Message-ID: <20040527133743.81EDC5A6E7@thoth.codespeak.net> Author: hpk Date: Thu May 27 15:37:42 2004 New Revision: 4685 Modified: pypy/trunk/doc/ (props changed) pypy/trunk/doc/devel/ (props changed) pypy/trunk/doc/funding/ (props changed) pypy/trunk/doc/funding/negotiations/ (props changed) pypy/trunk/doc/irclog/ (props changed) pypy/trunk/doc/objspace/ (props changed) pypy/trunk/doc/sprintinfo/ (props changed) pypy/trunk/doc/translation/ (props changed) Log: set .svninfo and .html files to 'ignore' in all doc directories From arigo at codespeak.net Thu May 27 18:09:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Thu, 27 May 2004 18:09:44 +0200 (MEST) Subject: [pypy-svn] r4689 - in pypy/trunk/src/pypy/module: . test Message-ID: <20040527160944.2ED085A6E7@thoth.codespeak.net> Author: arigo Date: Thu May 27 18:09:43 2004 New Revision: 4689 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/__builtin__module.py pypy/trunk/src/pypy/module/test/test_builtin.py Log: super() hack. 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 Thu May 27 18:09:43 2004 @@ -162,3 +162,8 @@ def setattr(w_object, w_name, w_val): space.setattr(w_object, w_name, w_val) return space.w_None + +def _pypy_get(w_value, w_self, w_class=None): # XXX temporary + if w_class is None: + w_class = space.w_None + return space.get(w_value, w_self, w_class) Modified: pypy/trunk/src/pypy/module/__builtin__module.py ============================================================================== --- pypy/trunk/src/pypy/module/__builtin__module.py (original) +++ pypy/trunk/src/pypy/module/__builtin__module.py Thu May 27 18:09:43 2004 @@ -426,7 +426,7 @@ from __interplevel__ import abs, chr, len, ord, pow, repr from __interplevel__ import hash, oct, hex, round from __interplevel__ import getattr, setattr, delattr, iter, hash, id -from __interplevel__ import issubclass +from __interplevel__ import issubclass, _pypy_get from __interplevel__ import compile from __interplevel__ import globals, locals, _caller_globals, _caller_locals @@ -487,14 +487,15 @@ i+=step -# XXX the following comes from http://<<>> +# Descriptor code, shamelessly stolen to Raymond Hettinger: +# http://users.rcn.com/python/download/Descriptor.htm class property(object): def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel - self.__doc__ = doc or "" + self.__doc__ = doc or "" # XXX why: or "" ? def __get__(self, obj, objtype=None): if obj is None: @@ -536,6 +537,42 @@ return newfunc +# super is a modified version from Guido's tutorial +# http://www.python.org/2.2.3/descrintro.html +# it exposes the same special attributes as CPython's. +class super(object): + def __init__(self, type, obj=None): + self.__thisclass__ = type + self.__self__ = obj + if obj is not None and isinstance(obj, type): + self.__self_class__ = obj.__class__ + else: + self.__self_class__ = obj + def __get__(self, obj, type=None): + if self.__self__ is None and obj is not None: + return super(self.__thisclass__, obj) + else: + return self + def __getattr__(self, attr): + mro = iter(self.__self_class__.__mro__) + for cls in mro: + if cls is self.__thisclass__: + break + # Note: mro is an iterator, so the second loop + # picks up where the first one left off! + for cls in mro: + try: + # XXX + # XXX build-in classes have no __dict__ currently! + # XXX + x = getattr(cls, attr) + except AttributeError: + continue + x = _pypy_get(x, self.__self__) # XXX replace with x.__get__ + return x + raise AttributeError, attr + + # ________________________________________________________________________ ## def app___import__(*args): ## # NOTE: No import statements can be done in this function, Modified: pypy/trunk/src/pypy/module/test/test_builtin.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_builtin.py (original) +++ pypy/trunk/src/pypy/module/test/test_builtin.py Thu May 27 18:09:43 2004 @@ -230,7 +230,21 @@ self.assertRaises(TypeError, hash, []) self.assertRaises(TypeError, hash, {}) - + def test_super(self): + class A: + def f(self): + return 'A' + class B(A): + def f(self): + return 'B' + super(B,self).f() + class C(A): + def f(self): + return 'C' + super(C,self).f() + class D(B, C): + def f(self): + return 'D' + super(D,self).f() + d = D() + self.assertEquals(d.f(), "DBCA") class TestInternal(testit.IntTestCase): From arigo at codespeak.net Fri May 28 17:39:45 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Fri, 28 May 2004 17:39:45 +0200 (MEST) Subject: [pypy-svn] r4700 - in pypy/trunk/src/pypy/objspace/std: . test Message-ID: <20040528153945.6BDA95A6E7@thoth.codespeak.net> Author: arigo Date: Fri May 28 17:39:44 2004 New Revision: 4700 Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Log: repr(string) bug fixed, corresponding test added. Modified: pypy/trunk/src/pypy/objspace/std/stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/stringobject.py Fri May 28 17:39:44 2004 @@ -910,20 +910,20 @@ def app_repr__String(s): - quote = '\'' - if quote in s and not '"' in s: + quote = "'" + if quote in s and '"' not in s: quote = '"' repr = quote - for i in range(len(s)): - c = s[i] - if c == '\\' or c == quote: repr += '\\'+c - elif c == '\t': repr+= '\\t' - elif c == '\r': repr+= '\\r' - elif c == '\n': repr+= '\\n' - elif not chr(32) <= c < chr(127) : - repr += '\\' + hex(ord(c))[-3:] + for c in s: + if c == '\\' or c == quote: repr += '\\'+c + elif c == '\t': repr += '\\t' + elif c == '\r': repr += '\\r' + elif c == '\n': repr += '\\n' + elif not '\x20' <= c < '\x7f': + n = ord(c) + repr += '\\x'+"0123456789abcdef"[n>>4]+"0123456789abcdef"[n&0xF] else: repr += c Modified: pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_stringobject.py Fri May 28 17:39:44 2004 @@ -469,6 +469,7 @@ self.assertEquals(repr('\\') ,"'\\\\'") self.assertEquals(repr("'''\"") ,'\'\\\'\\\'\\\'"\'') self.assertEquals(repr(chr(19)) ,"'\\x13'") + self.assertEquals(repr(chr(2)) ,"'\\x02'") if __name__ == '__main__': From jum at codespeak.net Sat May 29 01:05:58 2004 From: jum at codespeak.net (jum at codespeak.net) Date: Sat, 29 May 2004 01:05:58 +0200 (MEST) Subject: [pypy-svn] r4704 - pypy/trunk/doc/devel Message-ID: <20040528230558.5C1235ACB8@thoth.codespeak.net> Author: jum Date: Sat May 29 01:05:57 2004 New Revision: 4704 Modified: pypy/trunk/doc/devel/howtosvn.txt Log: Updated OS X version. Modified: pypy/trunk/doc/devel/howtosvn.txt ============================================================================== --- pypy/trunk/doc/devel/howtosvn.txt (original) +++ pypy/trunk/doc/devel/howtosvn.txt Sat May 29 01:05:57 2004 @@ -140,7 +140,7 @@ .. _website: http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B259403 .. _GUI: http://tortoisesvn.tigris.org/servlets/ProjectDocumentList?folderID=616 -.. _MacOS: http://codespeak.net/~jum/svn-1.0.1-darwin-ppc.tar.gz +.. _MacOS: http://codespeak.net/~jum/svn-1.0.4-darwin-ppc.tar.gz .. _versions: http://subversion.tigris.org/project_packages.html .. _Win: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4B6140F9-2D36-4977-8FA1-6F8A0F5DCA8F From alex at codespeak.net Mon May 31 10:38:23 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 10:38:23 +0200 (MEST) Subject: [pypy-svn] r4725 - pypy/trunk/src/pypy Message-ID: <20040531083823.47B785BE07@thoth.codespeak.net> Author: alex Date: Mon May 31 10:38:20 2004 New Revision: 4725 Modified: pypy/trunk/src/pypy/TODO Log: Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Mon May 31 10:38:20 2004 @@ -36,3 +36,4 @@ http://codespeak.net/pypy/index.cgi?doc/objspace/multimethod * enhance the translator components to accept more of PyPy ... + From alex at codespeak.net Mon May 31 10:38:40 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 10:38:40 +0200 (MEST) Subject: [pypy-svn] r4726 - pypy/trunk/src/pypy Message-ID: <20040531083840.867525BE07@thoth.codespeak.net> Author: alex Date: Mon May 31 10:38:39 2004 New Revision: 4726 Modified: pypy/trunk/src/pypy/TODO Log: Modified: pypy/trunk/src/pypy/TODO ============================================================================== --- pypy/trunk/src/pypy/TODO (original) +++ pypy/trunk/src/pypy/TODO Mon May 31 10:38:39 2004 @@ -36,4 +36,3 @@ http://codespeak.net/pypy/index.cgi?doc/objspace/multimethod * enhance the translator components to accept more of PyPy ... - From arigo at codespeak.net Mon May 31 12:29:58 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 12:29:58 +0200 (MEST) Subject: [pypy-svn] r4728 - pypy/trunk/src/pypy/module Message-ID: <20040531102958.C6FB65BE07@thoth.codespeak.net> Author: arigo Date: Mon May 31 12:29:58 2004 New Revision: 4728 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/__builtin__module.py Log: Jiwon's eval(). 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 Mon May 31 12:29:58 2004 @@ -92,6 +92,24 @@ raise OperationError(space.w_TypeError,space.wrap(str(e))) return space.wrap(PyCode()._from_code(c)) +def eval(w_source, w_globals=None, w_locals=None): + w = space.wrap + + if space.is_true(space.isinstance(w_source, space.w_str)): + w_codeobj = compile(w_source, w(""), w("eval")) + elif isinstance(space.unwrap(w_source), PyCode): + w_codeobj = w_source + else: + raise OperationError(space.w_TypeError, + w('eval() arg 1 must be a string or code object')) + + if w_globals is None: + w_globals = globals() + w_locals = locals() + elif w_locals is None: + w_locals = w_globals + + return space.unwrap(w_codeobj).exec_code(space, w_globals, w_locals) def abs(w_val): return space.abs(w_val) Modified: pypy/trunk/src/pypy/module/__builtin__module.py ============================================================================== --- pypy/trunk/src/pypy/module/__builtin__module.py (original) +++ pypy/trunk/src/pypy/module/__builtin__module.py Mon May 31 12:29:58 2004 @@ -427,7 +427,7 @@ from __interplevel__ import hash, oct, hex, round from __interplevel__ import getattr, setattr, delattr, iter, hash, id from __interplevel__ import issubclass, _pypy_get -from __interplevel__ import compile +from __interplevel__ import compile, eval from __interplevel__ import globals, locals, _caller_globals, _caller_locals from __interplevel__ import file From anna at codespeak.net Mon May 31 12:37:45 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 12:37:45 +0200 (MEST) Subject: [pypy-svn] r4729 - pypy/trunk/doc Message-ID: <20040531103745.5199C5BE08@thoth.codespeak.net> Author: anna Date: Mon May 31 12:37:44 2004 New Revision: 4729 Added: pypy/trunk/doc/optionaltools.txt pypy/trunk/doc/tasks.txt Log: optionaltools: notes on what tools to download and where to get them. tasks: notes on what tasks we want to accomplish for this sprint Added: pypy/trunk/doc/optionaltools.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/optionaltools.txt Mon May 31 12:37:44 2004 @@ -0,0 +1,21 @@ +In addition to svn, and Python, here are some optional tools to install for working on pypy. + +Recommended (Optional) tools: + +graphviz +(used for visualizing the postscript) +http://www.research.att.com/sw/tools/graphviz/download.html + +pygame +(recommended to call from Translator to visualize the control flow annotation) +http://www.pygame.org/download.shtml + +on MAC - TRY THIS: +package manager politus: alex will reconstruct + + +CLISP +Optional (if you want to work on generating lisp code from pypy) +http://clisp.cons.org/ + + Added: pypy/trunk/doc/tasks.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/tasks.txt Mon May 31 12:37:44 2004 @@ -0,0 +1,19 @@ +PyPy Tasks + +*Installing Pygame +*Annotation Translator +*Cleanup Pyrex Code Generator +*Intermediate Test cases (1 module, 1 class) +*Moving Test Framework (discussion) +*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) +*Fix Huge Tracebacks + -logging + -easy browsing + -moredetailed-butstructured + -connect TraceObjectSpace to Tracebacks (10min intro from holger) + +*Run py.py py.py +*Script on built-ins improve (use hasattr) + - proper introspection (not just for multi-methods) + - generate html status page for website +*Fix object model \ No newline at end of file From anna at codespeak.net Mon May 31 12:44:27 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 12:44:27 +0200 (MEST) Subject: [pypy-svn] r4730 - pypy/trunk/doc Message-ID: <20040531104427.793685BE09@thoth.codespeak.net> Author: anna Date: Mon May 31 12:44:26 2004 New Revision: 4730 Added: pypy/trunk/doc/gothsprinttasklist.txt Modified: pypy/trunk/doc/tasks.txt Log: renamed tasks.txt to gothsprinttasklist.txt Added: pypy/trunk/doc/gothsprinttasklist.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/gothsprinttasklist.txt Mon May 31 12:44:26 2004 @@ -0,0 +1,19 @@ +PyPy Gothenburg Sprint Tasks + +*Installing Pygame +*Annotation Translator +*Cleanup Pyrex Code Generator +*Intermediate Test cases (1 module, 1 class) +*Moving Test Framework (discussion) +*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) +*Fix Huge Tracebacks + -logging + -easy browsing + -moredetailed-butstructured + -connect TraceObjectSpace to Tracebacks (10min intro from holger) + +*Run py.py py.py +*Script on built-ins improve (use hasattr) + - proper introspection (not just for multi-methods) + - generate html status page for website +*Fix object model \ No newline at end of file Modified: pypy/trunk/doc/tasks.txt ============================================================================== --- pypy/trunk/doc/tasks.txt (original) +++ pypy/trunk/doc/tasks.txt Mon May 31 12:44:26 2004 @@ -1,4 +1,4 @@ -PyPy Tasks +PyPy Gothenburg Sprint Tasks *Installing Pygame *Annotation Translator From anna at codespeak.net Mon May 31 12:46:16 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 12:46:16 +0200 (MEST) Subject: [pypy-svn] r4731 - pypy/trunk/doc Message-ID: <20040531104616.6DB875BE09@thoth.codespeak.net> Author: anna Date: Mon May 31 12:46:15 2004 New Revision: 4731 Removed: pypy/trunk/doc/tasks.txt Log: removed tasks.txt,use gothsprinttasklist instead Deleted: /pypy/trunk/doc/tasks.txt ============================================================================== --- /pypy/trunk/doc/tasks.txt Mon May 31 12:46:15 2004 +++ (empty file) @@ -1,19 +0,0 @@ -PyPy Gothenburg Sprint Tasks - -*Installing Pygame -*Annotation Translator -*Cleanup Pyrex Code Generator -*Intermediate Test cases (1 module, 1 class) -*Moving Test Framework (discussion) -*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) -*Fix Huge Tracebacks - -logging - -easy browsing - -moredetailed-butstructured - -connect TraceObjectSpace to Tracebacks (10min intro from holger) - -*Run py.py py.py -*Script on built-ins improve (use hasattr) - - proper introspection (not just for multi-methods) - - generate html status page for website -*Fix object model \ No newline at end of file From anna at codespeak.net Mon May 31 13:09:24 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 13:09:24 +0200 (MEST) Subject: [pypy-svn] r4732 - pypy/trunk/doc Message-ID: <20040531110924.BCF405BE07@thoth.codespeak.net> Author: anna Date: Mon May 31 13:09:24 2004 New Revision: 4732 Modified: pypy/trunk/doc/gothsprinttasklist.txt Log: updated the sprint tasklist Modified: pypy/trunk/doc/gothsprinttasklist.txt ============================================================================== --- pypy/trunk/doc/gothsprinttasklist.txt (original) +++ pypy/trunk/doc/gothsprinttasklist.txt Mon May 31 13:09:24 2004 @@ -3,6 +3,8 @@ *Installing Pygame *Annotation Translator *Cleanup Pyrex Code Generator +*Import system hack +*Running large programs (write test cases) *Intermediate Test cases (1 module, 1 class) *Moving Test Framework (discussion) *Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) @@ -16,4 +18,5 @@ *Script on built-ins improve (use hasattr) - proper introspection (not just for multi-methods) - generate html status page for website -*Fix object model \ No newline at end of file +*Fix object model + From anna at codespeak.net Mon May 31 13:23:49 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 13:23:49 +0200 (MEST) Subject: [pypy-svn] r4733 - pypy/trunk/doc Message-ID: <20040531112349.ACF2B5BE0A@thoth.codespeak.net> Author: anna Date: Mon May 31 13:23:49 2004 New Revision: 4733 Modified: pypy/trunk/doc/gothsprinttasklist.txt Log: updated the sprint tasklist with who is starting on what Modified: pypy/trunk/doc/gothsprinttasklist.txt ============================================================================== --- pypy/trunk/doc/gothsprinttasklist.txt (original) +++ pypy/trunk/doc/gothsprinttasklist.txt Mon May 31 13:23:49 2004 @@ -1,13 +1,25 @@ PyPy Gothenburg Sprint Tasks -*Installing Pygame *Annotation Translator + -Anders and Armin + *Cleanup Pyrex Code Generator + -Holger + *Import system hack + -Alex and Samuele + *Running large programs (write test cases) -*Intermediate Test cases (1 module, 1 class) + +*Intermediate Test cases (1 module, 1 class) user classes + *Moving Test Framework (discussion) -*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) + - app level, Holger + - conversion scripts, Jacob + +*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) + - Anna + *Fix Huge Tracebacks -logging -easy browsing @@ -18,5 +30,6 @@ *Script on built-ins improve (use hasattr) - proper introspection (not just for multi-methods) - generate html status page for website + *Fix object model From arigo at codespeak.net Mon May 31 14:39:13 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 14:39:13 +0200 (MEST) Subject: [pypy-svn] r4736 - pypy/trunk/src/pypy/translator/test Message-ID: <20040531123913.556765BDB2@thoth.codespeak.net> Author: arigo Date: Mon May 31 14:39:12 2004 New Revision: 4736 Modified: pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py Log: Test for a bug. 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 May 31 14:39:12 2004 @@ -351,3 +351,10 @@ def prime(n): return len([i for i in range(1,n+1) if n%i==0]) == 2 + +def somebug1(n): + l = [] + v = l.append + while n: + l[7] = 5 + return v 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 May 31 14:39:12 2004 @@ -205,6 +205,12 @@ # result should be an integer self.assertEquals(s.knowntype, int) + def test_somebug1(self): + a = RPythonAnnotator() + s = a.build_types(snippet.somebug1, [int]) + # result should be a built-in method + self.assert_(isinstance(s, annmodel.SomeBuiltin)) + def g(n): return [0,1,2,n] From arigo at codespeak.net Mon May 31 14:40:44 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 14:40:44 +0200 (MEST) Subject: [pypy-svn] r4737 - pypy/trunk/src/pypy/objspace/std/test Message-ID: <20040531124044.70CAD5BDB2@thoth.codespeak.net> Author: arigo Date: Mon May 31 14:40:43 2004 New Revision: 4737 Modified: pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py Log: Test for bound and unbound method objects. Modified: pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py ============================================================================== --- pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py (original) +++ pypy/trunk/src/pypy/objspace/std/test/test_instmethobject.py Mon May 31 14:40:43 2004 @@ -19,5 +19,19 @@ self.assertRaises(TypeError, unboundMethod, 333) self.assertRaises(TypeError, unboundMethod, [1,2,3], 333) + def test_getBound(self): + def f(l,x): return l[x+1] + bound = _pypy_get(f, 'abcdef') # XXX replace with f.__get__() + self.assertEquals(bound(1), 'c') + self.assertRaises(TypeError, bound) + self.assertRaises(TypeError, bound, 2, 3) + def test_getUnbound(self): + def f(l,x): return l[x+1] + unbound = _pypy_get(f, None, str) # XXX replace with f.__get__() + self.assertEquals(unbound('abcdef', 2), 'd') + self.assertRaises(TypeError, unbound) + self.assertRaises(TypeError, unbound, 4) + self.assertRaises(TypeError, unbound, 4, 5) + if __name__ == '__main__': testit.main() From arigo at codespeak.net Mon May 31 14:41:51 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 14:41:51 +0200 (MEST) Subject: [pypy-svn] r4738 - pypy/trunk/src/pypy/annotation Message-ID: <20040531124151.083F05BE0A@thoth.codespeak.net> Author: arigo Date: Mon May 31 14:41:50 2004 New Revision: 4738 Modified: pypy/trunk/src/pypy/annotation/binaryop.py pypy/trunk/src/pypy/annotation/model.py pypy/trunk/src/pypy/annotation/unaryop.py Log: Fix for bug in revision 4736. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon May 31 14:41:50 2004 @@ -7,6 +7,7 @@ from pypy.annotation.model import SomeString, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod +from pypy.annotation.model import SomeBuiltin from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -25,7 +26,10 @@ class __extend__(pairtype(SomeObject, SomeObject)): def union((obj1, obj2)): - return SomeObject() + if obj1 == obj2: + return obj1 + else: + return SomeObject() def inplace_add((obj1, obj2)): return pair(obj1, obj2).add() # default @@ -161,6 +165,16 @@ return SomeInstance(basedef) +class __extend__(pairtype(SomeBuiltin, SomeBuiltin)): + + def union((bltn1, bltn2)): + if bltn1.analyser != bltn2.analyser: + return SomeObject() + else: + s_self = unionof(bltn1.s_self, bltn2.s_self) + return SomeBuiltin(bltn1.analyser, s_self) + + class __extend__(pairtype(SomeFunction, SomeFunction)): def union((fun1, fun2)): Modified: pypy/trunk/src/pypy/annotation/model.py ============================================================================== --- pypy/trunk/src/pypy/annotation/model.py (original) +++ pypy/trunk/src/pypy/annotation/model.py Mon May 31 14:41:50 2004 @@ -110,8 +110,9 @@ class SomeBuiltin(SomeObject): "Stands for a built-in function or method with special-cased analysis." knowntype = BuiltinFunctionType # == BuiltinMethodType - def __init__(self, analyser): + 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)." Modified: pypy/trunk/src/pypy/annotation/unaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/unaryop.py (original) +++ pypy/trunk/src/pypy/annotation/unaryop.py Mon May 31 14:41:50 2004 @@ -34,8 +34,9 @@ # a corresponding method to handle it if s_attr.is_constant() and isinstance(s_attr.const, str): attr = s_attr.const - if hasattr(obj, 'method_' + attr): - return SomeBuiltin(getattr(obj, 'method_' + attr)) + analyser = getattr(obj.__class__, 'method_' + attr, None) + if analyser is not None: + return SomeBuiltin(analyser, obj) return SomeObject() def classattribute(obj, classdef): @@ -115,11 +116,13 @@ class __extend__(SomeBuiltin): - def call(meth, args, kwds): + def call(bltn, args, kwds): # decode the arguments and forward the analysis of this builtin arglist = decode_simple_call(args, kwds) if arglist is not None: - return meth.analyser(*arglist) + if bltn.s_self is not None: + arglist.insert(0, bltn.s_self) + return bltn.analyser(*arglist) else: return SomeObject() From arigo at codespeak.net Mon May 31 14:48:18 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 14:48:18 +0200 (MEST) Subject: [pypy-svn] r4739 - pypy/trunk/src/pypy/annotation Message-ID: <20040531124818.7163F5BE0B@thoth.codespeak.net> Author: arigo Date: Mon May 31 14:48:17 2004 New Revision: 4739 Modified: pypy/trunk/src/pypy/annotation/binaryop.py Log: Union of two SomeIterators. Modified: pypy/trunk/src/pypy/annotation/binaryop.py ============================================================================== --- pypy/trunk/src/pypy/annotation/binaryop.py (original) +++ pypy/trunk/src/pypy/annotation/binaryop.py Mon May 31 14:48:17 2004 @@ -7,7 +7,7 @@ from pypy.annotation.model import SomeString, SomeList, SomeDict from pypy.annotation.model import SomeTuple, SomeImpossibleValue from pypy.annotation.model import SomeInstance, SomeFunction, SomeMethod -from pypy.annotation.model import SomeBuiltin +from pypy.annotation.model import SomeBuiltin, SomeIterator from pypy.annotation.model import unionof, set, setunion, missing_operation from pypy.annotation.factory import BlockedInference, getbookkeeper @@ -165,6 +165,12 @@ return SomeInstance(basedef) +class __extend__(pairtype(SomeIterator, SomeIterator)): + + def union((iter1, iter2)): + return SomeIterator(unionof(iter1.s_item, iter2.s_item)) + + class __extend__(pairtype(SomeBuiltin, SomeBuiltin)): def union((bltn1, bltn2)): From pedronis at codespeak.net Mon May 31 15:01:26 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 15:01:26 +0200 (MEST) Subject: [pypy-svn] r4741 - pypy/trunk/src/pypy/tool Message-ID: <20040531130126.C41445BE0B@thoth.codespeak.net> Author: pedronis Date: Mon May 31 15:01:26 2004 New Revision: 4741 Modified: pypy/trunk/src/pypy/tool/testit.py Log: added helper new_objspace Modified: pypy/trunk/src/pypy/tool/testit.py ============================================================================== --- pypy/trunk/src/pypy/tool/testit.py (original) +++ pypy/trunk/src/pypy/tool/testit.py Mon May 31 15:01:26 2004 @@ -291,6 +291,10 @@ raise TestSkip return option.objspace(name) +def new_objspace(name=''): + if name and Options.spacename and name != Options.spacename: + raise TestSkip + return option.objspace(name,_spacecache={}) class RegexFilterFunc: """ From pedronis at codespeak.net Mon May 31 15:02:32 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 15:02:32 +0200 (MEST) Subject: [pypy-svn] r4742 - in pypy/trunk/src/pypy/module/test: . impsubdir Message-ID: <20040531130232.6C1BB5BE0D@thoth.codespeak.net> Author: pedronis Date: Mon May 31 15:02:31 2004 New Revision: 4742 Added: pypy/trunk/src/pypy/module/test/impsubdir/ pypy/trunk/src/pypy/module/test/impsubdir/a.py pypy/trunk/src/pypy/module/test/test_import.py Log: start of tests for imports Added: pypy/trunk/src/pypy/module/test/impsubdir/a.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/a.py Mon May 31 15:02:31 2004 @@ -0,0 +1 @@ +# a.py Added: pypy/trunk/src/pypy/module/test/test_import.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/test_import.py Mon May 31 15:02:31 2004 @@ -0,0 +1,21 @@ +import autopath +from pypy.tool import testit + +class TestImport(testit.AppTestCase): + + def setUp(self): # interpreter-level + self.space = testit.new_objspace() + + def test_import_sys(self): + import sys + + def test_import_a(self): + import sys + sys.path.append('impsubdir') + import a + + +if __name__ == '__main__': + testit.main() + + From pedronis at codespeak.net Mon May 31 15:15:25 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 15:15:25 +0200 (MEST) Subject: [pypy-svn] r4745 - in pypy/trunk/src/pypy/module: . test test/impsubdir/pkg Message-ID: <20040531131525.B5EA65BD91@thoth.codespeak.net> Author: pedronis Date: Mon May 31 15:15:25 2004 New Revision: 4745 Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/ pypy/trunk/src/pypy/module/test/impsubdir/pkg/__init__.py Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/test/test_import.py Log: beginning of package import 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 Mon May 31 15:15:25 2004 @@ -32,6 +32,19 @@ return _actframe(position).getdictscope() +def try_import_mod(w_modulename,f): + w = space.wrap + if os.path.exists(f): + w_mod = space.wrap(Module(space, w_modulename)) + space.sys.setmodule(w_mod) + space.setattr(w_mod, w('__file__'), w(f)) + w_dict = space.getattr(w_mod, w('__dict__')) + execfile(w(f), w_dict, w_dict) + return w_mod + else: + return None + + def __import__(w_modulename, w_globals=None, w_locals=None, w_fromlist=None): modulename = space.unwrap(w_modulename) @@ -58,14 +71,17 @@ import os for path in space.unpackiterable(space.sys.w_path): f = os.path.join(space.unwrap(path), modulename + '.py') - if os.path.exists(f): - w_mod = space.wrap(Module(space, w_modulename)) - space.sys.setmodule(w_mod) - space.setattr(w_mod, w('__file__'), w(f)) - w_dict = space.getattr(w_mod, w('__dict__')) - execfile(w(f), w_dict, w_dict) + w_mod = try_import_mod(w_modulename,f) + if w_mod is not None: return w_mod - + dir = os.path.join(space.unwrap(path),modulename) + if not os.path.isdir(dir): + continue + f = os.path.join(dir,'__init__.py') + w_mod = try_import_mod(w_modulename,f) + if w_mod is not None: + return w_mod + w_exc = space.call_function(space.w_ImportError, w_modulename) raise OperationError(space.w_ImportError, w_exc) Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/__init__.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/__init__.py Mon May 31 15:15:25 2004 @@ -0,0 +1 @@ +# package 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 Mon May 31 15:15:25 2004 @@ -13,7 +13,13 @@ import sys sys.path.append('impsubdir') import a + self.assert_('a' in sys.modules) + def test_import_pkg(self): + import sys + sys.path.append('impsubdir') + import pkg + self.assert_('pkg' in sys.modules) if __name__ == '__main__': testit.main() From pedronis at codespeak.net Mon May 31 15:18:36 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 15:18:36 +0200 (MEST) Subject: [pypy-svn] r4746 - pypy/trunk/src/pypy/module/test Message-ID: <20040531131836.7A02C5BD91@thoth.codespeak.net> Author: pedronis Date: Mon May 31 15:18:35 2004 New Revision: 4746 Modified: pypy/trunk/src/pypy/module/test/test_import.py Log: tests that bare dirs are not considered packages and are not imported 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 Mon May 31 15:18:35 2004 @@ -15,6 +15,11 @@ import a self.assert_('a' in sys.modules) + def test_import_bare_dir_fails(self): + def imp(): + import impsubdir + self.assertRaises(ImportError,imp) + def test_import_pkg(self): import sys sys.path.append('impsubdir') From anna at codespeak.net Mon May 31 15:27:55 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 15:27:55 +0200 (MEST) Subject: [pypy-svn] r4747 - pypy/trunk/doc Message-ID: <20040531132755.A05ED5BE0C@thoth.codespeak.net> Author: anna Date: Mon May 31 15:27:54 2004 New Revision: 4747 Added: pypy/trunk/doc/index.txt Modified: pypy/trunk/doc/gothsprinttasklist.txt Log: adding index.txt and fixing the rest code on gothsprinttasklist.txt Modified: pypy/trunk/doc/gothsprinttasklist.txt ============================================================================== --- pypy/trunk/doc/gothsprinttasklist.txt (original) +++ pypy/trunk/doc/gothsprinttasklist.txt Mon May 31 15:27:54 2004 @@ -1,35 +1,36 @@ PyPy Gothenburg Sprint Tasks +============================ -*Annotation Translator - -Anders and Armin +* Annotation Translator + - Anders and Armin -*Cleanup Pyrex Code Generator - -Holger +* Cleanup Pyrex Code Generator + - Holger -*Import system hack - -Alex and Samuele +* Import system hack + - Alex and Samuele -*Running large programs (write test cases) +* Running large programs (write test cases) -*Intermediate Test cases (1 module, 1 class) user classes +* Intermediate Test cases (1 module, 1 class) user classes -*Moving Test Framework (discussion) +* Moving Test Framework (discussion) - app level, Holger - conversion scripts, Jacob -*Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about ohter projects) +* Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about other projects) - Anna -*Fix Huge Tracebacks - -logging - -easy browsing - -moredetailed-butstructured - -connect TraceObjectSpace to Tracebacks (10min intro from holger) +* Fix Huge Tracebacks + - logging + - easy browsing + - moredetailed-butstructured + - connect TraceObjectSpace to Tracebacks (10min intro from holger) -*Run py.py py.py -*Script on built-ins improve (use hasattr) +* Run py.py py.py +* Script on built-ins improve (use hasattr) - proper introspection (not just for multi-methods) - generate html status page for website -*Fix object model +* Fix object model Added: pypy/trunk/doc/index.txt ============================================================================== --- (empty file) +++ pypy/trunk/doc/index.txt Mon May 31 15:27:54 2004 @@ -0,0 +1,4 @@ +Pypy Documentation Tree +======================= + +No contents available yet. \ No newline at end of file From anna at codespeak.net Mon May 31 15:48:37 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 15:48:37 +0200 (MEST) Subject: [pypy-svn] r4749 - pypy/trunk/doc Message-ID: <20040531134837.599175BE11@thoth.codespeak.net> Author: anna Date: Mon May 31 15:48:36 2004 New Revision: 4749 Removed: pypy/trunk/doc/gothsprinttasklist.txt Log: removed the tasklist. it is now under the sprint wiki where it belongs. Deleted: /pypy/trunk/doc/gothsprinttasklist.txt ============================================================================== --- /pypy/trunk/doc/gothsprinttasklist.txt Mon May 31 15:48:36 2004 +++ (empty file) @@ -1,36 +0,0 @@ -PyPy Gothenburg Sprint Tasks -============================ - -* Annotation Translator - - Anders and Armin - -* Cleanup Pyrex Code Generator - - Holger - -* Import system hack - - Alex and Samuele - -* Running large programs (write test cases) - -* Intermediate Test cases (1 module, 1 class) user classes - -* Moving Test Framework (discussion) - - app level, Holger - - conversion scripts, Jacob - -* Documentation (Intro to pypy page with explanations, not just links, and comparisons to discussions about other projects) - - Anna - -* Fix Huge Tracebacks - - logging - - easy browsing - - moredetailed-butstructured - - connect TraceObjectSpace to Tracebacks (10min intro from holger) - -* Run py.py py.py -* Script on built-ins improve (use hasattr) - - proper introspection (not just for multi-methods) - - generate html status page for website - -* Fix object model - From arigo at codespeak.net Mon May 31 15:50:51 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 15:50:51 +0200 (MEST) Subject: [pypy-svn] r4750 - in pypy/trunk/src/pypy: annotation translator translator/test Message-ID: <20040531135051.F29915BE11@thoth.codespeak.net> Author: arigo Date: Mon May 31 15:50:51 2004 New Revision: 4750 Modified: pypy/trunk/src/pypy/annotation/factory.py pypy/trunk/src/pypy/translator/annrpython.py pypy/trunk/src/pypy/translator/test/snippet.py Log: Some new support code... Modified: pypy/trunk/src/pypy/annotation/factory.py ============================================================================== --- pypy/trunk/src/pypy/annotation/factory.py (original) +++ pypy/trunk/src/pypy/annotation/factory.py Mon May 31 15:50:51 2004 @@ -38,6 +38,7 @@ self.annotator = annotator self.creationpoints = {} # map positions-in-blocks to Factories self.userclasses = {} # map classes to ClassDefs + self.userclasseslist = []# userclasses.keys() in creation order def enter(self, position_key): """Start of an operation. @@ -81,7 +82,9 @@ try: return self.userclasses[cls] except KeyError: - self.userclasses[cls] = ClassDef(cls, self) + cdef = ClassDef(cls, self) + self.userclasses[cls] = cdef + self.userclasseslist.append(cdef) return self.userclasses[cls] Modified: pypy/trunk/src/pypy/translator/annrpython.py ============================================================================== --- pypy/trunk/src/pypy/translator/annrpython.py (original) +++ pypy/trunk/src/pypy/translator/annrpython.py Mon May 31 15:50:51 2004 @@ -73,6 +73,10 @@ """Return a set of known user classes.""" return self.bookkeeper.userclasses + def getuserclassdefinitions(self): + """Return a list of ClassDefs.""" + return self.bookkeeper.userclasseslist + def getuserattributes(self, cls): """Enumerate the attributes of the given user class, as Variable()s.""" clsdef = self.bookkeeper.userclasses[cls] 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 May 31 15:50:51 2004 @@ -314,12 +314,15 @@ lst = [d, e] return d.stuff, e.stuff +def getstuff(x): + return x.stuff + def inheritance2(): d = D() d.stuff = (-12, -12) e = E() e.stuff = (3, "world") - return C().stuff + return getstuff(d), getstuff(e) class F: pass From ale at codespeak.net Mon May 31 15:57:54 2004 From: ale at codespeak.net (ale at codespeak.net) Date: Mon, 31 May 2004 15:57:54 +0200 (MEST) Subject: [pypy-svn] r4751 - pypy/trunk/src/pypy/translator Message-ID: <20040531135754.87A915BE12@thoth.codespeak.net> Author: ale Date: Mon May 31 15:57:53 2004 New Revision: 4751 Modified: pypy/trunk/src/pypy/translator/genpyrex.py Log: Class inheritance and more effective attribute lookup Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Mon May 31 15:57:53 2004 @@ -233,14 +233,17 @@ def _paramvardecl(self, var): vartype = self.get_type(var) + ctype=self._gettypename(vartype) + return (ctype, self.get_varname(var)) + + def _gettypename(self, vartype): if vartype in (int, bool): ctype = "int" elif self.annotator and vartype in self.annotator.getuserclasses(): ctype = self.get_classname(vartype) else: ctype = "object" - - return (ctype, self.get_varname(var)) + return ctype def get_classname(self, userclass): return userclass.__name__ @@ -332,14 +335,17 @@ if self.annotator: self.lines = [] self.indent = 0 - for cls in self.annotator.getuserclasses(): - self.putline("cdef class %s:" % self.get_classname(cls)) + for cls in self.annotator.getuserclassdefinitions(): + if cls.basedef: + bdef="(%s)" % (self.get_classname(cls.basedef)) + else: + bdef="" + self.putline("cdef class %s%s:" % (self.get_classname(cls.cls),bdef)) self.indent += 1 empty = True - for var in self.annotator.getuserattributes(cls): - vartype, varname = self._paramvardecl(var) - varname = var.name # no 'i_' prefix - self.putline("cdef %s %s" % (vartype, varname)) + for attr,s_value in cls.attrs.items(): + vartype=self._gettypename(s_value.knowntype) + self.putline("cdef public %s %s" % (vartype, attr)) empty = False else: if empty: From anna at codespeak.net Mon May 31 15:59:22 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 15:59:22 +0200 (MEST) Subject: [pypy-svn] r4752 - pypy/trunk/doc Message-ID: <20040531135922.ED1085BE13@thoth.codespeak.net> Author: anna Date: Mon May 31 15:59:22 2004 New Revision: 4752 Modified: pypy/trunk/doc/optionaltools.txt Log: did rest formatting for the optional tools file Modified: pypy/trunk/doc/optionaltools.txt ============================================================================== --- pypy/trunk/doc/optionaltools.txt (original) +++ pypy/trunk/doc/optionaltools.txt Mon May 31 15:59:22 2004 @@ -1,21 +1,25 @@ +Optional Tools for Pypy sprinting: +================================== + In addition to svn, and Python, here are some optional tools to install for working on pypy. Recommended (Optional) tools: +----------------------------- -graphviz -(used for visualizing the postscript) -http://www.research.att.com/sw/tools/graphviz/download.html -pygame -(recommended to call from Translator to visualize the control flow annotation) -http://www.pygame.org/download.shtml +* graphviz:: + (used for visualizing the postscript) + http://www.research.att.com/sw/tools/graphviz/download.html_ -on MAC - TRY THIS: -package manager politus: alex will reconstruct +* pygame:: + (recommended to call from Translator to visualize the control flow annotation) + http://www.pygame.org/download.shtml_ + - on MAC OSX, TRY THIS:: + Alex will reconstruct the process for us -CLISP -Optional (if you want to work on generating lisp code from pypy) -http://clisp.cons.org/ +* CLISP + Optional (if you want to work on generating lisp code from pypy) + http://clisp.cons.org/_ From ale at codespeak.net Mon May 31 15:59:40 2004 From: ale at codespeak.net (ale at codespeak.net) Date: Mon, 31 May 2004 15:59:40 +0200 (MEST) Subject: [pypy-svn] r4753 - pypy/trunk/src/pypy/translator Message-ID: <20040531135940.738515BE14@thoth.codespeak.net> Author: ale Date: Mon May 31 15:59:39 2004 New Revision: 4753 Modified: pypy/trunk/src/pypy/translator/genpyrex.py Log: bug fix Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Mon May 31 15:59:39 2004 @@ -337,7 +337,7 @@ self.indent = 0 for cls in self.annotator.getuserclassdefinitions(): if cls.basedef: - bdef="(%s)" % (self.get_classname(cls.basedef)) + bdef="(%s)" % (self.get_classname(cls.basedef.cls)) else: bdef="" self.putline("cdef class %s%s:" % (self.get_classname(cls.cls),bdef)) From anna at codespeak.net Mon May 31 16:02:16 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 16:02:16 +0200 (MEST) Subject: [pypy-svn] r4754 - pypy/trunk/doc Message-ID: <20040531140216.B05125BE15@thoth.codespeak.net> Author: anna Date: Mon May 31 16:02:16 2004 New Revision: 4754 Modified: pypy/trunk/doc/optionaltools.txt Log: fixed rest formatting for the optional tools file Modified: pypy/trunk/doc/optionaltools.txt ============================================================================== --- pypy/trunk/doc/optionaltools.txt (original) +++ pypy/trunk/doc/optionaltools.txt Mon May 31 16:02:16 2004 @@ -1,24 +1,29 @@ Optional Tools for Pypy sprinting: ================================== -In addition to svn, and Python, here are some optional tools to install for working on pypy. +In addition to the latest version of svn, and (of course!) Python, here are some optional tools to install for working on pypy. -Recommended (Optional) tools: +Recommended tools: ----------------------------- - -* graphviz:: - (used for visualizing the postscript) - http://www.research.att.com/sw/tools/graphviz/download.html_ - * pygame:: + (recommended to call from Translator to visualize the control flow annotation) http://www.pygame.org/download.shtml_ - on MAC OSX, TRY THIS:: Alex will reconstruct the process for us -* CLISP +* graphviz:: + + (used for visualizing the postscript) + http://www.research.att.com/sw/tools/graphviz/download.html_ + +Optional tools: +--------------- + +* CLISP:: + Optional (if you want to work on generating lisp code from pypy) http://clisp.cons.org/_ From arigo at codespeak.net Mon May 31 16:13:35 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 16:13:35 +0200 (MEST) Subject: [pypy-svn] r4755 - pypy/trunk/src/pypy/translator/test Message-ID: <20040531141335.6F4535BE10@thoth.codespeak.net> Author: arigo Date: Mon May 31 16:13:34 2004 New Revision: 4755 Added: pypy/trunk/src/pypy/translator/test/test_translator.py Modified: pypy/trunk/src/pypy/translator/test/test_pyrextrans.py Log: Started a new test file for bigger (multi-functions) tests. 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 Mon May 31 16:13:34 2004 @@ -83,25 +83,5 @@ self.assertEquals(sand(0, 6), "no") self.assertEquals(sand(0, 0), "no") -class TypedPyrexGenTestCase(NoTypePyrexGenTestCase): - - def build_cfunc(self, func): - try: func = func.im_func - except AttributeError: pass - - dot = testit.Options.verbose >0 and 1 or 0 - options = { - 'simplify' : 1, - 'dot' : dot, - 'inputargtypes' : [int] * func.func_code.co_argcount - } - return build_cfunc(func, **options) - - # _______________________________________________________ - # The following tests require the type inference to work. - def test_set_attr(self): - set_attr = self.build_cfunc(t.set_attr) - self.assertEquals(set_attr(), 2) - if __name__ == '__main__': testit.main() Added: pypy/trunk/src/pypy/translator/test/test_translator.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/translator/test/test_translator.py Mon May 31 16:13:34 2004 @@ -0,0 +1,23 @@ +import autopath +from pypy.tool import testit +from pypy.translator.translator import Translator + +from pypy.translator.test import snippet + + +class TranslatorTestCase(testit.IntTestCase): + + def test_set_attr(self): + t = Translator(snippet.set_attr) + t.annotate([]) + set_attr = t.compile() + self.assertEquals(set_attr(), 2) + + def test_inheritance2(self): + t = Translator(snippet.inheritance2) + t.annotate([]) + inheritance2 = t.compile() + self.assertEquals(inheritance2(), ((-12, -12), (3, "world"))) + +if __name__ == '__main__': + testit.main() From pedronis at codespeak.net Mon May 31 16:22:20 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 16:22:20 +0200 (MEST) Subject: [pypy-svn] r4757 - in pypy/trunk/src/pypy/module: . test test/impsubdir/pkg test/impsubdir/pkg/pkg1 Message-ID: <20040531142220.5D9EC5BE49@thoth.codespeak.net> Author: pedronis Date: Mon May 31 16:22:19 2004 New Revision: 4757 Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/ pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/__init__.py pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/a.py Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/test/test_import.py Log: dotted package imports 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 Mon May 31 16:22:19 2004 @@ -32,18 +32,30 @@ return _actframe(position).getdictscope() -def try_import_mod(w_modulename,f): +def try_import_mod(w_modulename,f,pkgdir=None): w = space.wrap if os.path.exists(f): w_mod = space.wrap(Module(space, w_modulename)) space.sys.setmodule(w_mod) space.setattr(w_mod, w('__file__'), w(f)) + if pkgdir is not None: + space.setattr(w_mod,w('__path__'),space.newlist([w(pkgdir)])) w_dict = space.getattr(w_mod, w('__dict__')) execfile(w(f), w_dict, w_dict) return w_mod else: return None +def check_sys_modules(w_modulename): + try: + w_mod = space.getitem(space.sys.w_modules, w_modulename) + except OperationError,e: + pass + else: + return w_mod + if not e.match(space, space.w_KeyError): + raise + return None def __import__(w_modulename, w_globals=None, w_locals=None, w_fromlist=None): @@ -56,34 +68,62 @@ raise OperationError(space.w_TypeError, space.wrap("__import__() argument 1 must be string" + helper)) w = space.wrap - try: - w_mod = space.getitem(space.sys.w_modules, w_modulename) - except OperationError,e: - pass - else: + w_mod = check_sys_modules(w_modulename) + if w_mod is not None: return w_mod - if not e.match(space, space.w_KeyError): - raise + w_mod = space.get_builtin_module(modulename) if w_mod is not None: return w_mod import os - for path in space.unpackiterable(space.sys.w_path): - f = os.path.join(space.unwrap(path), modulename + '.py') + + parts = modulename.split('.') + prefix = [] + w_path = space.sys.w_path + + first = None + + for part in parts: + w_mod = load_part(w_path,prefix,part) + if w_mod is None: + # ImportError + w_failing = w('.'.join(prefix+[part])) + w_exc = space.call_function(space.w_ImportError, w_failing) + raise OperationError(space.w_ImportError, w_exc) + if first is None: + first = w_mod + prefix.append(part) + try: + w_path = space.getattr(w_mod,w('__path__')) + except OperationError,e: + if not e.match(space, space.w_AttributeError): + raise + w_path = None + + return first + +def load_part(w_path,prefix,partname): + w = space.wrap + w_modulename = w('.'.join(prefix+[partname])) + w_mod = check_sys_modules(w_modulename) + if w_mod is not None: + return w_mod + + for path in space.unpackiterable(w_path): + f = os.path.join(space.unwrap(path), partname + '.py') w_mod = try_import_mod(w_modulename,f) if w_mod is not None: return w_mod - dir = os.path.join(space.unwrap(path),modulename) + dir = os.path.join(space.unwrap(path),partname) if not os.path.isdir(dir): continue f = os.path.join(dir,'__init__.py') - w_mod = try_import_mod(w_modulename,f) + w_mod = try_import_mod(w_modulename,f,pkgdir=dir) if w_mod is not None: return w_mod - - w_exc = space.call_function(space.w_ImportError, w_modulename) - raise OperationError(space.w_ImportError, w_exc) + + return None def compile(w_str, w_filename, w_startstr, Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py Mon May 31 16:22:19 2004 @@ -0,0 +1 @@ +# a.py Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/__init__.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/__init__.py Mon May 31 16:22:19 2004 @@ -0,0 +1 @@ +# package Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/a.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/a.py Mon May 31 16:22:19 2004 @@ -0,0 +1 @@ +# a.py 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 Mon May 31 16:22:19 2004 @@ -26,6 +26,21 @@ import pkg self.assert_('pkg' in sys.modules) + def test_import_dotted(self): + import sys + sys.path.append('impsubdir') + import pkg.a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + + def test_import_dotted2(self): + import sys + sys.path.append('impsubdir') + import pkg.pkg1.a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.pkg1' in sys.modules) + self.assert_('pkg.pkg1.a' in sys.modules) + if __name__ == '__main__': testit.main() From alex at codespeak.net Mon May 31 16:30:19 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 16:30:19 +0200 (MEST) Subject: [pypy-svn] r4759 - in pypy/trunk/src/pypy/module: . test test/impsubdir test/impsubdir/ambig Message-ID: <20040531143019.D73EC5B7CC@thoth.codespeak.net> Author: alex Date: Mon May 31 16:30:19 2004 New Revision: 4759 Added: pypy/trunk/src/pypy/module/test/impsubdir/ambig/ pypy/trunk/src/pypy/module/test/impsubdir/ambig.py pypy/trunk/src/pypy/module/test/impsubdir/ambig/__init__.py Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/test/test_import.py Log: On import, package must shadow module if both exist under the same directory of sys.path 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 Mon May 31 16:30:19 2004 @@ -111,15 +111,14 @@ return w_mod for path in space.unpackiterable(w_path): + dir = os.path.join(space.unwrap(path), partname) + if os.path.isdir(dir): + f = os.path.join(dir,'__init__.py') + w_mod = try_import_mod(w_modulename, f, pkgdir=dir) + if w_mod is not None: + return w_mod f = os.path.join(space.unwrap(path), partname + '.py') - w_mod = try_import_mod(w_modulename,f) - if w_mod is not None: - return w_mod - dir = os.path.join(space.unwrap(path),partname) - if not os.path.isdir(dir): - continue - f = os.path.join(dir,'__init__.py') - w_mod = try_import_mod(w_modulename,f,pkgdir=dir) + w_mod = try_import_mod(w_modulename, f) if w_mod is not None: return w_mod Added: pypy/trunk/src/pypy/module/test/impsubdir/ambig.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/ambig.py Mon May 31 16:30:19 2004 @@ -0,0 +1 @@ +imamodule = 1 Added: pypy/trunk/src/pypy/module/test/impsubdir/ambig/__init__.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/ambig/__init__.py Mon May 31 16:30:19 2004 @@ -0,0 +1 @@ +imapackage = 1 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 Mon May 31 16:30:19 2004 @@ -40,7 +40,14 @@ self.assert_('pkg' in sys.modules) self.assert_('pkg.pkg1' in sys.modules) self.assert_('pkg.pkg1.a' in sys.modules) - + + def test_import_ambig(self): + import sys + sys.path.append('impsubdir') + import ambig + self.assert_('ambig' in sys.modules) + self.assert_(hasattr(ambig,'imapackage')) + if __name__ == '__main__': testit.main() From alex at codespeak.net Mon May 31 16:39:49 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 16:39:49 +0200 (MEST) Subject: [pypy-svn] r4761 - in pypy/trunk/src/pypy/module/test: . impsubdir impsubdir/pkg Message-ID: <20040531143949.61D2B5BDD6@thoth.codespeak.net> Author: alex Date: Mon May 31 16:39:48 2004 New Revision: 4761 Modified: pypy/trunk/src/pypy/module/test/impsubdir/a.py pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py pypy/trunk/src/pypy/module/test/test_import.py Log: start testing the from statement Modified: pypy/trunk/src/pypy/module/test/impsubdir/a.py ============================================================================== --- pypy/trunk/src/pypy/module/test/impsubdir/a.py (original) +++ pypy/trunk/src/pypy/module/test/impsubdir/a.py Mon May 31 16:39:48 2004 @@ -1 +1,2 @@ # a.py +imamodule = 1 Modified: pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py ============================================================================== --- pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py (original) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py Mon May 31 16:39:48 2004 @@ -1 +1,2 @@ # a.py +imamodule = 1 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 Mon May 31 16:39:48 2004 @@ -47,8 +47,21 @@ import ambig self.assert_('ambig' in sys.modules) self.assert_(hasattr(ambig,'imapackage')) - -if __name__ == '__main__': - testit.main() + def test_from_a(self): + import sys + sys.path.append('impsubdir') + from a import imamodule + self.assert_('a' in sys.modules) + self.assertEquals(imamodule, 1) + + def test_from_dotted(self): + import sys + sys.path.append('impsubdir') + from pkg.a import imamodule + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + self.assertEquals(imamodule, 1) +if __name__ == '__main__': + testit.main() From hpk at codespeak.net Mon May 31 16:43:13 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 31 May 2004 16:43:13 +0200 (MEST) Subject: [pypy-svn] r4762 - in pypy/trunk/doc: . devel Message-ID: <20040531144313.11C165BE0F@thoth.codespeak.net> Author: hpk Date: Mon May 31 16:43:13 2004 New Revision: 4762 Added: pypy/trunk/doc/devel/optionaltool.txt - copied, changed from r4759, pypy/trunk/doc/optionaltools.txt Removed: pypy/trunk/doc/optionaltools.txt Log: reworked optionaltools a bit and moved it to devel ... Copied: pypy/trunk/doc/devel/optionaltool.txt (from r4759, pypy/trunk/doc/optionaltools.txt) ============================================================================== --- pypy/trunk/doc/optionaltools.txt (original) +++ pypy/trunk/doc/devel/optionaltool.txt Mon May 31 16:43:13 2004 @@ -1,24 +1,27 @@ -Optional Tools for Pypy sprinting: -================================== +Optional Tools for running (and hacking) PyPy +============================================= -In addition to the latest version of svn, and (of course!) Python, here are some optional tools to install for working on pypy. +In addition to the latest version of svn and Python, we use some optional +tools to install for working on pypy. They are not required to run all the +tests or to get an interactive PyPy prompt but they help to understand and +debug PyPy. Recommended tools: ------------------------------ +------------------ + +* graphviz:: + + (used for visualizing the control-flow) + http://www.research.att.com/sw/tools/graphviz/download.html_ * pygame:: - (recommended to call from Translator to visualize the control flow annotation) + (to visualize control flow and annotation analysis of python programs) http://www.pygame.org/download.shtml_ - on MAC OSX, TRY THIS:: Alex will reconstruct the process for us -* graphviz:: - - (used for visualizing the postscript) - http://www.research.att.com/sw/tools/graphviz/download.html_ - Optional tools: --------------- Deleted: /pypy/trunk/doc/optionaltools.txt ============================================================================== --- /pypy/trunk/doc/optionaltools.txt Mon May 31 16:43:13 2004 +++ (empty file) @@ -1,30 +0,0 @@ -Optional Tools for Pypy sprinting: -================================== - -In addition to the latest version of svn, and (of course!) Python, here are some optional tools to install for working on pypy. - -Recommended tools: ------------------------------ - -* pygame:: - - (recommended to call from Translator to visualize the control flow annotation) - http://www.pygame.org/download.shtml_ - - - on MAC OSX, TRY THIS:: - Alex will reconstruct the process for us - -* graphviz:: - - (used for visualizing the postscript) - http://www.research.att.com/sw/tools/graphviz/download.html_ - -Optional tools: ---------------- - -* CLISP:: - - Optional (if you want to work on generating lisp code from pypy) - http://clisp.cons.org/_ - - From alex at codespeak.net Mon May 31 16:44:24 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 16:44:24 +0200 (MEST) Subject: [pypy-svn] r4763 - pypy/trunk/src/pypy/module Message-ID: <20040531144424.989405BE4D@thoth.codespeak.net> Author: alex Date: Mon May 31 16:44:24 2004 New Revision: 4763 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py Log: fixed: from pkg.module import something 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 Mon May 31 16:44:24 2004 @@ -101,7 +101,10 @@ raise w_path = None - return first + if w_fromlist is not None and space.is_true(w_fromlist): + return w_mod + else: + return first def load_part(w_path,prefix,partname): w = space.wrap From alex at codespeak.net Mon May 31 16:46:56 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 16:46:56 +0200 (MEST) Subject: [pypy-svn] r4764 - pypy/trunk/src/pypy/module/test Message-ID: <20040531144656.4DCA35BD83@thoth.codespeak.net> Author: alex Date: Mon May 31 16:46:55 2004 New Revision: 4764 Modified: pypy/trunk/src/pypy/module/test/test_import.py Log: added failing test for 'from package import module' 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 Mon May 31 16:46:55 2004 @@ -63,5 +63,13 @@ self.assert_('pkg.a' in sys.modules) self.assertEquals(imamodule, 1) + def test_from_pkg_import_module(self): + import sys + sys.path.append('impsubdir') + from pkg import a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + self.assert_(hasattr(a, 'imamodule')) + if __name__ == '__main__': testit.main() From hpk at codespeak.net Mon May 31 17:01:36 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 31 May 2004 17:01:36 +0200 (MEST) Subject: [pypy-svn] r4765 - in pypy/trunk/src/pypy/module/test: . impsubdir impsubdir/ambig impsubdir/pkg impsubdir/pkg/pkg1 Message-ID: <20040531150136.770EA5BD83@thoth.codespeak.net> Author: hpk Date: Mon May 31 17:01:35 2004 New Revision: 4765 Modified: pypy/trunk/src/pypy/module/test/impsubdir/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/a.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/ambig/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/ambig.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/ambig/__init__.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/__init__.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/ (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/__init__.py (props changed) pypy/trunk/src/pypy/module/test/impsubdir/pkg/pkg1/a.py (props changed) pypy/trunk/src/pypy/module/test/test_import.py (contents, props changed) Log: fixeol + fixtabbing of test_import 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 Mon May 31 17:01:35 2004 @@ -3,73 +3,73 @@ class TestImport(testit.AppTestCase): - def setUp(self): # interpreter-level - self.space = testit.new_objspace() + def setUp(self): # interpreter-level + self.space = testit.new_objspace() - def test_import_sys(self): - import sys + def test_import_sys(self): + import sys - def test_import_a(self): - import sys - sys.path.append('impsubdir') - import a - self.assert_('a' in sys.modules) - - def test_import_bare_dir_fails(self): - def imp(): - import impsubdir - self.assertRaises(ImportError,imp) - - def test_import_pkg(self): - import sys - sys.path.append('impsubdir') - import pkg - self.assert_('pkg' in sys.modules) - - def test_import_dotted(self): - import sys - sys.path.append('impsubdir') - import pkg.a - self.assert_('pkg' in sys.modules) - self.assert_('pkg.a' in sys.modules) - - def test_import_dotted2(self): - import sys - sys.path.append('impsubdir') - import pkg.pkg1.a - self.assert_('pkg' in sys.modules) - self.assert_('pkg.pkg1' in sys.modules) - self.assert_('pkg.pkg1.a' in sys.modules) - - def test_import_ambig(self): - import sys - sys.path.append('impsubdir') - import ambig - self.assert_('ambig' in sys.modules) - self.assert_(hasattr(ambig,'imapackage')) - - def test_from_a(self): - import sys - sys.path.append('impsubdir') - from a import imamodule - self.assert_('a' in sys.modules) - self.assertEquals(imamodule, 1) - - def test_from_dotted(self): - import sys - sys.path.append('impsubdir') - from pkg.a import imamodule - self.assert_('pkg' in sys.modules) - self.assert_('pkg.a' in sys.modules) - self.assertEquals(imamodule, 1) - - def test_from_pkg_import_module(self): - import sys - sys.path.append('impsubdir') - from pkg import a - self.assert_('pkg' in sys.modules) - self.assert_('pkg.a' in sys.modules) - self.assert_(hasattr(a, 'imamodule')) + def test_import_a(self): + import sys + sys.path.append('impsubdir') + import a + self.assert_('a' in sys.modules) + + def test_import_bare_dir_fails(self): + def imp(): + import impsubdir + self.assertRaises(ImportError,imp) + + def test_import_pkg(self): + import sys + sys.path.append('impsubdir') + import pkg + self.assert_('pkg' in sys.modules) + + def test_import_dotted(self): + import sys + sys.path.append('impsubdir') + import pkg.a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + + def test_import_dotted2(self): + import sys + sys.path.append('impsubdir') + import pkg.pkg1.a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.pkg1' in sys.modules) + self.assert_('pkg.pkg1.a' in sys.modules) + + def test_import_ambig(self): + import sys + sys.path.append('impsubdir') + import ambig + self.assert_('ambig' in sys.modules) + self.assert_(hasattr(ambig,'imapackage')) + + def test_from_a(self): + import sys + sys.path.append('impsubdir') + from a import imamodule + self.assert_('a' in sys.modules) + self.assertEquals(imamodule, 1) + + def test_from_dotted(self): + import sys + sys.path.append('impsubdir') + from pkg.a import imamodule + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + self.assertEquals(imamodule, 1) + + def test_from_pkg_import_module(self): + import sys + sys.path.append('impsubdir') + from pkg import a + self.assert_('pkg' in sys.modules) + self.assert_('pkg.a' in sys.modules) + self.assert_(hasattr(a, 'imamodule')) if __name__ == '__main__': testit.main() From alex at codespeak.net Mon May 31 17:22:37 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 17:22:37 +0200 (MEST) Subject: [pypy-svn] r4766 - in pypy/trunk/src/pypy/module: . test Message-ID: <20040531152237.935C75BE4C@thoth.codespeak.net> Author: alex Date: Mon May 31 17:22:36 2004 New Revision: 4766 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/test/test_import.py Log: stricter tests 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 Mon May 31 17:22:36 2004 @@ -32,14 +32,14 @@ return _actframe(position).getdictscope() -def try_import_mod(w_modulename,f,pkgdir=None): +def try_import_mod(w_modulename, f, pkgdir=None): w = space.wrap if os.path.exists(f): w_mod = space.wrap(Module(space, w_modulename)) space.sys.setmodule(w_mod) space.setattr(w_mod, w('__file__'), w(f)) if pkgdir is not None: - space.setattr(w_mod,w('__path__'),space.newlist([w(pkgdir)])) + space.setattr(w_mod, w('__path__'), space.newlist([w(pkgdir)])) w_dict = space.getattr(w_mod, w('__dict__')) execfile(w(f), w_dict, w_dict) return w_mod @@ -49,7 +49,7 @@ def check_sys_modules(w_modulename): try: w_mod = space.getitem(space.sys.w_modules, w_modulename) - except OperationError,e: + except OperationError, e: pass else: return w_mod @@ -85,7 +85,7 @@ first = None for part in parts: - w_mod = load_part(w_path,prefix,part) + w_mod = load_part(w_path, prefix, part) if w_mod is None: # ImportError w_failing = w('.'.join(prefix+[part])) @@ -95,24 +95,26 @@ first = w_mod prefix.append(part) try: - w_path = space.getattr(w_mod,w('__path__')) - except OperationError,e: + w_path = space.getattr(w_mod, w('__path__')) + except OperationError, e: if not e.match(space, space.w_AttributeError): raise w_path = None if w_fromlist is not None and space.is_true(w_fromlist): + if w_path is not None: + for w_name in space.unpackiterable(w_fromlist): + load_part(w_path, prefix, space.unwrap(w_name)) return w_mod else: return first -def load_part(w_path,prefix,partname): +def load_part(w_path, prefix, partname): w = space.wrap w_modulename = w('.'.join(prefix+[partname])) w_mod = check_sys_modules(w_modulename) if w_mod is not None: return w_mod - 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/test/test_import.py ============================================================================== --- pypy/trunk/src/pypy/module/test/test_import.py (original) +++ pypy/trunk/src/pypy/module/test/test_import.py Mon May 31 17:22:36 2004 @@ -13,7 +13,7 @@ import sys sys.path.append('impsubdir') import a - self.assert_('a' in sys.modules) + self.assertEquals(a, sys.modules.get('a')) def test_import_bare_dir_fails(self): def imp(): @@ -24,28 +24,28 @@ import sys sys.path.append('impsubdir') import pkg - self.assert_('pkg' in sys.modules) + self.assertEquals(pkg, sys.modules.get('pkg')) def test_import_dotted(self): import sys sys.path.append('impsubdir') import pkg.a - self.assert_('pkg' in sys.modules) - self.assert_('pkg.a' in sys.modules) + self.assertEquals(pkg, sys.modules.get('pkg')) + self.assertEquals(pkg.a, sys.modules.get('pkg.a')) def test_import_dotted2(self): import sys sys.path.append('impsubdir') import pkg.pkg1.a - self.assert_('pkg' in sys.modules) - self.assert_('pkg.pkg1' in sys.modules) - self.assert_('pkg.pkg1.a' in sys.modules) + self.assertEquals(pkg, sys.modules.get('pkg')) + self.assertEquals(pkg.pkg1, sys.modules.get('pkg.pkg1')) + self.assertEquals(pkg.pkg1.a, sys.modules.get('pkg.pkg1.a')) def test_import_ambig(self): import sys sys.path.append('impsubdir') import ambig - self.assert_('ambig' in sys.modules) + self.assertEquals(ambig, sys.modules.get('ambig')) self.assert_(hasattr(ambig,'imapackage')) def test_from_a(self): @@ -69,7 +69,10 @@ from pkg import a self.assert_('pkg' in sys.modules) self.assert_('pkg.a' in sys.modules) - self.assert_(hasattr(a, 'imamodule')) + pkg = sys.modules.get('pkg') + self.assertEquals(a, pkg.a) + aa = sys.modules.get('pkg.a') + self.assertEquals(a, aa) if __name__ == '__main__': testit.main() From alex at codespeak.net Mon May 31 17:30:58 2004 From: alex at codespeak.net (alex at codespeak.net) Date: Mon, 31 May 2004 17:30:58 +0200 (MEST) Subject: [pypy-svn] r4767 - pypy/trunk/src/pypy/module Message-ID: <20040531153058.7FC7A5BE4C@thoth.codespeak.net> Author: alex Date: Mon May 31 17:30:57 2004 New Revision: 4767 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py Log: ensured imports from packages update the package object's attributes 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 Mon May 31 17:30:57 2004 @@ -32,7 +32,7 @@ return _actframe(position).getdictscope() -def try_import_mod(w_modulename, f, pkgdir=None): +def try_import_mod(w_modulename, f, w_parent, w_name, pkgdir=None): w = space.wrap if os.path.exists(f): w_mod = space.wrap(Module(space, w_modulename)) @@ -42,6 +42,8 @@ space.setattr(w_mod, w('__path__'), space.newlist([w(pkgdir)])) w_dict = space.getattr(w_mod, w('__dict__')) execfile(w(f), w_dict, w_dict) + if w_parent is not None: + space.setattr(w_parent, w_name, w_mod) return w_mod else: return None @@ -71,7 +73,7 @@ w_mod = check_sys_modules(w_modulename) if w_mod is not None: return w_mod - + w_mod = space.get_builtin_module(modulename) if w_mod is not None: return w_mod @@ -83,9 +85,9 @@ w_path = space.sys.w_path first = None - + for part in parts: - w_mod = load_part(w_path, prefix, part) + w_mod = load_part(w_path, prefix, part, w_mod) if w_mod is None: # ImportError w_failing = w('.'.join(prefix+[part])) @@ -104,12 +106,12 @@ if w_fromlist is not None and space.is_true(w_fromlist): if w_path is not None: for w_name in space.unpackiterable(w_fromlist): - load_part(w_path, prefix, space.unwrap(w_name)) + load_part(w_path, prefix, space.unwrap(w_name), w_mod) return w_mod else: - return first + return first -def load_part(w_path, prefix, partname): +def load_part(w_path, prefix, partname, w_parent): w = space.wrap w_modulename = w('.'.join(prefix+[partname])) w_mod = check_sys_modules(w_modulename) @@ -119,11 +121,12 @@ dir = os.path.join(space.unwrap(path), partname) if os.path.isdir(dir): f = os.path.join(dir,'__init__.py') - w_mod = try_import_mod(w_modulename, f, pkgdir=dir) + w_mod = try_import_mod(w_modulename, f, w_parent, w(partname), + pkgdir=dir) if w_mod is not None: return w_mod f = os.path.join(space.unwrap(path), partname + '.py') - w_mod = try_import_mod(w_modulename, f) + w_mod = try_import_mod(w_modulename, f, w_parent, w(partname)) if w_mod is not None: return w_mod @@ -140,7 +143,7 @@ #print (str_, filename, startstr, supplied_flags, dont_inherit) # XXX we additionally allow GENERATORS because compiling some builtins - # requires it. doesn't feel quite right to do that here. + # requires it. doesn't feel quite right to do that here. try: c = cpy_builtin.compile(str_, filename, startstr, supplied_flags|4096, dont_inherit) # It would be nice to propagate all exceptions to app level, @@ -198,7 +201,7 @@ return space.hash(w_object) def oct(w_val): - # XXX does this need to be a space operation? + # XXX does this need to be a space operation? return space.oct(w_val) def hex(w_val): From anna at codespeak.net Mon May 31 17:45:26 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 17:45:26 +0200 (MEST) Subject: [pypy-svn] r4768 - pypy/trunk/doc Message-ID: <20040531154526.A8E3D5BE4E@thoth.codespeak.net> Author: anna Date: Mon May 31 17:45:26 2004 New Revision: 4768 Modified: pypy/trunk/doc/index.txt Log: pypy documentation page, first draft Modified: pypy/trunk/doc/index.txt ============================================================================== --- pypy/trunk/doc/index.txt (original) +++ pypy/trunk/doc/index.txt Mon May 31 17:45:26 2004 @@ -1,4 +1,41 @@ Pypy Documentation Tree ======================= -No contents available yet. \ No newline at end of file +We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the doc/ directory or under the src/devel directory. + +If you just want an overview of the project, take a look at our presentation to OSCON: + + * doc/oscon2003-paper:: + presentation to OSCON on what pypy is about and why you should care + +If you are wanting to get involved, take a look at the following documentation to get a better taste: + + * doc/howtopypy:: + provides some hands-on instructions for getting started + + * doc/readme:: + this file is on using ReST for pypy documentation + + * doc/architecture:: + an overview of the current architecture + + * doc/wrapping:: + a description of application-level and interpreter-level wrapped objects + +Before doing pypy work, you should also take a look at these developer-specific instructions: + + * devel/coding-style:: + covers pypy coding conventions + + * devel/howtosvn:: + for new users of subversion + + * checking_ReST:: + if you are adding documentation, look at both the doc/readme mentioned above and this file: + + * optionaltool:: + there are some optional tools we use for pypy. + + * testdesign:: + pypy is a test-driven development project.read here to find out more about how we're doing testing. + \ No newline at end of file From ale at codespeak.net Mon May 31 17:51:46 2004 From: ale at codespeak.net (ale at codespeak.net) Date: Mon, 31 May 2004 17:51:46 +0200 (MEST) Subject: [pypy-svn] r4769 - pypy/trunk/src/pypy/translator Message-ID: <20040531155146.A07685BE75@thoth.codespeak.net> Author: ale Date: Mon May 31 17:51:46 2004 New Revision: 4769 Modified: pypy/trunk/src/pypy/translator/genpyrex.py Log: Methods maybe works Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Mon May 31 17:51:46 2004 @@ -6,6 +6,7 @@ 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 class Op: def __init__(self, operation, gen, block): @@ -330,11 +331,12 @@ self.gen_block(block) - def globaldeclarations(self): + def globaldeclarations(self,): """Generate the global class declaration for a group of functions.""" if self.annotator: self.lines = [] self.indent = 0 + delay_methods={} for cls in self.annotator.getuserclassdefinitions(): if cls.basedef: bdef="(%s)" % (self.get_classname(cls.basedef.cls)) @@ -344,12 +346,21 @@ self.indent += 1 empty = True for attr,s_value in cls.attrs.items(): - vartype=self._gettypename(s_value.knowntype) - self.putline("cdef public %s %s" % (vartype, attr)) + if isinstance(s_value,SomeMethod): + for py_fun,fun_class in s_value.meths.items(): + delay_methods.setdefault(fun_class,[]).append(py_fun) + else: + vartype=self._gettypename(s_value.knowntype) + self.putline("cdef public %s %s" % (vartype, attr)) empty = False - else: - if empty: - self.putline("pass") + list_methods=delay_methods.get(cls,[]) + for py_fun in list_methods: + self.putline("def %s(*args):" % (self._str(py_fun,'XXX'))) + self.indent += 1 + self.putline("return %s(*args)" %(self._str(py_fun,'XXX'))) + self.indent -= 1 + if empty: + self.putline("pass") self.indent -= 1 self.putline("") return '\n'.join(self.lines) From arigo at codespeak.net Mon May 31 18:03:00 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 18:03:00 +0200 (MEST) Subject: [pypy-svn] r4770 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20040531160300.B09845BE75@thoth.codespeak.net> Author: arigo Date: Mon May 31 18:03:00 2004 New Revision: 4770 Modified: pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_translator.py Log: Generate simple methods. This hack has name clashes problem. Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Mon May 31 18:03:00 2004 @@ -191,6 +191,8 @@ self.lines = currentlines inputargnames = [ " ".join(self._paramvardecl(var)) for var in fun.getargs() ] params = ", ".join(inputargnames) + #returntype = self.get_type(fun.getreturnvar()) + #returntypename = self._gettypename(returntype) self.putline("def %s(%s):" % (fun.name, params)) self.indent += 1 #self.putline("# %r" % self.annotations) @@ -355,9 +357,9 @@ empty = False list_methods=delay_methods.get(cls,[]) for py_fun in list_methods: - self.putline("def %s(*args):" % (self._str(py_fun,'XXX'))) + self.putline("def %s(self, *args):" % py_fun.__name__) self.indent += 1 - self.putline("return %s(*args)" %(self._str(py_fun,'XXX'))) + self.putline("return %s(self, *args)" % py_fun.__name__) self.indent -= 1 if empty: self.putline("pass") 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 May 31 18:03:00 2004 @@ -361,3 +361,12 @@ while n: l[7] = 5 return v + +class Z: + def my_method(self): + return self.my_attribute + +def simple_method(v): + z = Z() + z.my_attribute = v + return z.my_method() Modified: pypy/trunk/src/pypy/translator/test/test_translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/test/test_translator.py (original) +++ pypy/trunk/src/pypy/translator/test/test_translator.py Mon May 31 18:03:00 2004 @@ -19,5 +19,11 @@ inheritance2 = t.compile() self.assertEquals(inheritance2(), ((-12, -12), (3, "world"))) + def test_simple_method(self): + t = Translator(snippet.simple_method) + t.annotate([int]).simplify() + simple_method = t.compile() + self.assertEquals(simple_method(55), 55) + if __name__ == '__main__': testit.main() From pedronis at codespeak.net Mon May 31 18:09:35 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 18:09:35 +0200 (MEST) Subject: [pypy-svn] r4771 - in pypy/trunk/src/pypy/module: . test test/impsubdir test/impsubdir/pkg Message-ID: <20040531160935.24BF35BE76@thoth.codespeak.net> Author: pedronis Date: Mon May 31 18:09:33 2004 New Revision: 4771 Modified: pypy/trunk/src/pypy/module/__builtin__interp.py pypy/trunk/src/pypy/module/test/impsubdir/a.py pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py pypy/trunk/src/pypy/module/test/test_import.py Log: factored out try_geattr test for relative import 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 Mon May 31 18:09:33 2004 @@ -48,6 +48,14 @@ else: return None +def try_getattr(w_obj,w_name): + try: + return space.getattr(w_obj, w_name) + except OperationError, e: + if not e.match(space, space.w_AttributeError): + raise + return None + def check_sys_modules(w_modulename): try: w_mod = space.getitem(space.sys.w_modules, w_modulename) @@ -96,12 +104,8 @@ if first is None: first = w_mod prefix.append(part) - try: - w_path = space.getattr(w_mod, w('__path__')) - except OperationError, e: - if not e.match(space, space.w_AttributeError): - raise - w_path = None + w_path = try_getattr(w_mod,w('__path__')) + if w_fromlist is not None and space.is_true(w_fromlist): if w_path is not None: Modified: pypy/trunk/src/pypy/module/test/impsubdir/a.py ============================================================================== --- pypy/trunk/src/pypy/module/test/impsubdir/a.py (original) +++ pypy/trunk/src/pypy/module/test/impsubdir/a.py Mon May 31 18:09:33 2004 @@ -1,2 +1,3 @@ # a.py imamodule = 1 +inpackage = 0 Modified: pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py ============================================================================== --- pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py (original) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/a.py Mon May 31 18:09:33 2004 @@ -1,2 +1,3 @@ # a.py imamodule = 1 +inpackage = 1 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 Mon May 31 18:09:33 2004 @@ -74,5 +74,11 @@ aa = sys.modules.get('pkg.a') self.assertEquals(a, aa) + def test_import_relative(self): + import sys + sys.path.append('impsubdir') + from pkg import relative_a + self.assertEquals(relative_a.a.inpackage,1) + if __name__ == '__main__': testit.main() From pedronis at codespeak.net Mon May 31 18:10:12 2004 From: pedronis at codespeak.net (pedronis at codespeak.net) Date: Mon, 31 May 2004 18:10:12 +0200 (MEST) Subject: [pypy-svn] r4772 - pypy/trunk/src/pypy/module/test/impsubdir/pkg Message-ID: <20040531161012.52C9C5BE77@thoth.codespeak.net> Author: pedronis Date: Mon May 31 18:10:11 2004 New Revision: 4772 Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/relative_a.py Log: missing relative_a.py Added: pypy/trunk/src/pypy/module/test/impsubdir/pkg/relative_a.py ============================================================================== --- (empty file) +++ pypy/trunk/src/pypy/module/test/impsubdir/pkg/relative_a.py Mon May 31 18:10:11 2004 @@ -0,0 +1 @@ +import a From anna at codespeak.net Mon May 31 18:33:10 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 18:33:10 +0200 (MEST) Subject: [pypy-svn] r4774 - pypy/trunk/doc Message-ID: <20040531163310.DFE6E5BE0B@thoth.codespeak.net> Author: anna Date: Mon May 31 18:33:10 2004 New Revision: 4774 Modified: pypy/trunk/doc/index.txt Log: index for documentation page with hyperlinks Modified: pypy/trunk/doc/index.txt ============================================================================== --- pypy/trunk/doc/index.txt (original) +++ pypy/trunk/doc/index.txt Mon May 31 18:33:10 2004 @@ -1,41 +1,60 @@ -Pypy Documentation Tree -======================= +Pypy Documentation +================== We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the doc/ directory or under the src/devel directory. -If you just want an overview of the project, take a look at our presentation to OSCON: - - * doc/oscon2003-paper:: +Overview +-------- + +If you just want an overview of the project, take a look at these items in doc/. + + * architecture_: + a more technical overview of the current architecture + + * oscon2003-paper_: presentation to OSCON on what pypy is about and why you should care -If you are wanting to get involved, take a look at the following documentation to get a better taste: +Getting Started +--------------- + +If you are wanting to get involved, take a look at the following documentation (also found in doc/) to get a better taste: - * doc/howtopypy:: + * howtopypy_: provides some hands-on instructions for getting started + - * doc/readme:: + * readme_: this file is on using ReST for pypy documentation - * doc/architecture:: - an overview of the current architecture - * doc/wrapping:: - a description of application-level and interpreter-level wrapped objects + * wrapping_: + a description of application-level and interpreter-level wrapped objects -Before doing pypy work, you should also take a look at these developer-specific instructions: +Before you code +--------------- - * devel/coding-style:: - covers pypy coding conventions +Before doing pypy work, you should also take a look at these developer-specific instructions, found in the src/devel/ directory of the repository: - * devel/howtosvn:: - for new users of subversion + * coding-style_: + covers pypy coding conventions - * checking_ReST:: - if you are adding documentation, look at both the doc/readme mentioned above and this file: + * howtosvn_: + for new users of subversion - * optionaltool:: + * optionaltool_: there are some optional tools we use for pypy. - * testdesign:: + * testdesign_: pypy is a test-driven development project.read here to find out more about how we're doing testing. - \ No newline at end of file + + + +.. _architecture: http://codespeak.net/pypy/index.cgi?doc/architecture.html +.. _oscon2003-paper: http://codespeak.net/pypy/index.cgi?doc/oscon2003-paper.html +.. _howtopypy: http://codespeak.net/pypy/index.cgi?doc/howtopypy.html +.. _readme: http://codespeak.net/pypy/index.cgi?doc/readme.html +.. _wrapping: http://codespeak.net/pypy/index.cgi?doc/wrapping.html +.. _coding-style: http://codespeak.net/pypy/index.cgi?doc/devel/coding-style.html +.. _howtosvn: http://codespeak.net/pypy/index.cgi?doc/devel/howtosvn.html +.. _optionaltool: http://codespeak.net/pypy/index.cgi?doc/devel/optionaltool.html +.. _testdesign: http://codespeak.net/pypy/index.cgi?doc/devel/testdesign.html \ No newline at end of file From hpk at codespeak.net Mon May 31 18:40:01 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 31 May 2004 18:40:01 +0200 (MEST) Subject: [pypy-svn] r4776 - in pypy/trunk/src: . pypy/tool pypy/translator/tool Message-ID: <20040531164001.EE3375BE10@thoth.codespeak.net> Author: hpk Date: Mon May 31 18:40:00 2004 New Revision: 4776 Modified: pypy/trunk/src/ (props changed) pypy/trunk/src/pypy/tool/newtest.py pypy/trunk/src/pypy/tool/testit.py pypy/trunk/src/pypy/tool/udir.py pypy/trunk/src/pypy/translator/tool/buildcl.py pypy/trunk/src/pypy/translator/tool/buildpyxmodule.py pypy/trunk/src/pypy/translator/tool/make_dot.py Log: scrap vpath, used 'std' Modified: pypy/trunk/src/pypy/tool/newtest.py ============================================================================== --- pypy/trunk/src/pypy/tool/newtest.py (original) +++ pypy/trunk/src/pypy/tool/newtest.py Mon May 31 18:40:00 2004 @@ -71,7 +71,7 @@ import sys import traceback import types -import vpath +from std import path #TODO # - add support for ignored tests (do we need to differentiate between @@ -529,12 +529,12 @@ by scanning the start directory recursively. """ items = [] - dirname = vpath.getlocal(dirname) + dirname = path.local(dirname) def testfilefilter(path): - return path.isfile() and path.fnmatch('test_*.py') + return path.check(file=1, fnmatch='test_*.py') def recfilter(path): - return recursive and vpath.nodotfile(path) + return recursive and path.check(dotfile=0) for testfn in dirname.visit(testfilefilter, recfilter): # strip the leading pypy directory and the .py suffix Modified: pypy/trunk/src/pypy/tool/testit.py ============================================================================== --- pypy/trunk/src/pypy/tool/testit.py (original) +++ pypy/trunk/src/pypy/tool/testit.py Mon May 31 18:40:00 2004 @@ -242,8 +242,8 @@ Additionally, their fully qualified python module path has to be accepted by filterfunc (if it is not None). """ - from vpath import getlocal, nodotfile - root = getlocal(root) + from std import path + root = path.local(root) if Options.verbose > 2: print >> sys.stderr, "scanning for test files in", root @@ -251,10 +251,10 @@ if loader is None: loader = unittest.TestLoader() - def testfilefilter(path): - return path.isfile() and path.fnmatch('test_*.py') - def recfilter(path): - return recursive and nodotfile(path) + def testfilefilter(p): + return p.check(file=1, fnmatch='test_*.py') + def recfilter(p): + return recursive and p.check(dotfile=0) suite = unittest.TestLoader.suiteClass() Modified: pypy/trunk/src/pypy/tool/udir.py ============================================================================== --- pypy/trunk/src/pypy/tool/udir.py (original) +++ pypy/trunk/src/pypy/tool/udir.py Mon May 31 18:40:00 2004 @@ -1,6 +1,6 @@ import autopath -from vpath.local import make_numbered_dir +from std.path import local -udir = make_numbered_dir(base='usession-', keep=3) +udir = local.make_numbered_dir(base='usession-', keep=3) Modified: pypy/trunk/src/pypy/translator/tool/buildcl.py ============================================================================== --- pypy/trunk/src/pypy/translator/tool/buildcl.py (original) +++ pypy/trunk/src/pypy/translator/tool/buildcl.py Mon May 31 18:40:00 2004 @@ -2,7 +2,7 @@ from pypy.objspace.flow import FlowObjSpace from pypy.translator.gencl import GenCL -from vpath.adapter.process import exec_cmd +from std.process import cmdexec class Literal: def __init__(self, val): @@ -56,7 +56,7 @@ print >>fp, writelisp(gen, arg), print >>fp, "))" fp.close() - output = exec_cmd("%s %s" % (cl, str(fpath))) + output = cmdexec("%s %s" % (cl, str(fpath))) return readlisp(output) return _ 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 May 31 18:40:00 2004 @@ -2,8 +2,8 @@ from pypy.tool import testit from pypy.tool.udir import udir -from vpath.adapter.process import exec_cmd -from vpath.local import Path +from std.process import cmdexec +from std import path from pypy.translator.genpyrex import GenPyrex import os, sys, inspect @@ -12,11 +12,11 @@ debug = 0 def make_module_from_pyxstring(name, dirpath, string): - dirpath = Path(dirpath) + dirpath = path.local(dirpath) pyxfile = dirpath.join('%s.pyx' % name) i = 0 - while pyxfile.exists(): - pyxfile = pyxfile.newbasename('%s%d.pyx' % (name, i)) + while pyxfile.check(): + pyxfile = pyxfile.new(basename='%s%d.pyx' % (name, i)) pyxfile.write(string) if debug: print "made pyxfile", pyxfile make_c_from_pyxfile(pyxfile) @@ -36,11 +36,11 @@ # print "ERROR IMPORTING" # pass - dirpath = pyxfile.dirname() - lastdir = Path() + dirpath = pyxfile.dirpath() + lastdir = path.local() os.chdir(str(dirpath)) try: - modname = pyxfile.purebasename() + modname = pyxfile.get('purebasename') if debug: print "modname", modname c = stdoutcapture.Capture(mixed_out_err = True) try: @@ -86,7 +86,7 @@ raise ValueError, "failure %s" % result except PyrexError, e: print >>sys.stderr, e - cfile = pyxfile.newext('.c') + cfile = pyxfile.new(ext='.c') def build_cfunc(func, simplify=1, dot=1, inputargtypes=None): """ return a pyrex-generated cfunction from the given func. @@ -109,7 +109,7 @@ if not inputargtypes: source = inspect.getsource(func) - base = udir.join(name).newext('.py').write(source) + base = udir.join(name).new(ext='.py').write(source) if dot: from pypy.translator.tool.make_dot import DotGen @@ -149,10 +149,10 @@ subgraphs.append(dotgen.getsubgraph(name, funcgraph)) content = dotgen.getgraph("graph_"+func.func_name, subgraphs) base = udir.join(name) - base.newext('dot').write(content) - base.newext('ps') - exec_cmd('dot -Tps -o %s %s' % ( - str(base.newext('ps')), - str(base.newext('.dot')))) + base.new(ext='dot').write(content) + base.new(ext='ps') + cmdexec('dot -Tps -o %s %s' % ( + str(base.new(ext='ps')), + str(base.new(ext='.dot')))) return getattr(mod, func.func_name) 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 Mon May 31 18:40:00 2004 @@ -7,6 +7,7 @@ from pypy.objspace.flow.model import * from pypy.objspace.flow import Space from pypy.tool.udir import udir +from std.process import cmdexec debug = 0 @@ -137,8 +138,6 @@ os.system('gv %s' % fn) def make_dot_graphs(basefilename, graphs, storedir=None, target='ps'): - from vpath.adapter.process import exec_cmd - if storedir is None: storedir = udir @@ -160,7 +159,7 @@ #print source dest.write(source) psdest = dest.newext(target) - out = exec_cmd('dot -T%s %s' % (target, str(dest))) + out = cmdexec('dot -T%s %s' % (target, str(dest))) psdest.write(out) #print "wrote", psdest return psdest From anna at codespeak.net Mon May 31 18:40:58 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 18:40:58 +0200 (MEST) Subject: [pypy-svn] r4777 - pypy/trunk/doc Message-ID: <20040531164058.02B5F5BE4E@thoth.codespeak.net> Author: anna Date: Mon May 31 18:40:58 2004 New Revision: 4777 Modified: pypy/trunk/doc/index.txt Log: updated documentation index page Modified: pypy/trunk/doc/index.txt ============================================================================== --- pypy/trunk/doc/index.txt (original) +++ pypy/trunk/doc/index.txt Mon May 31 18:40:58 2004 @@ -1,7 +1,7 @@ Pypy Documentation ================== -We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the doc/ directory or under the src/devel directory. +We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the doc/ directory or under the doc/devel sub-directory. Overview -------- @@ -17,8 +17,9 @@ Getting Started --------------- -If you are wanting to get involved, take a look at the following documentation (also found in doc/) to get a better taste: +If you are wanting to get involved, take a look at the following documentation to get a better taste: +These file are in the doc/ directory: * howtopypy_: provides some hands-on instructions for getting started @@ -30,16 +31,20 @@ * wrapping_: a description of application-level and interpreter-level wrapped objects +This file is in the devel/ sub-directory + + * howtosvn_: + for new users of subversion + Before you code --------------- -Before doing pypy work, you should also take a look at these developer-specific instructions, found in the src/devel/ directory of the repository: +Before doing pypy work, you should also take a look at these developer-specific instructions, found in the doc/devel/ sub-directory of the repository: * coding-style_: covers pypy coding conventions - * howtosvn_: - for new users of subversion + * optionaltool_: there are some optional tools we use for pypy. From anna at codespeak.net Mon May 31 18:42:53 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 18:42:53 +0200 (MEST) Subject: [pypy-svn] r4778 - pypy/trunk/doc Message-ID: <20040531164253.29E025BE77@thoth.codespeak.net> Author: anna Date: Mon May 31 18:42:52 2004 New Revision: 4778 Modified: pypy/trunk/doc/index.txt Log: updated documentation index page to fix a minor formatting problem Modified: pypy/trunk/doc/index.txt ============================================================================== --- pypy/trunk/doc/index.txt (original) +++ pypy/trunk/doc/index.txt Mon May 31 18:42:52 2004 @@ -31,8 +31,7 @@ * wrapping_: a description of application-level and interpreter-level wrapped objects -This file is in the devel/ sub-directory - +This file is in the devel/ sub-directory: * howtosvn_: for new users of subversion From arigo at codespeak.net Mon May 31 18:47:46 2004 From: arigo at codespeak.net (arigo at codespeak.net) Date: Mon, 31 May 2004 18:47:46 +0200 (MEST) Subject: [pypy-svn] r4779 - in pypy/trunk/src/pypy/translator: . test Message-ID: <20040531164746.19DAD5BE78@thoth.codespeak.net> Author: arigo Date: Mon May 31 18:47:45 2004 New Revision: 4779 Modified: pypy/trunk/src/pypy/translator/genpyrex.py pypy/trunk/src/pypy/translator/test/snippet.py pypy/trunk/src/pypy/translator/test/test_annrpython.py pypy/trunk/src/pypy/translator/translator.py Log: Small progress but HUGE hacks. Let's think about refactoring. Modified: pypy/trunk/src/pypy/translator/genpyrex.py ============================================================================== --- pypy/trunk/src/pypy/translator/genpyrex.py (original) +++ pypy/trunk/src/pypy/translator/genpyrex.py Mon May 31 18:47:45 2004 @@ -191,9 +191,20 @@ self.lines = currentlines inputargnames = [ " ".join(self._paramvardecl(var)) for var in fun.getargs() ] params = ", ".join(inputargnames) - #returntype = self.get_type(fun.getreturnvar()) - #returntypename = self._gettypename(returntype) - self.putline("def %s(%s):" % (fun.name, params)) + returntype = self.get_type(fun.getreturnvar()) + returntypename = self._gettypename(returntype) + try: + function_object = self.by_the_way_the_function_was # XXX! + except AttributeError: + def function_object(): pass # XXX!!! + # make the function visible from the outside under its original name + hackedargs = ', '.join([var.name for var in fun.getargs()]) + self.putline("def %s(%s):" % (fun.name, hackedargs)) + self.indent += 1 + self.putline("return %s(%s)" % (self._hackname(function_object), hackedargs)) + self.indent -= 1 + # go ahead with the mandled header and body of the function + self.putline("def %s(%s):" % (self._hackname(function_object), params)) self.indent += 1 #self.putline("# %r" % self.annotations) decllines = [] @@ -249,7 +260,7 @@ return ctype def get_classname(self, userclass): - return userclass.__name__ + return self._hackname(userclass) def _vardecl(self, var): vartype, varname = self._paramvardecl(var) @@ -258,22 +269,29 @@ else: return "" + def _hackname(self, value): + try: + name = value.__name__ + except AttributeError: + pass + else: + import types + if isinstance(value, (types.FunctionType, types.ClassType, type)): + # XXX! use the id of the value to make unique function and + # class names + return '%s__%x' % (name, id(value)) + elif isinstance(value, types.BuiltinFunctionType): + return str(name) + if isinstance(value, int): + value = int(value) # cast subclasses of int (i.e. bools) to ints + return repr(value) + def _str(self, obj, block): if isinstance(obj, Variable): #self.variablelocations[obj] = block return self.get_varname(obj) elif isinstance(obj, Constant): - value = obj.value - try: - name = value.__name__ - except AttributeError: - pass - else: - if callable(value): - return name # functions represented as their name only - if isinstance(value, int): - value = int(value) # cast subclasses of int (i.e. bools) to ints - return repr(value) + return self._hackname(obj.value) else: raise TypeError("Unknown class: %s" % obj.__class__) @@ -354,13 +372,18 @@ else: vartype=self._gettypename(s_value.knowntype) self.putline("cdef public %s %s" % (vartype, attr)) - empty = False + empty = False list_methods=delay_methods.get(cls,[]) for py_fun in list_methods: - self.putline("def %s(self, *args):" % py_fun.__name__) + # XXX! + fun = self.annotator.translator.flowgraphs[py_fun] + hackedargs = ', '.join([var.name for var in fun.getargs()]) + self.putline("def %s(%s):" % (py_fun.__name__, hackedargs)) self.indent += 1 - self.putline("return %s(self, *args)" % py_fun.__name__) + self.putline("return %s(%s)" % (self._hackname(py_fun), + hackedargs)) self.indent -= 1 + empty = False if empty: self.putline("pass") self.indent -= 1 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 May 31 18:47:45 2004 @@ -324,6 +324,13 @@ e.stuff = (3, "world") return getstuff(d), getstuff(e) +def inheritance_nonrunnable(): + d = D() + d.stuff = (-12, -12) + e = E() + e.stuff = (3, "world") + return C().stuff + class F: pass class G(F): 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 May 31 18:47:45 2004 @@ -165,7 +165,7 @@ def test_inheritance2(self): a = RPythonAnnotator() - s = a.build_types(snippet.inheritance2, []) + s = a.build_types(snippet.inheritance_nonrunnable, []) # result should be exactly: self.assertEquals(s, annmodel.SomeTuple([ annmodel.SomeInteger(), Modified: pypy/trunk/src/pypy/translator/translator.py ============================================================================== --- pypy/trunk/src/pypy/translator/translator.py (original) +++ pypy/trunk/src/pypy/translator/translator.py Mon May 31 18:47:45 2004 @@ -164,6 +164,7 @@ def generatecode1(self, gencls, input_arg_types, func, ann): graph = self.getflowgraph(func) g = gencls(graph) + g.by_the_way_the_function_was = func # XXX if input_arg_types is not None: ann.build_types(graph, input_arg_types) if ann is not None: From anna at codespeak.net Mon May 31 18:49:27 2004 From: anna at codespeak.net (anna at codespeak.net) Date: Mon, 31 May 2004 18:49:27 +0200 (MEST) Subject: [pypy-svn] r4780 - pypy/trunk/doc Message-ID: <20040531164927.856205BE7F@thoth.codespeak.net> Author: anna Date: Mon May 31 18:49:26 2004 New Revision: 4780 Modified: pypy/trunk/doc/index.txt Log: updated documentation index page. more formatting stuff. Modified: pypy/trunk/doc/index.txt ============================================================================== --- pypy/trunk/doc/index.txt (original) +++ pypy/trunk/doc/index.txt Mon May 31 18:49:26 2004 @@ -1,12 +1,12 @@ Pypy Documentation ================== -We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the doc/ directory or under the doc/devel sub-directory. +We have a fair amount of documentation for the Pypy project. The files are available from the website as html (view them along the left side of the pypy doc web-page). They are also available from the repository, under the *doc/* directory or under the *doc/devel* sub-directory. Overview -------- -If you just want an overview of the project, take a look at these items in doc/. +If you just want an overview of the project, take a look at these items in *doc/*. * architecture_: a more technical overview of the current architecture @@ -17,9 +17,10 @@ Getting Started --------------- -If you are wanting to get involved, take a look at the following documentation to get a better taste: +If you want to get involved, take a look at the following documentation to get a better taste: + +These file are in the *doc/* directory: -These file are in the doc/ directory: * howtopypy_: provides some hands-on instructions for getting started @@ -31,14 +32,15 @@ * wrapping_: a description of application-level and interpreter-level wrapped objects -This file is in the devel/ sub-directory: +This file is in the *doc/devel/* sub-directory: + * howtosvn_: for new users of subversion Before you code --------------- -Before doing pypy work, you should also take a look at these developer-specific instructions, found in the doc/devel/ sub-directory of the repository: +Before doing pypy work, you should also take a look at these developer-specific instructions, found in the *doc/devel/* sub-directory of the repository: * coding-style_: covers pypy coding conventions From hpk at codespeak.net Mon May 31 19:04:57 2004 From: hpk at codespeak.net (hpk at codespeak.net) Date: Mon, 31 May 2004 19:04:57 +0200 (MEST) Subject: [pypy-svn] r4782 - pypy/trunk/src/pypy/module/test Message-ID: <20040531170457.6E3C45BE0A@thoth.codespeak.net> Author: hpk Date: Mon May 31 19:04:44 2004 New Revision: 4782 Modified: pypy/trunk/src/pypy/module/test/test_import.py Log: use os.chdir and back to import from 'impsubdir' 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 Mon May 31 19:04:44 2004 @@ -1,41 +1,47 @@ import autopath from pypy.tool import testit +import os -class TestImport(testit.AppTestCase): +class TestImport(testit.AppTestCase): + def setUp(self): # interpreter-level + self.space = testit.new_objspace() + def test_import_bare_dir_fails(self): + def imp(): + import impsubdir + self.assertRaises(ImportError,imp) + +class TestImportChdiredToimpsubdir(testit.AppTestCase): def setUp(self): # interpreter-level self.space = testit.new_objspace() + dn = os.path.abspath(os.path.join(os.path.dirname(__file__), 'impsubdir')) + self.olddir = os.getcwd() + os.chdir(dn) + + def tearDown(self): # interpreter-level + os.chdir(self.olddir) def test_import_sys(self): import sys def test_import_a(self): import sys - sys.path.append('impsubdir') import a self.assertEquals(a, sys.modules.get('a')) - def test_import_bare_dir_fails(self): - def imp(): - import impsubdir - self.assertRaises(ImportError,imp) - def test_import_pkg(self): import sys - sys.path.append('impsubdir') import pkg self.assertEquals(pkg, sys.modules.get('pkg')) def test_import_dotted(self): import sys - sys.path.append('impsubdir') import pkg.a self.assertEquals(pkg, sys.modules.get('pkg')) self.assertEquals(pkg.a, sys.modules.get('pkg.a')) def test_import_dotted2(self): import sys - sys.path.append('impsubdir') import pkg.pkg1.a self.assertEquals(pkg, sys.modules.get('pkg')) self.assertEquals(pkg.pkg1, sys.modules.get('pkg.pkg1')) @@ -43,21 +49,18 @@ def test_import_ambig(self): import sys - sys.path.append('impsubdir') import ambig self.assertEquals(ambig, sys.modules.get('ambig')) self.assert_(hasattr(ambig,'imapackage')) def test_from_a(self): import sys - sys.path.append('impsubdir') from a import imamodule self.assert_('a' in sys.modules) self.assertEquals(imamodule, 1) def test_from_dotted(self): import sys - sys.path.append('impsubdir') from pkg.a import imamodule self.assert_('pkg' in sys.modules) self.assert_('pkg.a' in sys.modules) @@ -65,7 +68,6 @@ def test_from_pkg_import_module(self): import sys - sys.path.append('impsubdir') from pkg import a self.assert_('pkg' in sys.modules) self.assert_('pkg.a' in sys.modules) @@ -75,8 +77,6 @@ self.assertEquals(a, aa) def test_import_relative(self): - import sys - sys.path.append('impsubdir') from pkg import relative_a self.assertEquals(relative_a.a.inpackage,1)